jquerymy.js ‹{}›

Guide and API v1.3.4

Press Ctrl-F or ⌘-F to search the guide. Explore demos to quickstart.

Basic concepts

jquerymy is a plugin, not a framework. $.my works in browser and runs only client side of a web app. $.my does not include router, net functions, auth and security etc. Use your best-loved solutions for that tasks.

One app – one object. Any $.my app, its behavior and facade, is defined using single standard javascript object, hereafter manifest. ‘Standard’ means you need not learn new syntax rules or list of directives. All plugins are applied using their standard APIs, all code is good old-fashion javascript.

Extension-friendly. jQuery.my understands a lot of rich-ui plugins out of the box, and also can be extended to understand new solutions.

JSON-friendly. $.my manifests are JSONable though are very well suited for modern noSQL DBs. One doc – one app, no additional files or resources. 

Recursive. Any instance of $.my form can act as a single component for another form, which is common approach for complex nested composite apps. Children manifests are defined as properties of a parent app manifest object.

Robust. $.my is IE11+ compatible and fault-tolerant: when a child form or any control fail, its parent app usually stays operational.

Quick start

jQuery.my requires Sugar.js 1.4~ (not 1.5 or 2.x) and jQuery.js 2.0+ preloaded. You can use CDNJS repo for all required components:

xxxxxxxxxx
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/sugar/1.4.1/sugar.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery.my/1.2.14/jquerymy.min.js"></script>
xxxxxxxxxx
 
// Place your javascript here
xxxxxxxxxx
 
/* Container for CSS code */

$.my forms are initialized and managed during runtime according to jQuery standard  recommendations for plugins.

General syntax is $(DOM_node).my("command", param1, param2). If no command passed $.my assumes "init" requested. 

To create a form

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
// Source data
var person={ 
  name: "Ann", 
  metrics:{ age:"25" } 
};
// Manifest
var manifest = {
  
  //Default data  
  data: { name:"", metrics:{ age:"" }},
  
  // Init function  
  init: function ($node, runtime) {
    $node.html(
      '<h4>Simplest form</h4>'+
      '<div><input id="name" type="text" placeholder="Name"/></div>' +
      '<div><input id="age" type="number" placeholder="Age"/></div>'
    );
  },
  
  // Bindings
  ui: {
    '#name': { bind: 'name' },
    '#age' : { bind: 'metrics.age' }
  }
};
// Init $.my over DOM node
$("#form").my( manifest, person );
xxxxxxxxxx
 
/* Container for CSS code */

Above code generates this form:

Properties of person variable reflect states of two HTML controls. When control receive input, person is mutated.

Bindings like 'metrics.age' are just syntax sugar. Strings like 'arrayName.3' to bind with an array rows are also ok.

The manifest argument of $.my invocation defines form facade and bindings. Second argument, person, is data object the form is bound to and mutates on user input.

Getting form’s data

$('#form').my('data') returns a reference to dynamically updated object, bound to UI controls. When data is updated, change event is fired on form’s DOM node. Generally, object returned is ‘classic’ javascript object and is any-time serializable.

Setting form’s data

$('#form').my('data', { /* Data */ }) applied to running form updates its data and UI. Data received is merged deep with current app data – so update can be partial. For above example $('#form').my('data', {name:'John'}) changes only the name prop.

If data is external variable (like person in above example), external update of the var would not raise form update automatically. You must call $('#form').my('redraw') explicitly to make form know that data was updated.

Manifest structure

Manifest is a standard javascript object with some reserved properties:

  • data Default data object
  • die Function called on form disband, with same arguments as init
  • expose Obj, array or string, list of nodes allowed to be inherited by successors
  • files CouchDB-style object with base64-encoded binary resources inlined. Resources obtain session URL when the form starts.
  • id String, unique identifier of the manifest, autogenerated if omitted
  • inherit Obj, array or string, list of manifest nodes to inherit from parent
  • init Function, called just before building bindings
  • lang Localization dicts
  • my Non-enumerable object, container of $.my app runtime methods attached to manifest during form init.
  • params Object, defines form settings
  • radio Radio relay object
  • require Array of resources required to start the form
  • style Object which defines CSS rules local for the form
  • ui Required property, defines bindings between DOM and data. Object, each key is a valid jQuery selector of a control. Value under each key defines control section for a child DOM element which matches a key.
