SLB: Notes – JS: Components: Themes: Layout Tags

By Sol in Lab

Requirements

  • Insert predefined HTML
    • Core and theme-specific
  • Support dynamic content
    • Changes on per-item basis
    • Necessary to support multiple content types (e.g. images in <img> element, HTML in <div>, etc.)
  • Support attributes/options
    • Customize how tag is processed/output
  • Support user-customizable options (UI labels, formatting, etc.)

Elements (Core)

  • Content: Primary content (image, video, etc.) displayed in lightbox
    • Dynamic: HTML changes based on content type
  • Item Data: Data/attributes of current item
    • Examples: Permalink, source URI, image dimensions, title, caption, description, etc.
    • Available attributes based on item’s content type
    • Common attributes
      • Source URI (string): Direct URI to content (for display in lightbox)
        • Image source, video file, etc.
      • Permalink (string): Canonical URI for content (e.g. when viewed on its own page)
        • Video page, attachment page, image URI, Website address, etc.
      • Title (string): Item caption
        • Derived from link if not otherwise available
      • Group (obj): Group item belongs to
      • Internal (bool): Whether item is internal media or not
  • UI elements
    • Static: Does not change per-item
    • Labels: User-customizable UI content
      • Navigation text: previous/next item, start/stop slideshow, close, etc.
    • Predefined elements: HTML for building UI (close button, prev/next button, loading indicator, etc.)

