Jump to content

Peter Falkenberg Brown

Members
  • Posts

    347
  • Joined

  • Last visited

  • Days Won

    4

Posts posted by Peter Falkenberg Brown

  1. Dear Ryan and All,

    As I mentioned in a Wish-list post:

    http://processwire.com/talk/topic/5235-simple-clear-notes-and-method-to-use-admin-type-field-inputs-on-frontend-via-api/?p=50521

    I've gotten to the point where I'm getting front end images to use the Fancybox popup *if* the <a hrefs> that link to the images have the "class='InputfieldFileLink'" code included.

    However, rather than edit those links by hand, via the HTML icon in TinyMCE, which is a major pain, can you recommend a place in the PW core where that code could be inserted into the hrefs when a person adds an image in the body text, with the checkbox ticked off for linking to a larger image?

    Or maybe it would work via a hook?

    This is beyond my expertise at the moment, but it would be really great to implement this for our online magazine, so that every linked image ends up using Fancybox by default.

    Hoping for a genius solution.... :-)

    Peter

  2. Dear Matthew,

    Hey, those Biblical names are easy to mix up: Peter, David, Matthew, Lazarus... :-)

    Fancybox Lightboxes on Front end Images:

    To all, here's another example:

    I just parsed through an admin page, to determine what's needed on the front end to use the Fancybox lightboxes on an href to an image, and came up with this:

    <link type='text/css' href='/wire/modules/Jquery/JqueryFancybox/JqueryFancybox.css?v=126' rel='stylesheet' />
    
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryCore/JqueryCore.js?v=183'></script>
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryFancybox/JqueryFancybox.js?v=126'></script>
    <script type='text/javascript' src='/wire/modules/Inputfield/InputfieldImage/InputfieldImage.js?v=100'></script>
    
    <!--
    For the Fancybox to work, the hrefs that link to images need this class:
    <a class='InputfieldFileLink' href='xyz.jpg'>
    -->
    
    

    In the Significato Journal, we use a lot of images in the articles, and I'd like to start using popups to larger versions.

    PW has that very fine function, when you add an image to a page (in TinyMCE), to automatically scale a smaller image down, and it has a check box if you want to link to the larger image. I like that a lot.

    But... by default, it doesn't have a checkbox for target blank, and it doesn't have a dialogue box to use the Fancybox popup. (Unless I missed something.)

    So, on this article for example:

    http://significatojournal.com/help-the-world/freedom-human-rights/help-to-end-the-unbearable-evil-of-modern-slavery/

    I created a sidebar with images, linking to larger versions.

    Once I added the above Fancybox css and js files AND manually added the string

    class='InputfieldFileLink'
    

    to the first image in the sidebar, (via the HTML code button in the body text editor), the first image used the Fancybox popup!

    Zowie! I love it.

    (I haven't edited the other images yet.)

    Yes: I read the comments on another post about not using the default JQuery files, so I understand that risk. Maybe I'll copy them to my site dir.

    My questions now are:

    a) WISHLIST: it would be really great to add a dialogue box on the image insert, to use the Fancybox module, and

    b) does anyone have any clever code ideas to parse through the body text and edit the <a hrefs> that have images with the above class string?

    I don't want to add that class to every href in the body text. I suppose I could use a preg_match to grab every <a ...> and then check for a '.jpg', '.png', '.gif', and then add the class to that string.

    Just kicking ideas around.

    Thanks!

    Peter

    • Like 2
  3. Dear All,

    Tonight my wife and I were posting a long article in our new ProcessWire install of the Significato Journal.

    We logged in on her laptop, with a wireless connection, and started on an article.

    After adding all the field data, and then after working on a long body text paste and cleanup, we hit "Publish" and were brought to the Login page, much to our dismay, because after we logged in again, all the field data and body text was lost (although the images were still connected to the article).

    It happened once more during the 2 hour session, but that time I had hit Ctrl-A, Ctrl-C in the body text field, before I hit Save, so that I was able to paste the body text in again.

    My impression of the wire_challenge cookie is that it lasts as long as the browser is open (which defines a session). Is that correct?

    However, I think that the wire_challenge cookie gets deleted whenever there's a connection hiccup.

    I confirmed this in a new session on my laptop. I use an encrypted VPN called Private Internet Access. Using that, I logged into PW, and then disconnected from the VPN. My regular wireless connection was still active, but I had to re-login. When I looked at the cookies, the wire_challenge cookie was missing.

    Perhaps my wife's laptop (which did not have the VPN active at that time) experienced a connection glitch with the primary wireless connection.

    Or... could it be something else?

    Is there any way to stay logged in, even if the VPN connection, or main wireless connection, dies?

    That is, the *browser* is still open, so I would have thought that the browser would maintain the cookie.

    It's *very* disconcerting to lose the connection after a major edit, when one hits Save.

    I don't remember this happening in all the years I used MODX, but it's happened a number of times with ProcessWire.

    EDIT: I just confirmed that when I log into MODX Evo, and then disconnect my VPN, I stay logged into MODX, and can keep working.

    However, I re-confirmed that with PW, doing the same thing, I need to re-login after disconnecting my VPN.

    Thanks for any tips.

    Peter

  4. Dear Ryan,

    I think that the way you've created the interface to the more exotic field types in the Admin back end is really great.

    I'd like to be able to use any or all of those fields on the front end, via the API, more easily, based on a clear and simple set of notes and possible division of .js and .css files per field.

    For example, to get the calendar popup working in edit mode, in a front end app, I had to include these files in the <head> section of my pages:

    <link type='text/css' href='/site/templates-admin/styles/JqueryUI/JqueryUI.css' rel='stylesheet' />
    <link type='text/css' href='/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.css?v=103' rel='stylesheet' />
    
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryCore/JqueryCore.js?v=183'></script>
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryUI/JqueryUI.js?v=192'></script>
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js?v=103'></script>
    <script type='text/javascript' src='/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.js?v=103'></script>
    <script type='text/javascript' src='/wire/modules/Inputfield/InputfieldDatetime/jquery-ui-timepicker-addon.js'></script>
    

    To get the multi-column checkboxes working in edit mode, I had to include this <div> in my edit form:

    <ul class='Inputfields'>
    ... input field here ...
    </ul>

    and then I copied a variety of CSS classes from your core code into my main css file.

    I'd like to be able to use the image upload field with the progress bar, and many of the other specialized fields that you've created, that require special javascript or css to run properly.

    My suggestion is to create js and css files per field -- or field family, that can be easily included, without extra weight from other items, with notes on each field, e.g.

    - for xyz field, include these .js and .css files, and add this xyz html to your edit template (if necessary)

    This would allow developers to *easily* use the full power of the admin fields in front-end edits, which would be a truly glorious thing. :-)

    Thanks!

    Peter

    • Like 2
  5. Dear Craig, Teppo and PWired,

    Thanks for your kind words! I appreciate it very much.

    Teppo, I'll revisit the redirect. I agree, it's better to get the config value.

    And yes, I could have used Hanna, except that I had a lot of legacy tags and fields, like code_block1, etc.

    I just looked at the Hanna module again, and it looks great.

    Ain't it great that PW is so great! Zowie.

    Peter

  6. Case Study: SignificatoJournal.com:
    Migrating from MODX Evolution to ProcessWire

    Contents:

        * Useful MODX Fields

        * Custom Template Files

        * Template Chunks

        * Field Chunks

        * Snippets

        * The Writer Table

        * The Migration Script

        * URL Replacement

        * Image Migration

        * TinyMCE Code Breaks

        * Post Migration Data Checks

        * Link to Script Content


    I just finished migrating the magazine site that my wife and I run (http://significatojournal.com) from MODX Evolution to ProcessWire. How I did it may be of interest to other MODX users that wish to migrate their sites to ProcessWire.

    I liked MODX because it was so flexible. My experience with ProcessWire has been that PW is even more flexible than MODX, and it breaks the 5,000 page MODX Evo barrier that was the great bugaboo in Evo. I attempted to use MODX Revolution multiple times but was very unsatisfied with the slowness of the editorial interface. There were also other reasons that I left MODX for PW, that have been addressed by other writers.


    After using PW’s API to build a large web app in 2013 (which will be a different case study), and now, after having migrated my magazine site to PW, I’m absolutely thrilled with ProcessWire. I could go on and on... :-)

    There were many things that I liked about MODX Evo, that provided functionality that I wanted to continue to use in ProcessWire. They included:

    Chunks, snippets, and a combination of built in MODX fields and custom template var “fields” that I created for my former website, including:


    Useful MODX Fields

      MODX Fields:

    longtitle (headline)

    pub_date

    introtext (summary)

    template (id of custom template)

    menuindex

    menutitle

    hidemenu (show in menu)


    * In PW, I use the three menu fields to create the menu of the site, using Soma’s excellent module “MarkupSimpleNavigation”, with code like this: 'selector' => 'show_in_menu=1'

     

    post-1176-0-08205500-1388096261_thumb.jp

     

    * I use the publish_date field to block display of pages with future publish_dates, as well as to show the actual date of publication set by the editor (not just the date of the saved record).

     

    Custom Template Var Fields:

    subtitle

    writer_id

    static_author

    static_author_attribution

    newsletter_volume_number

    headline_thumbnail

      article_type

      sitemap_exclude

    code_blocks1-7


    Custom Template Files


    MODX Evo allows one to assign a custom template file to each article, which I found very useful. Unlike PW, MODX Evo uses a primary static data field set for each article, with custom fields added on as “template vars.”

    The advantage of the custom template files is that it allows one to use different display templates for different types of articles or section pages. I generally use a four level method of:


    - home page

    - multi-section page

    - section page

    - article page


    Given PW’s method of creating virtual data tables, aka template “field sets”, with display template files assigned to each template field set, I had to work out a method to have the same type of flexibility of assigning display template files to each page.


    For example, an article page might be a regular article page, with writer information, or an “article_plain” page, like a Contact Us page. A section page could be a multi-section page, with a list of sections, or a paginated section page that lists articles. I also had a need for custom section pages, to display articles based on “content_tags”.

    My solution was to create generic PW template data field sets, that all ran one php template file called “custom_template_controller.php.” The two main PW template field sets are:

    * article_page_structure_permanent

    * list_page_structure_permanent

    Using this method, when a new page is created, I select the PW data template first:

    post-1176-0-30325200-1388096160_thumb.jp


    and then, once I’m in the main set of fields, I select the custom template file for that page:
     

    post-1176-0-59590900-1388096256_thumb.jp
     

    The custom_template_controller.php is very simple, and simply pulls up the custom template file assigned to the page, and runs it:

    <?php
    ###################################################################################################
    # custom_template_controller.php
    ###################################################################################################
    
    include("./inc_vars.php");
    include("./inc_functions.php");
    
    #....................................................................
    # block future publish dates; don't block home page (id 1)
    
    if ( ( $page->id == '1'  ) || ( ! empty( $publish_date ) and $publish_date <= $now ) )
          {
          # page can be displayed
          }
    else
          {
          wire(session)->redirect("/http404", false);
          }
    
    #....................................................................
    
    include("./$custom_template_file");
    
    ###################################################################################################
    

    The "./inc_vars.php" file gets the value of the field:

    $custom_template_file = $page->custom_template_file->select_value;
    

    and also initiates a variety of variables and template “chunks”.

    Template Chunks

    MODX Evo allows one to define “chunks” of text that can be replaced in the templates or in data fields, using {{tags}} that are replaced at run time. In PW, I divided the chunks into sets of templates chunks, and a smaller set of field chunks.

    Because of the way PW uses PHP as its “templating” language (which I REALLY like), I decided to simply place the template “chunks” in a file called "./inc_vars.php", and define them as normal PHP variables. Since that file is loaded before every page, the variables are available to use in the custom template files.


    Field Chunks

    For field chunks, I created a PHP function that loops through a set of “chunk” data pages and looks for corresponding tags in the body field, and then replaces them. I placed the “field chunks” branch of data pages under a hidden master page called “elements”, which I also used for custom selects like the custom_template_files.

    post-1176-0-66125300-1388096254_thumb.jp


    The field chunks use the MODX delimiters of curly brackets {{chunk_name}} and the contents of the chunks are replaced. For example, “{{email.pfb}} is replaced with an image of the email address as the title of a clickable, Javascript encoded mailto: link.

    In MODX, the field chunk system also allowed one to replace tags in text fields of data coming from template vars (custom fields). I found that my primary need for that was with code that TinyMCE didn’t like, such as data entry forms or special Javascript, so I created seven “code_block” fields, e.g. “code_block1” … “code_block7”. Seven is a bit much, but at the time I created the fields in MODX, I was using many Amazon affiliate tags for books and CDs, in various articles.

    Snippets

    MODX Evo also has handy-dandy snippet tags that get replaced at run time. For my purposes, I only need to replace snippets in the code block fields, prior to replacing the code block tags in the body text.

    For example, I have a form that needs to display a dynamically generated captcha image that gets created by a Perl script. So, in the code_block1 field of the article, which contains the form, I place a snippet tag:

    [!s_form_get_captcha!]
    

    which then gets replaced by the same function that parses the chunk tags.

    I used the syntax [!...!] from MODX Evo mainly for convenience. Unlike MODX, the ! exclamation marks don’t affect caching of the snippet.

    To work with the snippet tags, I created an array in the chunk parsing function that attaches the snippet tag to the name of a PHP include file:

    $snippet_array = array(
                           '[!s_form_get_captcha!]' => '/home/sigj/s_form_get_captcha.php',
                          );
    

    In this case, the PHP file “s_form_get_captcha.php” contains a backtick call to a Perl script which returns the dynamically generated captcha image. But, the PHP file could contain any normal PHP code that has to be generated at run time. Here are the contents of the function that parses chunks and snippets:

    ###################################################################################################
    function parse_field_chunks($page_id)
    {
    
    $body = wire(pages)->get("$page_id")->body;
    
    $snippet_array = array(
                           '[!s_form_get_captcha!]' => '/home/sigj/s_form_get_captcha.php',
                          );
    
    #..............................................................................
    
    $field_chunk_id_array = wire(pages)->find("parent=1052, include=all");
    
    foreach( $field_chunk_id_array as $chunk_id )
          {
          $chunk_name  = '{{' . wire(pages)->get("id=$chunk_id")->name . '}}';
          $chunk_value = wire(pages)->get("id=$chunk_id")->chunk;
    
          $body = str_replace($chunk_name, $chunk_value, $body);
          }
    
    #..............................................................................
    # replace code_block tags with field values
    
    for ( $count=1; $count<=7; $count++ )
          {
          $code_block_field = 'code_block' . $count;
          $code_block_tag   = '{{' . $code_block_field . '}}';
    
          $code_block_value = wire(pages)->get("$page_id")->$code_block_field;
    
          # now parse code block value for snippet tags
          # [!snippet_name!]
          # [!s_form_get_captcha!]
    
          foreach ( $snippet_array as $snippet_tag => $snippet_include_file )
                {
                if ( strpos($code_block_value, $snippet_tag) !== false )
                      {
                      $snippet_value    = include("$snippet_include_file");
                      $code_block_value = str_replace($snippet_tag, $snippet_value, $code_block_value);
                      }
                }
    
          $body = str_replace($code_block_tag, $code_block_value, $body);
          }
    
    return($body);
    
    }
    ###################################################################################################
    

    The Writer Table

    I use the writer_id field as a popup, to pull in an id from a data table of long term writers. When an article page is displayed, code grabs the id and pulls in the writer info, including a photo, attribution and Javascript encoded email address. In MODX, I had to use a custom table. In PW, I simply created a template field set called ‘writer_page_structure_permanent.’

    post-1176-0-35642800-1388096260_thumb.jp
     

    I use a ‘static_author” and “static_author_attribution” field for those times when an author is a one-off writer. My code tests for a writer dropdown ID for ‘Non-Registered’ writer, and if the static fields have something, then that data is displayed.

    Template Structure

    Here are some screen shots of my PW template structure, which essentially replicated my previous MODX structure:

    Templates:

    post-1176-0-25450800-1388096259_thumb.jp

    List Page Structure Permanent:

    post-1176-0-49295300-1388096255_thumb.jp

    Article Page Structure Permanent:

    post-1176-0-35839500-1388096231_thumb.jp
     

    The Migration Script

     

    One of the challenges I faced with my script to migrate the data was the assignment of the correct parent of each article. Luckily, I wanted to keep the exact structure of the section and article tree and the urls.

     

    Since I didn’t have tens of thousands of articles, I decided to create an associate array of the sections and articles under the first level of the home page (i.e. starting at level 2), and then use that sorted list to create the ProcessWire parents before each lower level of section or article. I built the script dynamically, testing as I went, so I wouldn’t say that the script is fit for any and all MODX situations. It’s heavily tailored to my installation, and is missing a few elements that I missed until after I had finished with it (thus causing me to fix some things by hand).

    URL Replacement

     

    I had to parse through each article, in both the body, summary and subtitle, to make sure that any internally pointing MODX urls were replaced with the full url. MODX Evo uses the syntax [~ID~] in the “<a href...” tag to dynamically create the full page url at run time. I had to create a routine to replace the ID tags with page urls, e.g. “/columns/some_article_name”.

    Image Migration

     

    I first took the lazy way out and thought that I could simply move the “/assets/” folder from the MODX installation over to the new account. However, when I opened a PW page in edit mode, the links to the /assets/... images were there, but the images weren’t attached to the page, and thus, in edit mode, the image didn’t now show up in the edit box. I therefore added a routine to copy the images to each page.


    TinyMCE Code Breaks

     

    I found that TinyMCE kept trashing my various CSS codes that came over from MODX. I tried adding various tags to the body field’s “valid_elements” field under Input / TinyMCE, but finally just changed valid_elements to:


    +*[*]

     

    It’s a bit radical, I suppose, but my editors are fully trusted. After that, my migrated data was fine.


    Post Migration Data Checks

     

    After I migrated the data for the umpteenth time, in order to get it right, I still needed to do a variety of clean up tasks. I found the Selector Test module by Niklas Lakanen very useful (Thanks, Niklas!), and used it to run checks like:

    	body*=src\=\"{~root_url}assets
    

        (which looked for left over links to /assets/ which came from MODX)

     

    I also queried the MODX and PW tables directly, using SQLYog, a Windows MySQL client.

     

    I ran a script that compared the results of a find command (find . -type f -printf "%f\n") under the MODX assets folder to the files under the PW site/assets/files folder. I found about 70 files that were not copied, some because they were in template files, which my script didn’t parse, and some because the filenames were problematic, like files with spaces, etc. The script took into account the PW code that changes uploaded file names. To do that, I copied the PW “validate_filename” function into my script.


    For all my checking, I still forgot things, like parsing the subtitle or summary fields for hrefs, which I then had to go and do by hand (since there were very few records like that).

     

    I also created a few redirect aliases by hand, instead of trying to handle them via the script.

     

    All in all, this migration confirmed once again that website migrations are a Bear. Ugh. I’d rather not do them. :-)

    Link to Script Content


    Here’s the link to the script. Note that it didn’t catch everything, and it was heavily tailored to my design. Also note that I’ve removed some of the private data, like writer’s names, etc.

     

    sj_modx_pw_migrate_script.php

     

    That’s my case study. I hope it may be useful to another “MODX Refugee”. :-)

     

    Peter Falkenberg Brown

    • Like 12
  7. Dear All,

    Thanks for the likes, and thanks Diogo.

    SiNNuT, I agree about the background -- it stretches when the window is resized. I have to say that my CSS comfort zone is still rather small. I copied the code from somewhere on the web, for the scrolling ability with the background image.

    I tried the background cover option, but I'm not doing it right, and it didn't change anything. Here's my current css and html code:

    HTML:

    <body>
    
    <div>
    <img src="/site/assets/site_images/ireland_wallpaper.jpg" alt="background image" name="background" id="background" />
    </div>
    <div id="scroller"> <br />
    ... body content here ...
    </div>
    

    CSS:

    #scroller {
          position:absolute;
          width:100%;
          height:100%;
          top:0;
          left:0;
          overflow:auto;
          z-index:2;
    }
    

    So, based on this, my understanding is that everything inside the scroller div scrolls over the image.

    I tried adding the "background-size: cover;" attribute to the div wrapped around the image, to no effect.

    If you've got any tips on how to integrate that, I'd welcome them.

    Thanks!

    Peter

  8. Hello All,

    After spending most of my free time this year building a large web application with ProcessWire, I've finally found the time to migrate my magazine site from MODX Evolution to PW.

    http://significatojournal.com

    I'm very, very pleased with ProcessWire, and will no longer be using MODX.

    In a separate post, I'll write up a case study of how I did the migration.

    But for now, I really thank Ryan and all the extremely supportive gurus in this very fine PW community.

    Peter Brown

    • Like 8
  9. Dear Soma,

    Thanks for your help. I finally sorted it out by using all of the css and js files from the admin and other things, and then taking each one away until it was clear what was required (well, I did that for the calendar popup). So here's my report.

    =========================================================

    * Calendar popup via the API in the FrontEnd:

    =========================================================

    It needed these files in the header:

    <link type='text/css' href='/site/templates-admin/styles/JqueryUI/JqueryUI.css' rel='stylesheet' />
    <link type='text/css' href='/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.css?v=103' rel='stylesheet' />
    
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryCore/JqueryCore.js?v=183'></script>
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryUI/JqueryUI.js?v=192'></script>
    <script type='text/javascript' src='/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js?v=103'></script>
    <script type='text/javascript' src='/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.js?v=103'></script>
    <script type='text/javascript' src='/wire/modules/Inputfield/InputfieldDatetime/jquery-ui-timepicker-addon.js'></script>
    

    =========================================================

    * Multi-column checkboxes via the API in the FrontEnd:

    =========================================================

    I had to wrap my field in a ul tag, like this:

          <ul class='Inputfields'>
          :!:domains:!:
          </ul>
    

    Then, I copied a number of css elements from the wire dir that I probably should go through and isolate and determine

    which ones are really necessary for the checkboxes. But here's what I copied into my css file:

    /**********************************************************************************************
     * ProcessWire Admin Control Panel - Skyscraper Theme - inputfields.css
     *
     * This file provides common styling for ProcessWire inputfields. All other Inputfield styles
     * are provided by the Inputfield modules themselves.
     *
     * Copyright 2012 by Ryan Cramer
     *
     */
    
    .Inputfields fieldset,
    .Inputfields input,
    .Inputfields select,
    .Inputfields textarea,
    .Inputfields label {
    	/* reset */
    	margin: 0;
    	padding: 0;
    }
    
    .Inputfields,
    .Inputfields .Inputfield,
    .Inputfields label,
    .Inputfields input,
    .Inputfields select,
    .Inputfields textarea,
    .Inputfields table {
    	font-size: 12px;
    }
    
    .Inputfields input,
    .Inputfields select,
    .Inputfields textarea {
    	max-width: 100%;
    }
    
    .InputfieldForm .Inputfields,
    .InputfieldForm .Inputfields > .Inputfield {
    	list-style: none;
    	margin: 1em 0;
    	padding: 0;
    }
    	.InputfieldForm .Inputfields .Inputfields {
    		/* nested .Inputfields list needs no bottom margin since it'll already be offset from the parent's padding */
    		margin-bottom: 0;
    	}
    
    	.Inputfields > .Inputfield {
    		display: block;
    		clear: both;
    	}
    
    .Inputfields > .Inputfield > .ui-widget-content {
    	/* the Inputfield's content, padded from the borders */
    	padding: 1em;
    }
    
    .Inputfields .ui-widget-header {
    	/* typically the Inputfield's <label> */
    	padding: 0.25em 0 0.25em 1em;
    	-webkit-user-select: none;
    	-khtml-user-select: none;
    	-moz-user-select: none;
    	-o-user-select: none;
    	user-select: none; /* prevent selection of this element */
    }
    
    .Inputfields label {
    	/* label usually the same as the .ui-widget-header, but this applies to other labels too */
    	display: block;
    }
    
    /**
     * Tweaks specific to percentage width floated fields
     *
     */
    
    .InputfieldForm .Inputfields > .InputfieldColumnWidth {
    	/* an Inputfield that has a percentage width assigned to it */
    	float: left;
    	clear: none;
    	margin-top: 0;
    	margin-left: 1%;
    }
    	.InputfieldForm .Inputfields .InputfieldColumnWidthFirst,
    	.InputfieldForm .Inputfields .InputfieldColumnWidth + .InputfieldSubmit {
    		/* first Inputfield with a percent width... */
    		/* ...or the last percentage-width Inputifeld before the submit button */
    		clear: both;
    		margin-left: 0;
    	}
    
    /**
     * Margin and padding tweaks to prevent doubled visual whitespace
     *
     */
    
    .InputfieldForm .Inputfields > .Inputfield > .ui-widget-content > *:first-child,
    .InputfieldForm .Inputfields > .Inputfield > .ui-widget-content > div > *:first-child,
    .InputfieldForm .Inputfields > .Inputfield:first-child {
    	/* first child element of an Inputfield or it's content needs no top margin since it is already padded */
    	margin-top: 0;
    }
    
    .InputfieldForm .Inputfields .Inputfields > .Inputfield:last-child,
    .InputfieldForm .Inputfields > .Inputfield > .ui-widget-content > *:last-child {
    	/* last child element in an Inputfield content needs no margin since it is already padded */
    	margin-bottom: 0;
    }
    	.InputfieldForm .Inputfields > .Inputfield > .ui-widget-content .Inputfields.ui-helper-clearfix:last-child {
    		/* prevents extra space in the situation described by the selector */
    		/* example: the page editor sort settings box */
    		margin-bottom: -1em !important;
    	}
    
    /**
     * Inputfield states (collapsd vs. open, etc.)
     *
     */
    
    .Inputfields .InputfieldStateToggle {
    	cursor: pointer;
    }
    	.Inputfields .InputfieldStateToggle span.ui-icon {
    		/* the open/close icon that goes with most Inputfields */
    		float: right;
    		padding-right: 0.25em;
    	}
    
    	.Inputfields > .InputfieldStateCollapsed .ui-widget-header {
    		/* collapsed Inputfields appear sightly faded */
    		opacity: 0.6;
    	}
    	.Inputfields > .InputfieldStateCollapsed .ui-widget-header:hover {
    		/* when hovering, they are no longer faded */
    		opacity: 1.0;
    	}
    
    	.Inputfields > .InputfieldStateCollapsed .ui-widget-content {
    		/* collapsed Inputfields don't show their content (only header) */
    		display: none;
    	}
    
    .InputfieldForm .Inputfields .InputfieldStateError {
    	/* borders can break floated columns, so we avoid borders here */
    	border: none;
    }
    
    .InputfieldStateRequired > label.ui-widget-header:first-child:after {
    	content: ' *';
    }
    
    /****************************************************************************
     * Specific Inputfield types
     *
     * Defined here rather than as separate CSS files because their styles are
     * shared or there may be relationships with other Inputfields
     *
     */
    
    .Inputfields .InputfieldHidden {
    	display: none;
    }
    
    /**
     * Buttons
     *
     */
    
    .Inputfields .InputfieldSubmit,
    .Inputfields .InputfieldButton {
    	/* enable horizontal stack of buttons */
    	clear: none;
    }
    	.Inputfields .InputfieldSubmit .ui-widget-content,
    	.Inputfields .InputfieldButton .ui-widget-content {
    		/* we don't need our visual furniture for buttons */
    		padding: 0;
    		background: none;
    		border: none;
    	}
    
    	.Inputfields .InputfieldSubmit .ui-widget-header,
    	.Inputfields .InputfieldButton .ui-widget-header {
    		/* no need for a header with buttons */
    		display: none;
    	}
    
    /**
     * Text/Textarea fields
     *
     */
    
    .Inputfields textarea,
    .InputfieldMaxWidth {
    	/* full width fields */
    	width: 100%;
    }
    	.Inputfields textarea {
    		display: block;
    	}
    
    /****************************************************************************
     * Render Value Mode
     *
     * Used when only values are being rendered in the form (no inputs)
     *
     */
    
    .InputfieldRenderValueMode .InputfieldSelect li,
    .InputfieldRenderValueMode .InputfieldRadios li,
    .InputfieldRenderValueMode .InputfieldCheckboxes li {
            margin: 0;
    }
    
    .InputfieldRenderValueMode .InputfieldSubmit,
    .InputfieldRenderValueMode .InputfieldButton {
    	display: none;
    }
    
    .InputfieldCheckboxes ul li {
            /* we don't need checkboxes/radios to have bullets, etc. */
            list-style: none !important;
    	/* no need for top/bottom margins in a group of checkboxes or radios */
    	margin: 0 !important;
    }
    
    .InputfieldCheckboxes table,
    .InputfieldCheckboxesColumns,
    .InputfieldCheckboxesFloated {
    	width: 100%;
    }
    
    .Inputfields .InputfieldCheckboxesFloated li,
    .Inputfields .InputfieldCheckboxesColumns li {
    	display: block;
    	float: left;
    }
    
    .Inputfields .InputfieldCheckboxesFloated li {
    	padding-right: 1em;
    }
    
    .inputfields .InputfieldCheckboxesColumns li {
    	padding-right: 1%;
    	padding-bottom: 1%;
    }
    
    

    Thanks again for your help.

    Peter

    • Like 1
  10. Hi Harmster,

    Yes, here's some. My edit routine clicks through an array of field names, processes them, and then replaces a tag in an html template with the results of each field.

    Here's the code that processes each field:

    $inputfields = $page->getInputfields();
    
    foreach ( $field_array as $field_name => $display_status )
          {
          $field_tag      = ':!:' . $field_name . ':!:';
    
          if ( $display_status == 'display_only' )
                {
                $field       = $fields->get("$field_name");
    
                if ( !@include "./inc_view_fields_parse_types_code.php" ){echo $include_error; exit;}
                }
          else
                {
                $page->of(false);
    
                $field          = $inputfields->get("$field_name");
                $field_value    = $field->render();
                }
    
          $field_template = str_replace($field_tag, $field_value, $field_template);
          }
    

    The specific code includes these two lines:

                $field          = $inputfields->get("$field_name");
                $field_value    = $field->render();
    

    In my CSS file, I copied the classes from wire for the checkboxes.

    When I look at the page source, and compare the code around the fields in my API app, versus the code around the same fields in the Admin, it all looks very similar.

    I believe I must be missing some of the critical .js and/or .css files that the admin side uses.

    => I also need to use the admin popup calendar in a date field, so I'm thinking that it would be very, very helpful to get some documentation on which files can and should be included, from the core wire admin side, in a front end api app, that would enable one to use all the nifty things that the admin has.

    => One concern is that the css classes might conflict with app-specific classes.

    Is it as simple as including the following css and js file calls that one can see in the admin source (on an edit page)?

    	<link type='text/css' href='/wire/templates-admin/styles/main.css?v=2' rel='stylesheet' />
    	<link type='text/css' href='/site/modules/HelperFieldLinks/HelperFieldLinks.css' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Process/ProcessPageEdit/ProcessPageEdit.css?v=102' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.css?v=103' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Jquery/JqueryFancybox/JqueryFancybox.css?v=126' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Process/ProcessPageList/ProcessPageList.css?v=102' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Markup/MarkupAdminDataTable/MarkupAdminDataTable.css?v=101' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.css?v=104' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.css?v=103' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Inputfield/InputfieldPage/InputfieldPage.css?v=102' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Inputfield/InputfieldImage/InputfieldImage.css?v=100' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Inputfield/InputfieldFile/InputfieldFile.css?v=100' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Inputfield/InputfieldCheckboxes/InputfieldCheckboxes.css?v=100' rel='stylesheet' />
    	<link type='text/css' href='/wire/modules/Process/ProcessPageSearch/ProcessPageSearch.css?v=101' rel='stylesheet' />
    	<link type='text/css' href='/wire/templates-admin/styles/inputfields.css' rel='stylesheet' />
    	<link type='text/css' href='/wire/templates-admin/styles/ui.css?v=2' rel='stylesheet' />
    
    	<!--[if IE]>
    	<link rel="stylesheet" type="text/css" href="/wire/templates-admin/styles/ie.css" />
    	<![endif]-->	
    
    	<!--[if lt IE 8]>
    	<link rel="stylesheet" type="text/css" href="/wire/templates-admin/styles/ie7.css" />
    	<![endif]-->
    
    	
    	<script type='text/javascript' src='/wire/modules/Jquery/JqueryCore/JqueryCore.js?v=183'></script>
    	<script type='text/javascript' src='/wire/modules/Jquery/JqueryUI/JqueryUI.js?v=192'></script>
    	<script type='text/javascript' src='/wire/modules/Process/ProcessPageEdit/ProcessPageEdit.js?v=102'></script>
    	<script type='text/javascript' src='/wire/modules/Jquery/JqueryWireTabs/JqueryWireTabs.js?v=103'></script>
    	<script type='text/javascript' src='/wire/modules/Jquery/JqueryFancybox/JqueryFancybox.js?v=126'></script>
    	<script type='text/javascript' src='/wire/modules/Process/ProcessPageList/ProcessPageList.js?v=102'></script>
    	<script type='text/javascript' src='/wire/modules/Markup/MarkupAdminDataTable/MarkupAdminDataTable.js?v=101'></script>
    	<script type='text/javascript' src='/wire/modules/Jquery/JqueryTableSorter/JqueryTableSorter.js?v=203'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.js?v=104'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldPageTitle/InputfieldPageTitle.js?v=101'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.js?v=103'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldDatetime/jquery-ui-timepicker-addon.js'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldPage/InputfieldPage.js?v=102'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldTinyMCE/InputfieldTinyMCE.js?v=358'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldTinyMCE/tinymce-3.5.8/tiny_mce.js'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldImage/InputfieldImage.js?v=100'></script>
    	<script type='text/javascript' src='/wire/modules/Inputfield/InputfieldFile/InputfieldFile.js?v=100'></script>
    	<script type='text/javascript' src='/wire/modules/Process/ProcessPageSearch/ProcessPageSearch.js?v=101'></script>
    	<script type='text/javascript' src='/wire/templates-admin/scripts/inputfields.js'></script>
    	<script type='text/javascript' src='/wire/templates-admin/scripts/main.js?v=2'></script>
    

    I've assumed that it couldn't be that easy :-), and that doing so could cause all kinds of conflicts.

    But it sure would be nice to be able to easily use all those nifty admin tools, etc.

    Unfortunately, I'm not a Javascript or CSS guru. I sort of muddle through.

    Yours,

    Peter

  11. Hello Folks,

    I'm stuck on getting checkboxes to display in multiple columns in a front-end form, via the API.

    I've set the field to display in 3 columns, and it does so correctly in the back end admin page in edit mode.

    I've copied the InputfieldCheckboxes* CSS classes from the wire directories, and when I look at the source it all looks okay, compared to the admin source page, but the checkboxes in the front end only display in one column.

    Has anyone run into this? I'm sure I'm missing something, but I haven't figured it out yet.

    Thanks!

    Peter

  12. Hi All,

    I'm stumped by the right (safe) way to save textarea fields, via the API, and allow HTML tags and programming code.

    I'm creating a help ticket system that requires that type of content, that will display the codes in 'view' mode, not the result of the code.

    I've noted that the PW backend saves that type of content perfectly well, but I haven't been able to find the admin code in the core files, to copy the method of saving.

    * When I used the sanitizer->textarea function, it stripped out the code, and the option to list allowed tags would have been very long.

    * I noticed an option in the core files for 'stripTags' => false, but it was ignored when I tried that.

    * When I did a str_replace on single quotes, with backslashes, it just added extra backslashes.

    * When I used: $field_value = $db->real_escape_string($input->post->$field_name); it escaped line breaks, which I don't want.

    * Finally, when I simply saved the field without any escaping or sanitizing, it worked perfectly, even with single quotes in the text, but I somehow assumed that I should do something more secure than that.

    (and of course I'm using htmlentities on the 'view' mode)

    I read Ryan's post about SQL injections being a non-issue in PW, but there are also numerous posts about using sanitizer, and some about escaping single quotes.

    So... is it safe enough to not use sanitizer->textarea, or is there something I'm missing?

    Thanks,

    Peter

  13. Dear Pete and Soma,

    I don't want to save the form before the user does; I was just referring to the PW need to save the page before images get added.

    The error actually happens when the script tries to present the user with a blank form to add data, what I would call "add" mode, rather than "save" mode.

    I think Soma hit upon the answer. Thanks, Soma!

    I believe that I can still use my array of fields, and simply use the line you suggested:

    $inputfield = $fields->get($field->name)->getInputfield(null);

    inside the loop. I'll test it soon.

    If this works, then it's great, because it's an easy fix. :-)

    Thanks again,

    Peter

  14. Dear All,

    I couldn't find the answer to this... hopefully I didn't miss a post, since I don't want to duplicate posts.

    I'm having trouble adding a page that has an image field defined in the template field group, even though I'm not calling the image field in the code. I realize that you have to save the page first, before you add images. Thus, I'm trying to add a page and save it, without calling the image field.

    I've created a generic routine to create a form to add pages, based on a field list array and a routine that loops through the fields, calling them like this. First, I create the arrray (without the image field):

    $field_array = array(
                         'title'                                             => '',
                         'body'                                              => '',
                        );
    

    Then, based an action param, the script goes into "add mode", which presents the user with a blank add form.

    NOTE that at this point, nothing has been saved.

          # add mode
    
          $out .= "<br><h2>:: Add Mode ::</h2><br>";
    
          $new_page = new Page();
          $new_page->template = $templates->get("$template_field_group");
    
          $field_template = file_get_contents("$edit_template");
    
          if ( !@include "./inc_private_add_fields_code.php" ){echo $include_error; exit;}
    
          $save_form = "
          $cancel_button
          <form action='$full_page_url' method='POST' style='display: inline; margin: 0;'>
          $save_button
          <input type='hidden' name='a_' value='s'><br>
          <br>
          $field_template
          <br>
          $save_button
          </form>
          $cancel_button
          ";
    
          $out .= $save_form;
    

    Here's the code in the add routine, inc_private_add_fields_code.php:

    I think it's bombing out on the very first line:

    $inputfields = $new_page->getInputfields();

    When I removed the image field from the template, it all worked fine.

    $inputfields = $new_page->getInputfields();
    
    foreach ( $field_array as $field_name => $display_status )
          {
          $field_tag      = ':!:' . $field_name . ':!:';
    
          if ( $display_status == 'display_only' )
                {
                $field_value = '';
                }
          else
                {
                $new_page->setOutputFormatting(false);
    
                $field          = $inputfields->get("$field_name");
                $field_value    = $field->render();
                }
    
          $field_template = str_replace($field_tag, $field_value, $field_template);
          }
    

    The problem is that I want to:

    - keep the image field in the template

    - allow a user to add a page and save it without an image (per the PW need to have the page saved first)

    - add images later, in 'edit' mode.

    However, when I try to present an add form above, because the template field group has an image field, it bombs with the error:

    Error: Exception: New page '//' must be saved before files can be accessed from it
    

    I don't think it's a good idea to save a page from an 'add page form' before the user has hit save, because the user might want to cancel it.

    I hope there's a clever, PW way around this.

    I also hope that it can be integrated into the code above in "inc_private_add_fields_code.php", which as been working like a charm so far, as a generic code routine.

    Thanks for anyone's help!

    Peter

  15. Dear Ryan and All,

    I just installed PW on a shared server, for the first time, for a client, over at LiquidWeb.com.

    (I recommend them highly by the way. I've been with them for 8 years, with shared servers,

    VPS and dedicated servers, and their tech support is excellent.)

    I ran into two glitches, one of which was significant for the install.php file.

    1. Although the shared server was quite full featured, for some reason it didn't have mod_env enabled.

    (And LW doesn't mess with changes like that once a shared server has been deployed -- unfortunately.)

    Therefore, the line in the .htaccess file to set a var to confirm that mod_rewrite was working, broke.

    So, I had to comment it out.

      # Set an environment variable so the installer can detect that mod_rewrite is active.
      # SetEnv HTTP_MOD_REWRITE On
    

    Then, because that no longer was in play, I had to comment out the block of code in install.php that looked for that var.

    Since I was able to confirm with a tech that mod_rewrite was on, I didn't need the install file to check it. I commented out these lines:

    /*
    		if(function_exists('apache_get_modules')) {
    			if(in_array('mod_rewrite', apache_get_modules())) $this->ok("Found Apache module: mod_rewrite");
    				else $this->err("Apache mod_rewrite does not appear to be installed and is required by ProcessWire.");
    		} else {
    			// apache_get_modules doesn't work on a cgi installation.
    			// check for environment var set in htaccess file, as submitted by jmarjie.
    			$mod_rewrite = getenv('HTTP_MOD_REWRITE') == 'On' ? true : false;
    			if($mod_rewrite) {
    				$this->ok("Found Apache module (cgi): mod_rewrite");
    			} else {
    				$this->err("Unable to determine if Apache mod_rewrite (required by ProcessWire) is installed. On some servers, we may not be able to detect it until your .htaccess file is place. Please click the 'check again' button at the bottom of this screen, if you haven't already.");
    			}
    		}
    */
    

    After that, the install worked.

    I recommend that a config flag be added somewhere, to allow the install.php file to run without checking for mod_rewrite, with the noted caveat that it would mean that the person installing it must check manually.

    2. The second glitch was related to the fact that it was a shared server, and I added some Basic Auth code at the end of the .htaccess file to block the public while the site was being developed. When I did that, the server behaved the way I've seen .htaccess auth break in subdirectories. I'm not sure why it broke in the web doc root, but the solution was the same.

    (This has not happened in VPS's, so perhaps it's a symptom with shared servers.)

    The symptom, by the way, was that the Basic Auth directives were ignored, and the home page went to a 404 page.

    So, after adding this line at the top of the .htaccess file, it all worked.

    ErrorDocument 401 "Unauthorized"
    

    This line also worked, but I chose the the first option:

    # this was an alternate method to fix the above
    RewriteCond $1 !^(401.shtml)
    

    The second option was offered by a brainy LiquidWeb tech, which jogged my memory about the first option.

    Even though the second problem wasn't a specific PW issue, I thought it might be a valuable tip for anyone wanting to install PW on a shared server, when the home page has to be protected by Basic Auth. It threw me when I couldn't log into my admin url after installing PW.

    Anyway, after all this, PW seems to be behaving quite well on a shared account on LiquidWeb, which is a big step up from Drupal, which, as far as I know, doesn't work well at all in a shared environment.

    Plus One for PW. :-)

    Edit: I also recommend that you place in the list of server requirements a note about Mod_Env as it relates to SetEnv. It's not only an issue for the installation, but also provides an extra security method for using Basic Auth on the admin login page, as I wrote about in my post here:

    http://processwire.com/talk/topic/3706-how-to-blockredirect-one-user-role-away-from-admin-pages/?p=46421

    If I had known about this (or thought about it) before deploying the shared account, I would have specified that it was a requirement.

    Peter

    • Like 1
  16. Hi Kongondo,

    I'm probably missing something, but what about using the code in ProcessWire for uploading images?

    PW's image uploader has a progress bar, and the TinyMCE implementation has an icon to grab an image attached to the page.

    Has anyone figured out how to use those two things in front-end forms in PW, via the API? (Not the form builder, but just straight PHP/API code.)

    I'd like to use TinyMCE in a front end textarea field, and also use the PW progress bar on an image upload field.

    Yours,

    Peter

×
×
  • Create New...