Custom properties of a manifest, if any, better have Capitalized or camelCase keys to ensure no conflict with future versions of $.my. 

Binding data to a control

The ui object of a manifest assumed to be a flat key/value dict. Each key is jQuery selector and each value is a control section for the DOM node which matches the selector.

Property bind of a control section should be a string reference or a function. 

  • If a string, bind assumed to be a dot-notation reference, pointing to the branch of form’s data object, or, if defined as "this.SomeKey", the branch of the runtime manifest.
  • If a function, bind is called any time control receives input or when $.my forced the control to update. The bind function receives three arguments: (dataObj, newValue, $control)

dataObj is a reference to form’s data object. It‘s important to keep data object anytime serializable to JSON.

If newValue is null, function must return value to put into the control. If not null – binder function must store newValue into appropriate branch of dataObj and may return new/updated value for the control.

So bind function acts like both getter and setter. The above example can be rewritten:

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
$('#form').my({
  ui:{
    '#name': 'name',
    '#age' : {
      bind: function (data, value, $control) {
        var dm = data.metrics;
        if (value != null) dm.age = value; 
        return dm.age =  (dm.age + '').replace(/\D/g, '');
      }
    }
  }
}, person);
xxxxxxxxxx
 
/* Container for CSS code */

This example makes impossible to put anything but number into #age input. Depressing any non-num key makes no visible sense, non numeric chars are stripped immediately.

 Third argument, $control, is deprecated and will be probably removed in $.my 2.0. Use proxies like this.my.method instead. 

The third argument $control is a jQuery object of a DOM control being processed. It has several extension properties and can be useful for navigation over form DOM tree. $control.my('find', '#name') returns #name control from inside the form as a jQuery object.

Also bind function receives this pointing to runtime.

Dependencies

Dependencies are defined using watch and/or recalc properties. 

Both watch and recalc are shown. Syntax watch: "#num2, #num3" means ‘When #num2 or #num3 changed, update me’. Syntax recalc: "#product" means ‘When I was changed, update #product’.

If both external recalc and own watch are defined for a control, recalc runs first.

Loop dependencies

Controls can be cross-dependent. They even can be looped in dependency rings of 3+ more controls:

To keep recalc graph manageable, default dependency resolution depth is 2. Value can be increased for deep dependency trees or long loops using recalcDepth property, that can be defined for any particular control.

Tuning bind events

By default $.my tracks control’s most frequent events. However one may need less frequent updates. For example we may need data to be updated when textarea loose focus, not on every key press.

Events that trigger control’s update are defined using events property. It’s a string, or an array of strings. 

To ensure event listeners unbind when form is removed add .my namespace postfix for event types.

Delayed bind

Some controls raise update events very frequently. Calling bind function on every single update can take excessive amounts of CPU and RAM. The delay property defines minimum gap between subsequent bind calls. If there is a series of events all raised in gaps smaller than delay, only the last event invokes bind, other events are suppressed. 

When control is rebuilt during dependency recalc its bind is executed without any delay, in sync.

Update on pub/sub event

Control can be updated on pub/sub event. For example we received new items and need list of them to be redrawn. Pub/sub events reaction is defined in listen property:

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
({
  List:[],
  ui:{
    "#filter":{
      bind: function(){ /* We (re)build list here */},
      
      listen:{
        // Here we listen to /list and /item channels
        "/list": true,
        "/item": function(data, message, $ctrl){
          if (message && message.doctype == "item") return true;
        },
      }
    },
    "#list":{
      bind:"this.List",
      watch:"#filter",  // Watch for filter changes
      manifest: { /* Here goes list item manifest */ }
    }
  }
})
xxxxxxxxxx
 
/* Container for CSS code */