Implementation

  1. Dynamic Data (options)
    1. Wrap tag output with DOM element
      • Example:
        <span id="slb_tag-id" class="slb_dynamic_wrap">[tag output]</span>
      • Wrapper indicates dynamic data using DOM attributes
        • class: slb_dynamic_wrap
        • id: slb_tag[id] (Points to object with tag options)
        • Alternative: Set reference to raw tag as data on wrapper element itself
          $(el).data('slb_tag', tag);
      • + Allows dynamic replacement of content in viewer
      • Similar to current method of loading new content in lightbox (replace HTML inside of a wrapper DOM element)
      • + Allows any tag to be dynamic
      • ? Should all tags be dynamic?
        • A: No, only those accessing data (item, environment, date/time, etc.)
      • - Cannot use data within HTML tags (since tag output is wrapped in a DOM element itself)
        • Example
          Original

          <a href="domain.com/file.html?id={tag}">Link text</a>

          Rendered

          <a href="domain.com/file.html?id=<span id="slb_tag-id">[tag output]</span>">Link text</a>
        • Solution (options)
          1. Build HTML tag using options in theme tag
            • Example
              • Link
                <a href="domain.com/file.html?id=[tag data]">Link text</a>
              • Tag
                {tag pre='<a href="domain.com/file.html?id=' post='">Link text</a>'}
              • Alt
                {tag format='<a href="domain.com/file.html?id=%s">Link text</a>'}
                • Uses string formatting to replace %s with tag output
            • Entire output wrapped in wrapper
            • Original string format saved
            • Formatted value inserted as HTML into DOM (wrapped)
            • + Allows complex output using item data
            • + Does not impede HTML output
            • - Convoluted way to build HTML output using tag output
            • - Limited: How to use other data within link? (link text, title attribute, etc.)
          2. Register handlers for different tags
            • Similar to CNR content type field templates
            • Example: Link
              {link href="domain.com/file.html?id=%s" data="item.permalink"}Link text{/link}
              • Attributes
                • href: URI format
                • data: Data to use in URI format
                • title: Link title (can be string format)
                • title_data: Data to use for Link title
                • Link text: Wrapped in tag
            • + More specific handling of output
              • Attribute data will be properly formatted (escaped for URLs, etc.)
            • + Simple: Don’t need to mess with HTML in tag attributes
            • - More complex to implement
            • + Highly flexible: any kind of output can be accomplished by tag handlers
    2. Rebuild entire layout for each item
      • Start with raw layout (with tags, etc.) every time an item is displayed
      • - Inefficient: must parse entire layout for each item (even if few dynamic tags are present)
        • Performance may suffer
      • + Will always be a certain amount of dynamic data in layout (content, etc.)
        • Parts of layout must always be rebuilt per-item anyway
      • ? Visual smoothness? Rebuilding full layout affect transition between items?
        • Likely
      • + Simple: Don’t need to wrap tags since raw layout will be used every time
  2. Tags (Default)
    • item: Access item data/properties
      • Example:{item.title} – Item title
      • Dynamic: Yes
      • Format modifiers: Yes
        • {item.title|lower|escape} (makes item title lowercase and escapes it)
    • ui: User interface output
      • Example: {ui.nav_next} – Next item navigation link
      • Dynamic: No
      • Format modifiers: No
    • Common attributes: Can be set on all default tags
      • May be implemented differently by different tags
      • class: CSS class
      • id: Unique ID
  3. Tag format (Options)
    1. Curly braces + XML-style attributes
      • Tags denoted by curly braces ({, })
      • Options/attributes set XML-style: attribute="value"
      • + Simple: Familiar to any using HTML
      • + Fairly unique: Curly braces not common in normal content
      • ? How do format modifiers fit in?
        • Simple: {tag.prop|modifier}
        • With Options
          1. XML-style attributes followed by delimited modifiers: {tag.prop attribute="value"|modifier}
            • Attributes processed first, then passed to modifiers
            • + Clear separate between modifiers and attributes
            • + Still pretty simple to write
            • - Convoluted: 2 different modes for similar information (options that modify output)
          2. Format modifier style: {tag.prop|attribute:value|modifier}
            • - Attributes not clearly separated from modifiers (hard to tell when option is an attribute or a modifier)
            • + Simple: Singular way to add options that modify output
            • + Tag handler can use supported options and pass output to global modifiers after (with processed options removed)
              • supports_modifiers flag in tag definition can determine whether output is processed by global modifiers or not
          3. One or the other (attributes or modifiers): {tag.prop attribute="value"} or {tag.prop|modifier}
            • - Limiting: May be useful to have access to properties and modifiers in tag
              • ? When? (Use cases)
                • Item: No – Modifiers only ({item.title|lower})
                • UI: No – Attributes only ({ui.nav_next class="test"})
                  • Outputs DOM element, so should not be modified by standard modifiers (lower, etc.)
                    • Formatting of values (e.g. labels) should be handled via CSS
                • Custom Tags: Possibly ({tag attr="value"|modifier})
                  • + Allows theme designer to further customize output from custom tags
    2. Double braces (curly/square) + XML-style attributes
      • Attributes same as 1
      • Tags denoted by double braces ({{/}} or [[/]])
      • + More unique: double braces even less common than single braces in content
      • - More characters to type for every tag
      • - Increases visual “noise” in layout
    3. Other established format
      • Liquid, Smarty, etc.
      • Need to look into options
  4. Registering External Tag Handlers (options)
    1. Client file registration (via other plugins)
      • Allow additional files to be registered with internal client files
      • Use same structure: [handle, file, etc.]
      • - Will need to expand file parser to handle external files
        • + Not too difficult since external files should have full path rather than relative path (just look for presence of path constants)
      • + Allows simple inclusion of JS files after internal files loaded
        • JS file can register tags, etc.
      • Use dependencies to determine order of loading external files
        • + Also controls whether external file is loaded (if dependent on internal file that is not loaded, external file with not be loaded, etc.)
    2. WP Hooks
      • Fire hooks before/after various operations
      • Events
        • slb_head/slb_admin_head: Header files loaded
        • slb_footer/slb_admin_footer: Footer files loaded
        • slb_client_init: Client JS initialized
      • + Allows external code to add files/code in proper location
        • Ensures SLB’s files are loaded before external code is executed
      • ? How to confirm necessary files have been loaded?
        • Hooks will always fire, but different files are loaded based on various conditions (context, callbacks, etc.)
        • A Use SLB functions in external code to determine if external file should be loaded
          • PHP
            /* External Plugin */
            add_action('slb_head', 'ext_load_head_files');
            
            function ext_load_head_files() {
            	if ( slb_is_enabled() && slb_is_context('public') ) {
            		//Load files...
            	}
            }
          • JS (object detection)
            /* Confirm SLB loaded */
            if ( !SLB || !SLB.View )
            	return false;
            
            /* Run code */
            SLB.View.add_tag(...);
      • ? How to fire hook after files loaded?
        • File loading is handled by WP enqueue/registration API (No direct loading)
        • AAdd hook to trigger SLB hook
          //Low priority hook
          add_action('wp_head', 'call_slb_head', 99);
          
          function call_slb_head() {
          	//Fire internal hook
          	do_action('slb_head');
          }
  5. Tag Handlers
    • Properties
      • id (string): Tag ID
      • build (function): Function to build tag output
      • attrs (object): Default attributes/values
      • dynamic (bool): Tag rebuilt for each item or not
      • supports_modifiers (bool): Determines if modifiers can be used on tag output