Skip to content

Latest commit

 

History

History
434 lines (330 loc) · 13.4 KB

core.md

File metadata and controls

434 lines (330 loc) · 13.4 KB

Core

Formstone Library core. Required for all plugins.

Using Core

Formstone Object

The Formstone core is a dependency of all JavaScript based components and will contain a few global values, as well as a simple plugin factory. The global Formstone object has access to the following keys:

Key Type Description
$window object Reference to jQuery wrapped window
window object Reference to original window
$document object Reference to jQuery wrapped document
document object Reference to original document
$body object Reference to jQuery wrapped body tag
Plugins object Contains all registered plugins
Version string Current version number
support.file boolean File API support
support.history boolean History API support, including push and pop state
support.matchMedia boolean Match Media API support
support.nativeMatchMedia boolean Native Match Media API support (no polyfill, requires feature test classing)
support.raf boolean Request Animation Frame API support
support.touch boolean Touch event support
support.transition boolean CSS3 Transition support
userAgent string Raw user string
isChrome boolean Browser is Chrome
isFirefox boolean Browser is FireFox
isSafari boolean Browser is Safari
isMobile boolean Browser is Mobile
isFirefoxMobile boolean Browser is FireFox Mobile
transform string Prefixed transform property
transition string Prefixed transition property
windowWidth int Current window width
windowHeight int Current window height
fallbackWidth int Match Media fallback width

User agent sniffing isn't always reliable or considered best practice - it should be used sparingly, if at all.

Plugin Factory

The Formstone.Plugin factory function is used to define a plugin. The factory will use the provided namespace to register the plugin with jQuery. The plugin is then available like any other:

$(".target").plugin({
  option: value
});

AMD Support

Plugins should remain compatible with module loaders like RequireJS or webpack:

(function(factory) {
  if (typeof define === "function" && define.amd) {
    define([
      "jquery",
      "./core",
      "./dependency",
    ], factory);
  } else {
    factory(jQuery, Formstone);
  }
}(function($, Formstone) {

  // Plugin

})

);

Plugin Types

There are two types of plugins that can be defined: Widget or Utility.

Widget

Widget plugins are implicitly tied to an element to enhance or change the interface. Examples of Widgets include input enhancements like Checkbox or Dropdown. A simple Widget might look like:

/* global define */

(function(factory) {
  if (typeof define === "function" && define.amd) {
    define([
      "jquery",
      "./core",
      "./dependency",
    ], factory);
  } else {
    factory(jQuery, Formstone);
  }
}(function($, Formstone) {

  "use strict";

  function setup() {
    // this = document
  }

  function construct(data) {
    // this = jQuery wrapped target element
    // data = instance data
  }

  function destruct(data) {
    // this = jQuery wrapped target element
    // data = instance data
  }

  function reset(data) {
    // this = jQuery wrapped target element
    // data = instance data
  }

  // Register Plugin

  var Plugin = Formstone.Plugin("namespace", {
      widget: true,
      defaults: {
        option:    value
      },
      classes: [
        "visible"
      ],
      methods: {
        _construct     : construct,
        _postConstruct : construct,
        _destruct      : destruct,
        _resize        : resize,
        _raf           : raf,

        reset          : reset
      },
      utilities: {
        close:         close
      }
    }),

    // Localize References

    Classes      = Plugin.classes,
    Events       = Plugin.events,
    Functions    = Plugin.functions;

  Formstone.Ready(setup);

})

);

As in the example above, Widgets can override the following internal methods by pointing a key to the corresponding local function:

Method Description
_construct Run at initialization of each instance, scoped to specific instance
_postConstruct Run after initialization of current instance set, scoped to specific instance
_destruct Run at destruction of each instance, scoped to specific instance
_resize Run on window resize, scoped to window
_raf Run on request animation frame, scoped to window

When an instance is created or destroyed, the factory will automatically add or remove the instance's localized plugin data. This data is available as the first argument in any public method call, or by using the namespace to query for the data:

this.data("namespace");

Custom public methods can also be defined, provided their keys are not prefixed with an underscore (_). The underscore signifies a core method and should be avoided when defining public methods. The factory will scope any public method call to the target instance, as well as provide it's plugin data as the first argument followed by any additional arguments:

$(".target").namespace("reset", 500);

A Widget can also operate as a singleton, like Lightbox or Tooltip. In this case, events are bound to the instance's target element, while DOM manipulations are tied to a single internal instance. This helps prevent unwanted duplication when the interface pattern calls for a single instance.

Utility

Utility plugins may interact with DOM nodes but are not necessarily tied to any specific elements. An example of a Utility is the media query event abstraction provided by Media Query. A simple Utility plugin might look like:

/* global define */

(function(factory) {
  if (typeof define === "function" && define.amd) {
    define([
      "jquery",
      "./core"
    ], factory);
  } else {
    factory(jQuery, Formstone);
  }
}(function($, Formstone) {

  "use strict";

  function delegate() {
    // Manually handle public methods
  }

  // Register Plugin

  var Plugin = Formstone.Plugin("namespace", {
      utilties: {
        _delegate:     delegate
      }
    }),

    // Internal Defaults

    Defaults = {
      option    : value
    },

    // Localize References

    Document = Formstone.$document[0];

})

);