This control #filter is redrawn when /list channel receives any message or when /item channel receives appropriate doctype. We assume that #filter rebuilds list of items, and then #list is redrawn.

Messages can be transmitted using $.my.radio(channel, msg) for global broadcast or using $ctrl.trigger("radio", {channel:"channelName", message:msg}) for realm-controllable broadcast.

Validation

Validators are located in .check properties of controls’ ui sections. For a simple control its validator can be a regexp, a function, or a list of acceptable control’s values. For nested lists the .check prop can be true to propagate children errors to a parent form, or a function which validates entire underlying list data array.

Regexp validation can only indicate the fact of mismatch, message is predefined in the manifest (error property of control‘s ui section). Same for array of allowed values.

Validator function can return custom error messages.

Validation takes place just before bind call. When validation fails, closest DOM container of the control receives class .my-error. Then $.my looks for an element with class .my-error-tip within this container, makes it visible and puts error message inside. If no element found, title attribute of the control receives the message. 

For non-interactive controls (<div> bound to data, for example) .my-error class is applied to element itself, not to its container.

Regexp validation

If the #name input element has less then 3 chars, container receives class .my-error.

.my-error-tip receives validator message, so to make message visible there must be an element with my-error-tip class inside control’s container. 

Validation with function

Validator check receives same arguments as bind, but is executed before bind. Unlike bind, check is never called with value === null.

Entire form validity

$("#formObj").my("valid") returns true if all form’s controls are valid, and  false  otherwise.

$("#formObj").my("errors") returns an object. Keys are controls’ selector, and values are error messages. Form is valid if the object has no keys. Children forms’ error objects are attached under selectors the child was bind to parent form if and only if a child’s subform or list has .check:true, otherwise if .check is a function, its result is included.

Object returned with this.my.errors() from inside bind is nearly the same, but may contain empty string values (which means control under key selector is valid).

Conditional formatting

Allows different CSS rules to be applied over control’s container when conditions are met. Condition is a regexp or a function. There exists special key :disabled, that disables control when its condition is met.

Conditional formatting is applied after check and bind. To apply rule to control itself, not container, prefix self: must be added to a rule key. Rule "self:red":function(){...}  is applied to control, not to its container.

Local CSS rules

CSS classes .Red and .Green of above example are defined locally using style property of the manifest. Those classes are translated into runtime CSS rules, which are applicable only to form’s inside – so different forms don’t interfere. One form can have class .Green that is yellowish, and other – that is olive. They both are local.

When form starts, $.my creates unique <style> tag in current document, and puts compiled CSS rules inside. To avoid <style> dupes for every instance of a form, form’s manifest must have id property. 

Note leading spaces in keys. Spaces needed when key hierarchy is concatenated to produce rule.  " .Red" + " input" become something like

.my-manifest-1ftwlphd .Red input {background-color: #FCC; color: #C02;}.

Rules can be defined as functions:

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
style:{
  " .item": function ($form, runtime) {
    if ($form.width()<500) return "display:none";
    return {
      " p": "font-size:80%",
      " a": "color: blue"
    };
  }
}
xxxxxxxxxx
 
/* Container for CSS code */

When a rule is defined as a function, it is calculated on start, just before init function runs. 

Also function-defined custom rules can be recalculated each time window obj receives resize event. The property restyle of params section of manifest defines delay between resize event and style recalc. By default (value is -1) no restyle wired on resize – it can be costly. 

The above example evaluates form width and returns different CSS rules if the form is wider than 500px.

New <style> element is created for every single instance of a manifest with function-defined styles.

Form init

Every control’s bind section and entire manifest can have init property, that is function.

All those functions run once when form starts, can be async and are useful for remote data retrieval, rendering HTML, applying rich ui plugins to controls and so on. 

Any init function can return promise. Init assumed completed when promise is resolved. If returned value is not a promise, init assumed completed immediately.

Code below builds HTML skeleton, loads external data and builds <select> control, applies plugin to it and then fades the form in. 

Note how code that fades the form in is subscribed to form init successful finish. 

Init function is invoked after manifest properties inheritrequire, files and style are successfully processed (if any). So when init starts, all resources are loaded, files have session URLs and styles are calculated and applied to form.

Note that radio section and though pub/sub events are not processed unil entire form starts.

Runtime: this and this.my objects

Every function inside running app is bound, and so sees own parent manifest as this. First level children functions inside the app object, if any, also see app as this after form start.

Actually, runtime version of a manifest is slightly different from original. Shorthanded prop are unfolded, string references are resolved and so on. Those differences are insignificant in most cases although.

Runtime as data store

Manifest runtime object is not sealed or frozen. It means internal app functions can use this to store intermediate results not suitable to live in main data section. 

Any form control can be bound not only to props of data object, but to this-hosted data, just use bind:'this.MyProperty' syntax. Children of this are not restricted to be anytime-serializable unlike data section. Members of app root can have circular references, be DOM objects and so on. 

this.my methods

Since 1.2.0 any form‘s manifest receives additional non-enumerable property my, that proxies several useful runtime methods. They are visible from inside manifest functions as:

this.my.root()

Returns jQuery object of form‘s root DOM node.

this.my.indom()

Returns true if form‘r root is in document DOM (form was not removed).

this.my.parent()

Returns runtime manifest object of the parent form, if any. ‘Parent’ here means the first DOM ancestor with .my-form class.

this.my.ajax( obj )

Ajax call, by default uses standard jQuery syntax, returns jQuery promise.

this.my.cancel(), this.my.commit()

Triggers commit or cancel event on form‘s root. 

this.my.index()

For children forms in lists returns zero-based index of a form in parent list.

this.my.insert("#node", where, obj)

Inserts element in a list of forms under jQuery selector. If selector is omitted, insertion is performed on the first ancestor of the form‘s root (allows insert call from inside list elements). 

The where argument is a number or a string, position to insert. Strings "before" and "after" are allowed for insert calls from inside of other list elements.

Argument obj is an object to insert.

this.my.check("#node"), this.my.recalc("#node")

Triggers check or recalc events on a control for a given jQuery selector. Looks up a control only inside the form.

this.my.trigger("#node", "event")

Triggers given event on form‘s child.

this.my.modal("#node", obj)

Opens modal dialog, pivotted to "#node" DOM object. Returns dialog Promise. All child dialogs are automatically closed on parent form disband.

Other available this.my methods are listed at External commands section.

Nested forms

Any $.my form can act as a control for other embracing $.my form, forms can be nested. Set of repeated child form bound to an array of data are also supported. Moreover, an array can consist of items of different types, and list can pick different children forms according to value type.

When nested form is bound as a control, bind property must be a string. If bind points to an object, single child form is applied. If bind points to an array, list of repeated forms is built.

Single child form

Child forms’ init functions can be async if they return a promise. In this case list start (and parent form binding) assumed successful when all promises are resolved. 

Repeated child form

If bind property of a selector points to an array and there is manifest property, $.my builds repeated list of child forms. Each form by default lives in container <div></div>. To change container type or attributes, define container HTML in list property.

Insertion/deletion are event-driven. To delete row any control from inside the row must trigger remove event or this event can be fired over child form’s container.

Event insert must be triggered to insert row. Insertion supports additional argument, that defines what to insert and where. $control.trigger ("insert", param). Param is a string or an object:

  • "before" inserts empty row before caller row
  • "after" inserts row after
  • {where: "before" | "after" | index, what: ObjToInsert} – inserts ObjToInsert. If where property is a number, object is inserted into this index. Sparse arrays are not supported, so {where:1e6} inserts row at the end of the list.

List of different forms

Sometimes data array consists of different-typed items that require different manifests to render. To allow runtime selection, manifest property of a control section can contain a function. It receives each data item during runtime and must return suitable manifest.

Property stamp or equivalent is required to differentiate items. 

Dynamic lists functionality allows to build very complex ensembles of applications.

Identifying child forms

Control section, describing list of child forms, may have id and/or hash properties. Each can be a function, a string or an array of strings.

id function receives item and it’s index as arguments and must return unique item’s id. When id is a string, it’s assumed to be a pointer inside child form’s data object. If an array – list of pointers (values are concatenated).

hash function receives same args, but must return unique hash, that changes when any significant item’s property is changed. In general if hash of child form’s data changed, the form is redrawn. 

When no id or hash defined, sdbm code hash function from BerkeleyDB codebase is used.

Merging new data

If list‘s underlying array with data is modified externally, list must be rebuilt. There are two strategies of combining new and old (already rendered) data:

  • kill all forms with old data and re-init new child forms,
  • try to extend already existing forms if their data rows just slightly changed.

Ui section for a list can have property merge, with values true, false of function (oldObj, newObj){ }

Property omitted or false value turns on standard behavior – if new object received, new form is always created and this form is bound to new object.

If merge:true, new data is overlapped over old if row was already rendered. Overlapping is like deep merge, exept arrays, that are taken from new obj entirely.

If a function given, it must modify oldObj, that is 1st arg, using data from newObj

Inherit and expose sections

Sections inherit and expose manage what properties will manifest inherit from callee or root, or expose to child attached.

Property expose restricts properties, that can be inherited by childs from current form. If no expose defined, child forms can inherit any property of parent’s runtime.

Property inherit defines, what properties must be inherited form parent.

Both properties can be comma-separated strings or arrays of strings.

Require section

The require property of a manifest defines external resources to load before form starts, and also local plugins required for a form to run.

The section is an array of groups, and each group is processed after previous one finished successfully. If any of required presence checks fail after all requests, the form throws and init promise is rejected.

xxxxxxxxxx
 
<!-- Put HTML code here -->
x
 
({
  require:[
    // First group
    {
      // Checks if select2 plugin is absent –
      // in which case global window.$.fn.select2 is undefined –
      // and loads script necessery
      "$.fn.select2": "http://some.url/select2.js",
      
      // Same here, but we r looking for the manifest property Dict,
      // and if it is missing we load json
      // with extended request params defined
      "this.Dict" :{
        url: "http://some.url/some.json",
        dataType: "json"
      }
    },
    
    // Second group, executed after all 
    // resources of the first group are loaded
    {
      // some keys with urls as values
    }
  ],
  init: function(){ /* ... */ },
  ui:{ /* ... */ }
})
xxxxxxxxxx
 
/* Container for CSS code */

All these checks and preloads are executed before any other form’s function run.

Inlined resources

$.my allows to include binary resources into manifest as base64-encoded strings. Section files of a manifest is a container for them. 

All entries of the files section are processed during form start and each obtain local session URL. Files become accessible from <img src= or in links. 

After form’s start session URLs are accessible as this.files["fname.ext"].url from inside of any function.

files section has structure very similar to CouchDB’s _attachments section of a document. 

Settings

App instance params

There are several runtime settings, that has global defaults, but can be overridden using params property of a manifest.

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
var manifest = { 
  data:    { /* data section */ },
  ui:      { /* ui section */ },
  init:   function ( $form ){ /* init */ },
  // Manifest settings
  params:  { 
    container:function ($control) {/**/}, // Container getter, returns $ obj
    change: function ($form){},           // Change handler
    recalcDepth:  2,                      // Depth of dependencies resolver tree
    delay:        0,                      // Delay of bind invocation, ms
    strict:       false,                  // If true form assumed unjsonned
    errorTip:     '.my-error-tip',        // $ selector of err tip container
    errorCss:     'my-error',             // Class applied to container on err
    pendingCss:   'my-form-pending',      // Class applied when form starts
    remember:     0,                      // Undo steps to remember
    historyDelay: 100,                    // Min history steps gap, ms
    restyle:      -1,                     // Custom styles recalc delay on window.resize
    locale:       'en'                    // Locale for l10n using .lang dict
  }
}
xxxxxxxxxx
 
/* Container for CSS code */

Both recalcDepth and delay properties can be also set for a particular selector in the ui section.

Localization

Each manifest can have lang section, that must be i18n dictionary of below structure:

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
({
  // en section must always be present
  // and must always have all necessery keys 
  en:{
    TITLE_PLC: 'Input title...',
    TITLE_ERR: 'A-Z and numbers'
  },
  // other sections may have incomplete
  // set of keys
  ru:{
    TITLE_PLC: 'Введите название...'
  }
})
xxxxxxxxxx
 
/* Container for CSS code */

During form start, appropriate dict branch is taken and merged with lang section itself. So all app functions can access constants in a manner like this.lang.LANG_CONST. Source locale branches are not removed, so all lang constants also accessible directly using this.lang.en.LANG_CONST syntax.

Default locale can be set using $.my.locale('lang') globally or using params.locale property for local override.

If no particular locale present in lang section, or some locale constants are omitted, en section is taken (entirely or partially). It means lang.en section must always be present and complete, if lang present.

External commands

Syntax is $obj.my("cmd", argument). $obj expected to be jQuery object that is a form instance or a control inside a form.

Form commands

Form is manageable during runtime using form command $('#runningForm').my('command', arg). Available commands are:

$form.my("data")

$form.my("data") returns link to live data object.

$form.my("data", object) deep merges object with form data, and then redraws the form.

$form.my("disabled")

Disables/enables form or returns current state. $form.my("disabled", true) marks all controls as inactive – form come inactive. $form.my("disabled") returns false if form is in active state.

$form.my("valid")

If all form’s controls are valid, returns true, else – false.

$form.my("errors")

Returns {} if all controls are valid, or {"#selector":"Error message", ...} with all invalid selectors as keys and related error messages as values. 

$form.my("manifest")

Returns runtime instance of app manifest.

$form.my("redraw")

Redraws the form. 

$form.my("restyle")

Recalculates dynamic CSS rules for form and its childs.

$form.my("remove")

Removes the form. Unbinds all event listeners and removes all plugin instances attached. Returns form’s data.

$form.my("undo")

$form.my("undo", steps) rolls the form several steps back. To use this feature params.history property of a manifest must be 1+ – no undo steps are remembered by default. 

$form.my()

Returns jQuery data object "my", mounted on DOM node, is equivalent to $form.data("my"). Properties of an object returned:

  • cid unique form instance id
  • mid unique manifest id hash
  • data points to form’s data object
  • id manifest id, if it had any, or autogenerated id
  • initial initial data object deep clone
  • manifest form manifest
  • params full list of form instance’s settings
  • ui internal extended ui section

Control’s commands

 Not recommended. Using control‘s commands from inside running manifest‘s functions is not recommended. In those cases better use this.my[command](args) syntax introduced in 1.2.0 instead.

Syntax – $ctrl.my("command", arg). Available commands are:

$ctrl.my("container")

Returns jQuery object of DOM container of a control.

$ctrl.my("find")

$ctrl.my("find", "#selector") searches #selector inside the form.

$ctrl.my("insert")

$ctrl.my("insert", where, what ), if applied inside list item, inserts object what at where position of the list. To insert at the end – where:1e12.

$ctrl.my("remove")

If applied inside list item – removes it form the list.

$ctrl.my("val")

Returns control’s value.

$control.my()

Returns data object "my" of the control. Properties are:

  • data points to data object of the form
  • errors points to error list of the form
  • events, string, list of events tracked
  • id manifest id
  • params form settings
  • root jQuery object of the form
  • selector control’s jQuery selector
  • ui control section.

Form delivery, caching and merge

Manifests are single objects without loop references and are more or less scope independent. A manifest almost completely defines form’s facade and behavior so delivering a manifest you deliver an app. 

Manifest as JSON

If regexps and functions are represented as strings a manifest become valid JSON. jQuery.my has service function $.my.tojson (obj), it converts objects with functions and regexps into JSON. This approach is not unique, functions are represented as JSON strings in CouchDB design documents for example. 

$.my.tojson( {x: function () {}} ) >> '{"x": "function (){}"}'

Converting functions into strings we surely loose all scope info, however functions of a manifest are assumed to be scope independent in general.

Another utility function $.my.fromjson( extJsonString ) converts extended JSON into JS object with all functions and regexps restored from strings to valid executables.

Manifest cache

If a manifest has id property like "ns.Name1.Name2" it can be cached using $.my.cache( manifest ). Cached manifest is available from inside of other forms by string reference like manifest: "ns.Name1.Name2". References are resolved on form init.

The id prop of a cacheable manifest must be string of latins in dot notation. It must have at least two parts an contain no spaces. So for above example the ns part is a namespace string, and Name1.Name2 .... NameN tail is an unique form name.

Use $.my.cache( formId ) to get a clone of cached manifest. 

Combining manifests

The id prop is a reference in dot notation. It points to the branch of cache the manifest is put into. 

When we first cache manifest of  id:"app.Name", and then manifest of id:"app.Name.Component", the former one receives new Component property object which is the latter manifest.

If we then call $.my.cache( "app.Name" ) we get app.Name manifest having  app.Name.Component add-on mounted into Component property

Pub/sub radio

$.my app instances and their controls can both emit messages and listen to pub/sub channels. Pub/sub technique is good for broadcasting events, that may have out-of-app impact. For example, our app loaded a lot of data and notify neighbors, that cache is updated and they are to rebuild item lists.

There are two modes of radio – global broadcast and realm-based broadcast. Listeners for both of them are identical – a control must have listen property in ui section with channels control is subscribed to.

Difference is how radio event is submitted and propagated.

Realm-based radio

When radio packet is submitted using $ctrl.trigger("radio", {channel:"chName", msg:message}), transmission packet bubbles until it reach:

  • Any $.my form, that has radio section with event’s channel name, or
  • <body> DOM node.

If one of two is reached, event reflects and propages down to all children listeners. So if an app wants a radio channel to stay inside the app, the manifest must have radio property with that particular channel listed.

Global radio

There is another way to broadcast – $.my.radio("chName", message). This command sends message to every channel subscriber across web page regardless if it’s screened with radio of a parent manifest or not.

Utility functions

The plugin exports several service functions. They are:

$.my.version()

Returns jquerymy version like "1.3.4"

$.my.locale( null or string )

Gets / sets locale. By default initial locale value is taken from the leading part of browser locale (mean en-GB and en-US both set $.my internal locale to en).

$.my.tojson( obj, separator, maxChars)

Converts JS object into json. Unlike JSON.stringify accepts functions and regexps. If provided maxChars collapses long arrays and key ladders into compact strings.

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
var obj = {
  fn: function plusOne(e){return e+1},
  re: /xy?/g,
  ar: [1,2,3,4,5,6],
  ob:{nest:{more:0}}
};
$.my.tojson(obj, ' ', 30);
// returns string like
// {
//  "fn": "function plusOne(e) {return e+1}", 
//  "re": "new RegExp(/xy?/g)", 
//  "ar": [1, 2, 3, 4, 5, 6], 
//  "ob": {"nest": {"more": 0}}
// }
xxxxxxxxxx
 
/* Container for CSS code */

$.my.fromjson( string )

Parse extJSON string and returns object, with functions and regexps if any.

$.my.ajax( obj or fn )

Execs ajax request if obj is passed. If function is passed replaces internal ajax implemetation ($.ajax by default) with external function.

Returns promise.

$.my.f.mask( obj, mask )

Select object properties by mask. Mask is an object, string reference or an array of references.

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
$.my.f.mask( {a:{b:1, c:2, d:{ e:3 }}}, 'a.d.e' )         // 3
$.my.f.mask( {a:{b:1, c:2, d:{ e:3 }}}, ['a.d', 'a.b'] )  // [{e:3}, 1]
$.my.f.mask( {a:{b:1, c:2, d:{ e:3 }}}, {a:{c:true}} )    // {a:{ c:2 }}
xxxxxxxxxx
 
/* Container for CSS code */

In no property exist, undefined is returned.

$.my.f.unmask( obj, mask ) 

Unfolds masked object into original.

xxxxxxxxxx
 
<!-- Put HTML code here -->
xxxxxxxxxx
 
// Two arguments
$.my.f.unmask( [{e:3}, 1], ["a.d", "a.b"] )         
  // returns {a:{b:1, d:{ e:3 }}}
$.my.f.unmask( ["","",""], ["a.b.c","e.f","e.h"] )   
  // returns {a:{b:{c:""}}, e:{f:"", h:""}}
// Three arguments
var obj = {a:[5]};
$.my.f.unmask (obj, [6,7], ["a.1", "c.d"]);
  // Returns mutated obj, that is now
  // {a:[5,6], c:{d:7}}
xxxxxxxxxx
 
/* Container for CSS code */

$.my.f.sdbmCode( any )

Simple sdbm hash function, from Berkeley ndb. Non-cryptographic and though blazing fast.

$.my.f.css2json( string )

Converts plain text CSS ruleset into object structured as style manifest property.

Modal dialog

jQuery.my plugin includes promise-based modal and non-blocking (popup) dialog implementation. Dialog can be $.my form, simple HTML or jQuery image.

Global modal is a singletone and blocks all other inputs. A global modal dialog once open blocks other global modals’ attempts to init until closed.

Non-global popup dialogs are good for in-place pop-ups with info or settings for example. They are non-blocking.

$pivot.modal( obj , done )  » promise

Opens or closes modal. Both done done and promise can handle dialog close. Unlike promise, done can cancel popup close request. Promise is resolved or rejected on modal close.

Note, that since 1.2.6 $obj.modal does not conflict with Bootstrap implementation when Bootstrap was initialized before $.my. BT and $.my calls are distinguishable by argumants provided, so if arguments looks suitable for BT, BT.modal is invoked.

$pivot object can be $.my control or just DOM node inside $.my form: when parent form is removed all linked dialogs are cold-closed. $pivot geometry and position are used to align non-modal dialogs.

One $pivot object can have only one linked and opened dialog at a time. If $pivot.data("modal") returns object, $pivot already have an attached dialog.

Global blocking modal can be initialized calling $.my.modal(obj). This syntax opens global modal not bound to any form.

First argument:

Object Opens modal and renders $.my form inside. Properties:

  • manifest form manifest
  • data form data, mutated by dialog on user input
  • root jQuery object to hold modal’s DOM. Default is control’s container or parent form.
  • width dialog inside content width
  • esc allows ‘cold’ close on Esc pressed – promise is rejected with string Cancelled. Default is false for non-modals and true for blocking modals.
  • enter allows ‘warm’ close on Enter, default is false
  • nose string, defines where dialog tip is placed – allowed positions are  "left""right""top""bottom"
  • align string, determines modal position relative to pivot, like top:103%;left:0px; that means modal, that is 103% of pivot height shifted from top and zero pixels from left of the pivot
  • global boolean, true opens global blocking dialog
  • screen boolean or string with CSS-compatible color. Defines if blocking screen div must be shown under dialog
  • focus auto-focuses first control in the form after init, default is true.
  • drag allows dragging the dialog if jQuery UI Draggable plugin is loaded. 
  • bound Number, distance in pixels between modal and it’s root obj, default is false, that is no bounds
  • hardClose Boolean, defines X close button behavior, if true, closing is cold, if false closing is warm and can be stopped by .done function
  • done – function (formErrors, formValue), allows or denies warm close, this inside the function points to modal form‘s manifest.
Promise returned is resolved with form’s data if modal was ‘warm’ closed.

Boolean Close dialog. Modal close has two scenarios – cold and warm. 

Warm close request  $.my.modal(false) can be cancelled. The done(null or err, data) function which is called just before close, can return true to keep modal. 

Cold close request $.my.modal(true) invokes done (null, null) and regardless of value returned rejects promise with "Cancelled" value.

jQuery image Image passed pops up with max available width, if no width received.

HTML string  HTML content for modal.

$.my.modal.visible() » boolean

Returns true if global modal is visible.

$.my.modal.parent( selector or null ) » jQuery object

Sets or gets DOM container that will hold modal dialog itself and underlying screen. Default is "body".



© 2024 ermouth, license – MIT