A utility can override the default method delegation by pointing the _delegate key to a custom function. The delegate function will need to manually handle any arguments passed. Otherwise, Utilities will use the same public method delegation system as Widgets.

$.namespace("reset", 500);

Plugin Object

Defining a plugin using the factory will return an object containing the follow keys:

Key Type Description
namespace string plugin namespace
initialized boolean initialized state
defaults object default options extended with initialization and local options
functions object private utility functions
methods object public methods
utilities object public utility methods
classes object namespaced classes strings
events object namespaced event strings

These values can then be localized in the scope of the plugin for optimal minimization:

var Plugin = Formstone.Plugin(“namespace”, {
    ...
  }),
  Defaults     = Plugin.defaults,
  Functions    = Plugin.functions,
  Methods      = Plugin.methods,
  Utilities    = Plugin.utilities,
  Classes      = Plugin.classes,
  Events       = Plugin.events;

This may seem strangely redundant at first, however multi-dimensional objects do not minimize efficiently. This is also one reason standard prototypal inheritance is not used when building a plugin, however this is not to say a specific plugin could not contain locally scoped prototypes. Plugin design is always up to the developer, the factory simply provides a consistent, DRY approach to the basic plugin pattern.

Classes

The classes object returned when defining a plugin will contain properly namespaced strings of both default and custom classes. Custom classes will become object keys, while the namespaced class will become the value:

var Plugin = Formstone.Plugin(“namespace”, {
  ...
  classes: [
    "visible",
    "content"
  ],
  ...
});
var $element = $(Classes.content);
Key Type Value
base Default .namespace
element Default .namespace-element
visible Custom .namespace-visible
content Custom .namespace-content

The classes.raw key will contain just the namespaced class without the leading '.', useful for building html:

html += '<div class="' + Classes.raw.content + '">';

Events

The events object returned when defining a plugin will contain properly namespaced strings of both default and custom events. Custom events will become object keys, while the namespaced event will become the value:

var Plugin = Formstone.Plugin(“namespace”, {
  ...
  events: [
    "enable",
    "disable"
  ],
  ...
});
data.$el.on(Events.click, onClick);
Key Type Value
namespace Default .namespace
beforeUnload Default beforeunload.namespace
blur Default blur.namespace
change Default change.namespace
click Default click.namespace
clickTouchStart Default click.namespace touchstart.namespace
dblClick Default dblClick.namespace
drag Default drag.namespace
dragEnd Default dragend.namespace
dragEnter Default dragenter.namespace
dragLeave Default dragleave.namespace
dragOver Default dragover.namespace
dragStart Default dragstart.namespace
drop Default drop.namespace
error Default error.namespace
focus Default focus.namespace
focusIn Default focusin.namespace
focusOut Default focusout.namespace
input Default input.namespace
keyDown Default keydown.namespace
keyPress Default keypress.namespace
keyUp Default keyup.namespace
load Default load.namespace
mouseDown Default mousedown.namespace
mouseEnter Default mouseenter.namespace
mouseLeave Default mouseleave.namespace
mouseMove Default mousemove.namespace
mouseOut Default mouseout.namespace
mouseOver Default mouseover.namespace
mouseUp Default mouseup.namespace
panStart Default panstart.namespace
pan Default pan.namespace
panEnd Default panend.namespace
resize Default resize.namespace
scaleStart Default scalestart.namespace
scale Default scale.namespace
scaleEnd Default scaleend.namespace
scroll Default scroll.namespace
select Default select.namespace
swipe Default swipe.namespace
touchCancel Default touchcancel.namespace
touchEnd Default touchend.namespace
touchLeave Default touchleave.namespace
touchMove Default touchmove.namespace
touchStart Default touchstart.namespace
transitionEnd Default transitionEnd.namespace

Document Ready

Changes introduced to the ready event handler in jQuery 3 can cause a flash of unstyled content before widget plugins have completely initialized. The Formstone.Ready handler utilizes the native 'DOMContentLoaded' event to avoid the flash and can be safely used a jQuery ready replacement:

Formstone.Ready(function() {
  ...
});

No Conflict

One benefit of Formstone is the module nature of the components, allowing developers to include only what's required. Certain edge cases may require overlapping namespaces between two or more libraries. To avoid (some) namespace collisions with other libraries, such as Bootstrap or Lightbox, developers can call the Formstone.NoConflict() method to restore all jQuery plugin namespaces to their 'original' functions. Other libraries should be included before Formstone components, however Formstone will remember this flag and avoid registering un-namespaced plugins included after the initial call. Note: This does not effect data attributes or events, only the jQuery plugin namespace.

Formstone.NoConflict();

Methods

NoConflict

Resolves plugin namespace conflicts

Formstone.NoConflict();

Plugin

Builds a plugin and registers it with jQuery.

Formstone.Plugin("namespace", { ... });

Parameters

Name Type Default Description
namespace string   Plugin namespace
settings object   Plugin settings

Ready

Replacement for jQuery ready

Parameters

Name Type Default Description
e object   Event data