From 13b84f7e6c324a35b536397c82504a23eb7eee0c Mon Sep 17 00:00:00 2001 From: Keegan Date: Wed, 27 Jan 2016 00:03:07 -0800 Subject: [PATCH] Refactor structure to be more testable --- dev/config.js | 8 +- dev/custom-fn.js | 18 +- src/scripts/config-page.js | 152 +- src/scripts/lib/api-item.js | 88 + src/scripts/lib/api.js | 95 + src/scripts/lib/items/color.js | 16 +- src/scripts/lib/items/footer.js | 5 +- src/scripts/lib/items/heading.js | 6 +- src/scripts/lib/items/input.js | 6 +- src/scripts/lib/items/radiogroup.js | 6 +- src/scripts/lib/items/select.js | 4 + src/scripts/lib/items/submit.js | 5 +- src/scripts/lib/items/text.js | 5 +- src/scripts/lib/items/toggle.js | 5 +- src/scripts/lib/manipulators.js | 6 +- src/scripts/vendor/minified/minified.js | 131 +- src/scripts/vendor/minified/minified.min.js | 2923 ------------------- src/styles/items/_color.scss | 5 + src/templates/items/color.tpl | 2 +- 19 files changed, 391 insertions(+), 3095 deletions(-) create mode 100644 src/scripts/lib/api-item.js create mode 100644 src/scripts/lib/api.js delete mode 100644 src/scripts/vendor/minified/minified.min.js diff --git a/dev/config.js b/dev/config.js index 8585034..592bc7a 100644 --- a/dev/config.js +++ b/dev/config.js @@ -22,7 +22,7 @@ module.exports = [ }, { "type": "input", - "app_key": "email", + "appKey": "email", "value": "", "label": "Email", "attributes": { @@ -34,13 +34,13 @@ module.exports = [ }, { "type": "toggle", - "app_key": "like_stuff", + "appKey": "cool_stuff", "label": "Enable Cool Stuff", "value": false }, { "type": "color", - "app_key": "background", + "appKey": "background", "value": "0xFF0000", "label": "Background Color" } @@ -56,7 +56,7 @@ module.exports = [ { "id": "flavor", "type": "select", - "app_key": "flavor", + "appKey": "flavor", "value": "grape", "label": "Favorite Flavor", "options": [ diff --git a/dev/custom-fn.js b/dev/custom-fn.js index a65dfb0..1af6daa 100644 --- a/dev/custom-fn.js +++ b/dev/custom-fn.js @@ -1,15 +1,15 @@ 'use strict'; module.exports = function() { - var Api = window.Clay = this; + var Clay = this; - var testHandler = function() { - console.debug('KEEGAN: this', this); - console.debug('KEEGAN: arguments', arguments); -// Api.getItemByAppKey('background').off(testHandler); - }; + Clay.getItemByAppKey('cool_stuff').on('change', function() { + if (this.get()) { + Clay.getItemByAppKey('background').enable(); + } else { + Clay.getItemByAppKey('background').disable(); + } + }); - Api.getItemByAppKey('background').on('change', testHandler); - - console.debug('custom fn worked'); + Clay.getSettings(); }; diff --git a/src/scripts/config-page.js b/src/scripts/config-page.js index 21a7541..4358734 100755 --- a/src/scripts/config-page.js +++ b/src/scripts/config-page.js @@ -1,28 +1,16 @@ 'use strict'; -/** - * A Clay config Item - * @typedef {object} Clay~Item - * @property {string} type - * @property {string} app_key - * @property {string} id - * @property {string} content - * @property {string|boolean} default - * @property {string} label - * @property {object} attributes - * @property {Array} options - * @property {Array} items - */ - -var itemTypes = require('./lib/items'); var $ = require('./vendor/minified/minified').$; var _ = require('./vendor/minified/minified')._; -var HTML = require('./vendor/minified/minified').HTML; - +var Api = require('./lib/api'); var config = _.extend([], window.clayConfig || []); + var settings = _.extend({}, window.claySettings || {}); var returnTo = window.returnTo || 'pebblejs://close#'; -var customFn = window.customFn; +var customFn = window.customFn || function() {}; + +var api = new Api(settings); +var $mainForm = $('#main-form'); function submit(event) { _.each(api.itemsByAppKey, function(appKey, item) { @@ -34,132 +22,8 @@ function submit(event) { return false; } -/** - * - * @param {string} key - * @param {string|boolean} defaultValue - * @return {string|boolean} - */ -function getSetting(key, defaultValue) { - return typeof settings[key] !== 'undefined' ? settings[key] : (defaultValue || ''); -} +api.addItem(config, $mainForm); -// function setSetting(key, value) { -// settings[key] = value; -// } +//$mainForm.on('submit', submit); -/** - * @param {Clay~Item|Array} item - * @param {$} $parent - */ -function processConfigItem(item, $parent) { - // @todo add validation on the Item - - if (Array.isArray(item)) { - item.forEach(function(item) { - processConfigItem(item, $parent); - }); - } else if (item.type === 'section') { - var $container = HTML('
'); - $parent.add($container); - processConfigItem(item.items, $container); - } else { - var apiItem = {}; - var itemType = itemTypes[item.type]; - var templateData = { - label: '', - options: [], - attributes: {}, - size: 4 - }; - - _.extend(templateData, item); - apiItem.$element = HTML(_.formatHtml(itemType.template, templateData)); - apiItem.$manipulatorTarget = - apiItem.$element.select('[data-manipulator-target]'); - - // this caters for situations where the manipulator target is the root element - if (!apiItem.$manipulatorTarget.length) { - apiItem.$manipulatorTarget = apiItem.$element; - } - - // proxy event related methods - var eventProxies = {}; - apiItem.on = function(events, handler) { - eventProxies[handler] = function() { - handler.apply(apiItem, arguments); - }; - return apiItem.$manipulatorTarget.on(events, eventProxies[handler]); - }; - apiItem.one = function(events, handler) { - eventProxies[handler] = function(event) { - handler.apply(apiItem, arguments); - $.off(eventProxies[handler]); - }; - return apiItem.$manipulatorTarget.on(events, eventProxies[handler]); - }; - apiItem.off = function(handler) { - return $.off(eventProxies[handler]); - }; - - apiItem.trigger = - apiItem.$manipulatorTarget.trigger.bind(apiItem.$manipulatorTarget); - - // attach the manipulator methods to the apiItem - _.eachObj(itemType.manipulator, function(methodName, method) { - apiItem[methodName] = method.bind(apiItem); - }); - - apiItem.config = item; - - // attach the initialize method to the API. - apiItem.iniialize = typeof itemType.initialize === 'function' ? - itemType.initialize : - function() {}; - apiItem.iniialize.bind(apiItem); - apiItem.iniialize(); - - // set the value of the item via the manipulator to ensure consistency - apiItem.set(getSetting(item.app_key, item.value)); - - if (item.id) { - api.itemsById[item.id] = apiItem; - } - - if (item.app_key) { - api.itemsByAppKey[item.app_key] = apiItem; - } - - api.items.push(apiItem); - - $parent.add(apiItem.$element); - } -} - -var api = { - items: [], - itemsById: {}, - itemsByAppKey: {} -}; - -var $mainForm = $('#main-form'); - -api.getItemByAppKey = function(key) { - return api.itemsByAppKey[key]; -}; - -api.getItemById = function(key) { - return api.itemsById[key]; -}; - -api.getItemsByType = function(type) { - return api.items.filter(function(item) { - return item.config.type === type; - }); -}; - -processConfigItem(config, $mainForm); -$mainForm.on('submit', submit); - -module.exports = api; customFn.call(api); diff --git a/src/scripts/lib/api-item.js b/src/scripts/lib/api-item.js new file mode 100644 index 0000000..483a3ac --- /dev/null +++ b/src/scripts/lib/api-item.js @@ -0,0 +1,88 @@ +'use strict'; + +var itemTypes = require('./items'); +var $ = require('../vendor/minified/minified').$; +var _ = require('../vendor/minified/minified')._; +var HTML = require('../vendor/minified/minified').HTML; + +function ApiItem(config) { + var self = this; + + var eventProxies = {}; + var itemType = itemTypes[config.type]; + var templateData = _.extend({}, itemType.defaults, config); + + var $element = HTML(_.formatHtml(itemType.template, templateData)); + var $manipulatorTarget = $element.select('[data-manipulator-target]'); + + // this caters for situations where the manipulator target is the root element + if (!$manipulatorTarget.length) { + $manipulatorTarget = $element; + } + + Object.defineProperties(self, { + id: { + value: config.id || null + }, + + appKey: { + value: config.appKey || null + }, + + config: { + value: config || null + }, + + $element: { + value: $element + }, + + $manipulatorTarget: { + value: $manipulatorTarget + }, + + on: { + value: function(events, handler) { + eventProxies[handler] = function() { + handler.apply(self, arguments); + }; + return $manipulatorTarget.on(events, eventProxies[handler]); + } + }, + + one: { + value: function(events, handler) { + eventProxies[handler] = function(event) { + handler.apply(self, arguments); + $.off(eventProxies[handler]); + }; + return $manipulatorTarget.on(events, eventProxies[handler]); + } + }, + + off: { + value: function(handler) { + return $.off(eventProxies[handler]); + } + }, + + trigger: { + value: $manipulatorTarget.trigger.bind($manipulatorTarget) + }, + + initialize: { + value: typeof itemType.initialize === 'function' ? + itemType.initialize.bind(self) : + function() {} + } + }); + + // attach the manipulator methods to the apiItem + _.eachObj(itemType.manipulator, function(methodName, method) { + Object.defineProperty(self, methodName, { value: method.bind(self) }); + }); + + self.initialize(); +} + +module.exports = ApiItem; diff --git a/src/scripts/lib/api.js b/src/scripts/lib/api.js new file mode 100644 index 0000000..2e8c600 --- /dev/null +++ b/src/scripts/lib/api.js @@ -0,0 +1,95 @@ +'use strict'; + +/** + * A Clay config Item + * @typedef {object} Clay~Item + * @property {string} type + * @property {string} appKey + * @property {string} id + * @property {string} content + * @property {string|boolean} default + * @property {string} label + * @property {object} attributes + * @property {Array} options + * @property {Array} items + */ + +var HTML = require('../vendor/minified/minified').HTML; +var _ = require('../vendor/minified/minified')._; +var ApiItem = require('./api-item'); + +function Api(settings) { + var self = this; + var _items = []; + var _itemsById = {}; + var _itemsByAppKey = {}; + var _settings = _.copyObj(settings); + + Object.defineProperties(self, { + getItemByAppKey: { + value: function(key) { + return _itemsByAppKey[key]; + } + }, + + getItemById: { + value: function(key) { + return _itemsById[key]; + } + }, + + getItemsByType: { + value: function(type) { + return _items.filter(function(item) { + return item.config.type === type; + }); + } + }, + + getSettings: { + value: function() { + _.eachObj(_itemsByAppKey, function(appKey, item) { + _settings[appKey] = item.get(); + }); + return _settings; + } + }, + + addItem: { + value: function(item, $container) { + if (Array.isArray(item)) { + item.forEach(function(item) { + self.addItem(item, $container); + }); + } else if (item.type === 'section') { + var $wrapper = HTML('
'); + $container.add($wrapper); + self.addItem(item.items, $wrapper); + } else { + var apiItem = new ApiItem(item); + + if (item.id) { + _itemsById[item.id] = apiItem; + } + + if (item.appKey) { + _itemsByAppKey[item.appKey] = apiItem; + } + + _items.push(apiItem); + + // set the value of the item via the manipulator to ensure consistency + var value = typeof _settings[item.appKey] !== 'undefined' ? + _settings[item.appKey] : + (item.value || ''); + + apiItem.set(value); + + $container.add(apiItem.$element); + } + } + } + }); +} + +module.exports = Api; diff --git a/src/scripts/lib/items/color.js b/src/scripts/lib/items/color.js index fcc2253..2036761 100644 --- a/src/scripts/lib/items/color.js +++ b/src/scripts/lib/items/color.js @@ -5,6 +5,9 @@ var HTML = require('../../vendor/minified/minified').HTML; module.exports = { template: require('../../../templates/items/color.tpl'), manipulator: require('../manipulators').val, + defaults: { + label: '' + }, initialize: function() { var self = this; @@ -72,9 +75,12 @@ module.exports = { var $valueDisplay = $elem.select('.value'); var $picker = $elem.select('.picker-wrap'); + var disabled = self.$manipulatorTarget.get('disabled'); $elem.on('click', function(ev) { - $picker.set('show'); + if (!disabled) { + $picker.set('show'); + } }); self.on('|change', function() { @@ -89,5 +95,13 @@ module.exports = { $picker.set('-show'); }); + self.on('disabled', function() { + disabled = true; + }); + + self.on('enabled', function() { + disabled = false; + }); + } }; diff --git a/src/scripts/lib/items/footer.js b/src/scripts/lib/items/footer.js index 4313443..b817ff7 100644 --- a/src/scripts/lib/items/footer.js +++ b/src/scripts/lib/items/footer.js @@ -2,5 +2,8 @@ module.exports = { template: require('../../../templates/items/footer.tpl'), - manipulator: require('../manipulators').html + manipulator: require('../manipulators').html, + defaults: { + attributes: {} + } }; diff --git a/src/scripts/lib/items/heading.js b/src/scripts/lib/items/heading.js index 37d72e8..509fa08 100644 --- a/src/scripts/lib/items/heading.js +++ b/src/scripts/lib/items/heading.js @@ -2,5 +2,9 @@ module.exports = { template: require('../../../templates/items/heading.tpl'), - manipulator: require('../manipulators').html + manipulator: require('../manipulators').html, + defaults: { + attributes: {}, + size: 4 + } }; diff --git a/src/scripts/lib/items/input.js b/src/scripts/lib/items/input.js index c6c0fad..5371090 100644 --- a/src/scripts/lib/items/input.js +++ b/src/scripts/lib/items/input.js @@ -2,5 +2,9 @@ module.exports = { template: require('../../../templates/items/input.tpl'), - manipulator: require('../manipulators').val + manipulator: require('../manipulators').val, + defaults: { + label: '', + attributes: {} + } }; diff --git a/src/scripts/lib/items/radiogroup.js b/src/scripts/lib/items/radiogroup.js index f581230..cd4eebe 100644 --- a/src/scripts/lib/items/radiogroup.js +++ b/src/scripts/lib/items/radiogroup.js @@ -2,5 +2,9 @@ module.exports = { template: require('../../../templates/items/radiogroup.tpl'), - manipulator: require('../manipulators').radiogroup + manipulator: require('../manipulators').radiogroup, + defaults: { + label: '', + options: [] + } }; diff --git a/src/scripts/lib/items/select.js b/src/scripts/lib/items/select.js index 0863ba7..70a277d 100644 --- a/src/scripts/lib/items/select.js +++ b/src/scripts/lib/items/select.js @@ -3,6 +3,10 @@ module.exports = { template: require('../../../templates/items/select.tpl'), manipulator: require('../manipulators').val, + defaults: { + label: '', + options: [] + }, initialize: function() { var self = this; diff --git a/src/scripts/lib/items/submit.js b/src/scripts/lib/items/submit.js index 3082c23..2fdfd6b 100644 --- a/src/scripts/lib/items/submit.js +++ b/src/scripts/lib/items/submit.js @@ -2,5 +2,8 @@ module.exports = { template: require('../../../templates/items/submit.tpl'), - manipulator: require('../manipulators').val + manipulator: require('../manipulators').val, + defaults: { + attributes: {} + } }; diff --git a/src/scripts/lib/items/text.js b/src/scripts/lib/items/text.js index 65efa34..07c64f0 100644 --- a/src/scripts/lib/items/text.js +++ b/src/scripts/lib/items/text.js @@ -2,5 +2,8 @@ module.exports = { template: require('../../../templates/items/text.tpl'), - manipulator: require('../manipulators').html + manipulator: require('../manipulators').html, + defaults: { + attributes: {} + } }; diff --git a/src/scripts/lib/items/toggle.js b/src/scripts/lib/items/toggle.js index 6c33742..345bfaf 100644 --- a/src/scripts/lib/items/toggle.js +++ b/src/scripts/lib/items/toggle.js @@ -2,5 +2,8 @@ module.exports = { template: require('../../../templates/items/toggle.tpl'), - manipulator: require('../manipulators').checked + manipulator: require('../manipulators').checked, + defaults: { + attributes: {} + } }; diff --git a/src/scripts/lib/manipulators.js b/src/scripts/lib/manipulators.js index fd7b6f6..62a4ede 100755 --- a/src/scripts/lib/manipulators.js +++ b/src/scripts/lib/manipulators.js @@ -19,10 +19,12 @@ module.exports = { .trigger('change'); }, disable: function() { - return this.$manipulatorTarget.set('disabled', true); + return this.$manipulatorTarget.set('disabled', true) + .trigger('disabled'); }, enable: function() { - return this.$manipulatorTarget.set('disabled', false); + return this.$manipulatorTarget.set('disabled', false) + .trigger('enabled'); } }, checked: { diff --git a/src/scripts/vendor/minified/minified.js b/src/scripts/vendor/minified/minified.js index 114a125..261d22b 100644 --- a/src/scripts/vendor/minified/minified.js +++ b/src/scripts/vendor/minified/minified.js @@ -1,8 +1,8 @@ // minified.js config start -- use this comment to re-create a configuration in the Builder -// - Only sections add, always, amdsupport, dollardollar, each, -// - eachobj, error, extend, filter, find, format, formathtml, get, html, isobject, -// - map, mapobj, off, on, ready, request, select, set, template, trigger, -// - underscore, wait. +// - Only sections add, always, amdsupport, copyobj, dollardollar, +// - each, eachobj, error, extend, filter, filterobj, find, format, formathtml, +// - get, ht, html, isobject, keys, map, mapobj, objvalues, off, on, ready, +// - request, select, set, template, trigger, underscore, wait. // WARNING! This file is autogenerated from minified-master.js and others. @@ -2741,6 +2741,89 @@ define('minified', function() { 'find': find, // @condend + /*$ + * @id keys + * @group OBJECT + * @requires + * @configurable default + * @name _.keys() + * @syntax _.keys(obj) + * @module UTIL + * Creates a ##list#Minified list## containing all property names of the specified object. Only direct properies are + * included, not inherited ones. The order of the keys in the list is undefined and runtime-specific. + * + * @example Using keys(): + *
var obj = {a: 2, b: 52};
+     * var keys = _.keys(obj);  // keys contains ['a', 'b'] now
+     * 
+ * + * @param object The object to gather keys from. + * @return A Minified list containing the property names. + * + * @see ##_.values() returns the values of an object as a list. + */ + 'keys': funcArrayBind(keys), + + /*$ + * @id objvalues + * @group OBJECT + * @requires + * @configurable default + * @name _.values() + * @syntax _.values(obj) + * @module UTIL + * Creates a ##list#Minified list## containing all property values of the specified object. Only direct properies are + * included, not inherited ones. The order of the values in the list is undefined and runtime-specific. + * + * @example Using values(): + *
var obj = {a: 2, b: 52};
+     * var values = _.values(obj);  // keys contains [2, 52] now
+     * 
+ * + * @param object The object to gather values from. + * @return A Minified list containing the property names. + * + * @see ##_.keys() retrieves the property names of an object as a list. + */ + 'values': funcArrayBind(function(obj, keys) { + var list = []; + if (keys) + each(keys, function(value) { list.push(obj[value]); }); + else + eachObj(obj, function(key, value) { list.push(value); }); + return list; + }), + + /*$ + * @id copyobj + * @group OBJECT + * @requires + * @configurable default + * @name _.copyObj() + * @syntax _.copyObj(from) + * @syntax _.copyObj(from, to) + * @module UTIL + * Copies every property of the first object into the second object. The properties are copied as shallow-copies. + * + * @example Copying properties: + *
var target = {a:3, c: 3};
+     * _.copyObj({a: 1, b: 2}, target); // target is now {a: 1, b: 2, c: 3}
+ * + * @example Inline property merge: + *
var target = _.copyObj({a: 1, b: 2}, {a:3, c: 3}); // target is now {a: 1, b: 2, c: 3}
+ * + * @example Duplicating an object: + *
var target = _.copyObj({a: 1, b: 2}); // target is now {a: 1, b: 2}
+ * + * @param from the object to copy from + * @param to optional the object to copy to. If not given, a new object will be created. + * @return the object that has been copied to + * + * @see ##_.extend() is very similar to copyObj(), but with a slightly different syntax. + * @see ##_.merge() copies a list of objects into a new object. + */ + 'copyObj': copyObj, + /*$ * @id extend * @group OBJECT @@ -2848,6 +2931,46 @@ define('minified', function() { return result; }, + /*$ + * @id filterobj + * @group OBJECT + * @requires + * @configurable default + * @name _.filterObj() + * @syntax _.filterObj(obj, filterFunc) + * @syntax _.filterObj(obj, filterFunc, ctx) + * @module UTIL + * Creates a new object that contains only those properties of the input object that have been approved by the filter function. + * + * If the callback function returns true, the property and its value are shallow-copied in the new object, otherwise it will be removed. + * + * @example Removing all values over 10 from an object: + *
+     * var list = _.filterObj({a: 4, b: 22, c: 7, d: 2, e: 19}, function(key, value) {
+     *     return value <= 10;
+     * });
+     * 
+ * + * @param obj the object to use + * @param callback The callback function(key, value) to invoke for each property. + *
key
The name of the current property.
+ *
value
The value of the current property.
+ *
this
The given context. If not set, the object itself.
+ *
(callback return value)
true to include the property in the new object, false to omit it.
+ * @param ctx optional a context to pass to the callback as 'this'. + * @return the new object + * + * @see ##_.mapObj() can be used to modify the values og an object. + */ + 'filterObj': function(obj, f, ctx) { + var r = {}; + eachObj(obj, function(key, value) { + if (f.call(ctx || obj, key, value)) + r[key] = value; + }); + return r; + }, + /*$ * @id isobject * @group TYPE diff --git a/src/scripts/vendor/minified/minified.min.js b/src/scripts/vendor/minified/minified.min.js deleted file mode 100644 index 584fc53..0000000 --- a/src/scripts/vendor/minified/minified.min.js +++ /dev/null @@ -1,2923 +0,0 @@ -// minified.js config start -- use this comment to re-create a configuration in the Builder -// - Only sections add, always, amdsupport, each, error, extend, -// - filter, find, map, on, ready, request, template, trigger, underscore, wait. - - -// WARNING! This file is autogenerated from minified-master.js and others. - -/* - * Minified.js - Lightweight Client-Side JavaScript Library (full package) - * Version: Version 2014 beta 5 b2 - * - * Public Domain. Use, modify and distribute it any way you like. No attribution required. - * To the extent possible under law, Tim Jansen has waived all copyright and related or neighboring rights to Minified. - * Please see http://creativecommons.org/publicdomain/zero/1.0/. - * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - * - * Contains code based on https://github.com/douglascrockford/JSON-js (also Public Domain). - * - * https://github.com/timjansen/minified.js - */ -// ==ClosureCompiler== -// @output_file_name minified.js -// @compilation_level ADVANCED_OPTIMIZATIONS -// ==/ClosureCompiler== - -/*$ - * @id ALL - * @doc no - * @required - * This id allows identifying whether both Web and Util are available. - */ - -///#snippet commonAmdStart - -/*$ - * @id require - * @name require() - * @syntax require(name) - * @group OPTIONS - * @module WEB, UTIL - * Returns a reference to a module. If you do not use an AMD loader to load Minified, just call require() with the - * argument 'minified' to get a reference to Minified. You can also access all modules defined using ##define(). - * - * If you do use an AMD loader, Minified will not define this function and you can use the AMD loader to obtain the - * reference to Minified. - * Minified's version of require is very simple and will only support Minified and other libraries designed - * for Minfied, but no real AMD libraries. If you need to work with libraries requiring AMD, you need a real AMD loader. - * - * @param name the name of the module to request. Minified is available as 'minified'. - * @return the reference to the module. Use the name 'minified' to get Minified. You can also access any modules defined using - * ##define(). If the name is unknown, it returns undefined. - * - * @see ##define() allows you to define modules that can be obtained using require(). - */ - -/*$ - * @id define - * @name define() - * @syntax define(name, factoryFunction) - * @group OPTIONS - * @module WEB, UTIL - * Defines a module that can be returned by ##require(), in case you don't have a AMD loader. If you have a AMD loader before you include Minified, - * define() will not be set and you can use the AMD loader's (more powerful) variant. - * - * Minified's versions of require() and define() are very simple and can not resolve things like circular references. - * Also, they are not AMD-compatible and only useful for simple modules. If you need to work with real AMD libraries that are not written - * for Minified, you need a real AMD loader. - * - * @example Creates a simple module and uses it: - *
- * define('makeGreen', function(require) {
- *     var MINI = require('minified'), $ = MINI.$; // obtain own ref to Minified
- *     return function(list) {
- *         $(list).set({$color: '#0f0', $backgroundColor: '#050'});
- *     });
- * });
- *
- * var makeGreen = require('makeGreen');
- * makeGreen('.notGreenEnough');
- * 
- * - * @param name the name of the module to request. In Minified's implementation, only 'minified' is supported. - * @param factoryFunction is a function(require) will be called the first time the name is defined to obtain the module - * reference. It received a reference to ##require() (which is required for AMD backward-compatibility) and - * must return the value that is returned by ##require(). The function will only be called once, its result will - * be cached. - *
require
A reference to ##require(). While you could use require() from the global - * context, this would prevent backward compatibility with AMD.
- *
(callback return value)
The reference to be returned by ##require().
- * - * @see ##require() can be used to obtain references defined with ##define(). - */ - -/*$ - * @id amdsupport - * @name AMD stubs - * @configurable default - * @group OPTIONS - * @doc no - * @module WEB, UTIL - * If enabled, Minified will create stubs so you can use it without an AMD framework. - * It requires AMD's define() function. - */ -if (/^u/.test(typeof define)) { // no AMD support available ? define a minimal version - (function(def){ - var require = this['require'] = function(name) { return def[name]; }; - this['define'] = function(name, f) { def[name] = def[name] || f(require); }; - })({}); -} -/*$ - * @stop - */ - -define('minified', function() { - - ///#/snippet commonAmdStart - ///#snippet webVars - /*$ - * @id WEB - * @doc no - * @required - * This id allows identifying whether the Web module is available. - */ - - /** - * @const - */ - var _window = window; - - /** - * @const - * @type {!string} - */ - var MINIFIED_MAGIC_NODEID = 'Nia'; - - /** - * @const - * @type {!string} - */ - var MINIFIED_MAGIC_PREV = 'NiaP'; - - var setter = {}, getter = {}; - - var idSequence = 1; // used as node id to identify nodes, and as general id for other maps - - - /*$ - * @id ready_vars - * @dependency - */ - /** @type {!Array.} */ - var DOMREADY_HANDLER = /^[ic]/.test(document['readyState']) ? _null : []; // check for 'interactive' and 'complete' - /*$ - * @stop - */ - - ///#/snippet webVars - ///#snippet utilVars - /*$ - * @id UTIL - * @doc no - * @required - * This id allows identifying whether the Util module is available. - */ - - var _null = null; - - /** @const */ - var undef; - - /*$ - * @id date_constants - * @dependency - */ - function val3(v) {return v.substr(0,3);} - var MONTH_LONG_NAMES = split('January,February,March,April,May,June,July,August,September,October,November,December', /,/g); - var MONTH_SHORT_NAMES = map(MONTH_LONG_NAMES, val3); // ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; - var WEEK_LONG_NAMES = split('Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday', /,/g); - var WEEK_SHORT_NAMES = map(WEEK_LONG_NAMES, val3); - var MERIDIAN_NAMES = split('am,pm', /,/g); - var MERIDIAN_NAMES_FULL = split('am,am,am,am,am,am,am,am,am,am,am,am,pm,pm,pm,pm,pm,pm,pm,pm,pm,pm,pm,pm', /,/g); - - var FORMAT_DATE_MAP = { - 'y': ['FullYear', nonOp], - 'Y': ['FullYear', function(d) { return d % 100; }], - 'M': ['Month', plusOne], - 'n': ['Month', MONTH_SHORT_NAMES], - 'N': ['Month', MONTH_LONG_NAMES], - 'd': ['Date', nonOp], - 'm': ['Minutes', nonOp], - 'H': ['Hours', nonOp], - 'h': ['Hours', function(d) { return (d % 12) || 12; }], - 'k': ['Hours', plusOne], - 'K': ['Hours', function(d) { return d % 12; }], - 's': ['Seconds', nonOp], - 'S': ['Milliseconds', nonOp], - 'a': ['Hours', MERIDIAN_NAMES_FULL], - 'w': ['Day', WEEK_SHORT_NAMES], - 'W': ['Day', WEEK_LONG_NAMES], - 'z': ['TimezoneOffset', function(d, dummy, timezone) { - if (timezone) - return timezone; - - var sign = d > 0 ? '-' : '+'; - var off = d < 0 ? -d : d; - return sign + pad(2, Math.floor(off/60)) + pad(2, off%60); - }] - }; - - var PARSE_DATE_MAP = { - 'y': 0, // placeholder -> ctorIndex - 'Y': [0, -2000], - 'M': [1,1], // placeholder -> [ctorIndex, offset|value array] - 'n': [1, MONTH_SHORT_NAMES], - 'N': [1, MONTH_LONG_NAMES], - 'd': 2, - 'm': 4, - 'H': 3, - 'h': 3, - 'K': [3,1], - 'k': [3,1], - 's': 5, - 'S': 6, - 'a': [3, MERIDIAN_NAMES] - }; - - /*$ - * @stop - */ - - /** @const */ - var MAX_CACHED_TEMPLATES = 99; - var templateCache={}; // template -> function - var templates = []; // list of MAX_CACHED_TEMPLATES templates - - ///#/snippet utilVars - ///#snippet commonFunctions - - /** @param s {?} */ - function toString(s) { - return s!=_null ? ''+s : ''; - } - /** - * @param s {?} - * @param o {string} - */ - function isType(s,o) { - return typeof s == o; - } - /** @param s {?} */ - function isString(s) { - return isType(s, 'string'); - } - function isObject(f) { - return !!f && isType(f, 'object'); - } - function isNode(n) { - return n && n['nodeType']; - } - function isNumber(n) { - return isType(n, 'number'); - } - function isDate(n) { - return isObject(n) && !!n['getDay']; - } - function isBool(n) { - return n === true || n === false; - } - function isValue(n) { - var type = typeof n; - return type == 'object' ? !!(n && n['getDay']) : (type == 'string' || type == 'number' || isBool(n)); - } - function nonOp(v) { - return v; - } - function plusOne(d) { - return d+1; - } - function replace(s, regexp, sub) { - return toString(s).replace(regexp, sub != _null ? sub : ''); - } - function escapeRegExp(s) { - return replace(s, /[\\\[\]\/{}()*+?.$|^-]/g, "\\$&"); - } - function trim(s) { - return replace(s, /^\s+|\s+$/g); - } - function eachObj(obj, cb, ctx) { - for (var n in obj) - if (obj.hasOwnProperty(n)) - cb.call(ctx || obj, n, obj[n]); - return obj; - } - function each(list, cb, ctx) { - if (list) - for (var i = 0; i < list.length; i++) - cb.call(ctx || list, list[i], i); - return list; - } - function filter(list, filterFuncOrObject, ctx) { - var r = []; - var f = isFunction(filterFuncOrObject) ? filterFuncOrObject : function(value) { return filterFuncOrObject != value; }; - each(list, function(value, index) { - if (f.call(ctx || list, value, index)) - r.push(value); - }); - return r; - } - function collector(iterator, obj, collectFunc, ctx) { - var result = []; - iterator(obj, function (a, b) { - if (isList(a = collectFunc.call(ctx || obj, a, b))) // extreme variable reusing: a is now the callback result - each(a, function(rr) { result.push(rr); }); - else if (a != _null) - result.push(a); - }); - return result; - } - function collectObj(obj, collectFunc, ctx) { - return collector(eachObj, obj, collectFunc, ctx); - } - function collect(list, collectFunc, ctx) { - return collector(each, list, collectFunc, ctx); - } - function keyCount(obj) { - var c = 0; - eachObj(obj, function(key) { c++; }); - return c; - } - function keys(obj) { // use Object.keys? in IE>=9 - var list = []; - eachObj(obj, function(key) { list.push(key); }); - return list; - } - function map(list, mapFunc, ctx) { - var result = []; - each(list, function(item, index) { - result.push(mapFunc.call(ctx || list, item, index)); - }); - return result; - } - function startsWith(base, start) { - if (isList(base)) { - var s2 = _(start); // convert start as we don't know whether it is a list yet - return equals(sub(base, 0, s2.length), s2); - } - else - return start != _null && base.substr(0, start.length) == start; - } - function endsWith(base, end) { - if (isList(base)) { - var e2 = _(end); - return equals(sub(base, -e2.length), e2) || !e2.length; - } - else - return end != _null && base.substr(base.length - end.length) == end; - } - function reverse(list) { - var len = list.length; - if (isList(list)) - return new M(map(list, function() { return list[--len]; })); - else - return replace(list, /[\s\S]/g, function() { return list.charAt(--len); }); - } - function toObject(list, value) { - var obj = {}; - each(list, function(item, index) { - obj[item] = value; - }); - return obj; - } - function copyObj(from, to) { - var dest = to || {}; - for (var name in from) - dest[name] = from[name]; - return dest; - } - function merge(list, target) { - var o = target; - for (var i = 0; i < list.length; i++) - o = copyObj(list[i], o); - return o; - } - function getFindFunc(findFunc) { - return isFunction(findFunc) ? findFunc : function(obj, index) { if (findFunc === obj) return index; }; - } - function getFindIndex(list, index, defaultIndex) { - return index == _null ? defaultIndex : index < 0 ? Math.max(list.length+index, 0) : Math.min(list.length, index); - } - function find(list, findFunc, startIndex, endIndex) { - var f = getFindFunc(findFunc); - var e = getFindIndex(list, endIndex, list.length); - var r; - for (var i = getFindIndex(list, startIndex, 0); i < e; i++) - if ((r = f.call(list, list[i], i)) != _null) - return r; - } - function findLast(list, findFunc, startIndex, endIndex) { - var f = getFindFunc(findFunc); - var e = getFindIndex(list, endIndex, -1); - var r; - for (var i = getFindIndex(list, startIndex, list.length-1); i > e; i--) - if ((r = f.call(list, list[i], i)) != _null) - return r; - } - function sub(list, startIndex, endIndex) { - var r = []; - if (list) { - var e = getFindIndex(list, endIndex, list.length); - for (var i = getFindIndex(list, startIndex, 0); i < e; i++) - r.push(list[i]); - } - return r; - } - function array(list) { - return map(list, nonOp); - } - function unite(list) { - return function() { - return new M(callList(list, arguments)); - }; - } - function uniq(list) { - var found = {}; - return filter(list, function(item) { - if (found[item]) - return false; - else - return found[item] = 1; - }); - } - function intersection(list, otherList) { - var keys = toObject(otherList, 1); - return filter(list, function(item) { - var r = keys[item]; - keys[item] = 0; - return r; - }); - } - function contains(list, value) { // TODO: can Array.indexOf be used in >IE8? - for (var i = 0; i < list.length; i++) - if (list[i] == value) - return true; - return false; - } - // equals if a and b have the same elements and all are equal. Supports getters. - function equals(x, y) { - var a = isFunction(x) ? x() : x; - var b = isFunction(y) ? y() : y; - var aKeys; - if (a == b) - return true; - else if (a == _null || b == _null) - return false; - else if (isValue(a) || isValue(b)) - return isDate(a) && isDate(b) && +a==+b; - else if (isList(a)) { - return (a.length == b.length) && - !find(a, function(val, index) { - if (!equals(val, b[index])) - return true; - }); - } - else { - return !isList(b) && - ((aKeys = keys(a)).length == keyCount(b)) && - !find(aKeys, function(key) { - if (!equals(a[key],b[key])) - return true; - }); - } - } - - function call(f, fThisOrArgs, args) { - if (isFunction(f)) - return f.apply(args && fThisOrArgs, map(args || fThisOrArgs, nonOp)); - } - function callList(list, fThisOrArgs, args) { - return map(list, function(f) { return call(f, fThisOrArgs, args);}); - } - function bind(f, fThis, beforeArgs, afterArgs) { - return function() { - return call(f, fThis, collect([beforeArgs, arguments, afterArgs], nonOp)); - }; - } - function partial(f, beforeArgs, afterArgs) { - return bind(f, this, beforeArgs, afterArgs); - } - function pad(digits, number) { - var signed = number < 0 ? '-' : ''; - var preDecimal = (signed?-number:number).toFixed(0); - while (preDecimal.length < digits) - preDecimal = '0' + preDecimal; - return signed + preDecimal; - } - - function processNumCharTemplate(tpl, input, fwd) { - var inHash; - var inputPos = 0; - var rInput = fwd ? input : reverse(input); - var s = (fwd ? tpl : reverse(tpl)).replace(/./g, function(tplChar) { - if (tplChar == '0') { - inHash = false; - return rInput.charAt(inputPos++) || '0'; - } - else if (tplChar == '#') { - inHash = true; - return rInput.charAt(inputPos++) || ''; - } - else - return inHash && !rInput.charAt(inputPos) ? '' : tplChar; - }); - return fwd ? s : (input.substr(0, input.length - inputPos) + reverse(s)); - } - - function getTimezone(match, idx, refDate) { // internal helper, see below - if (idx == _null || !match) - return 0; - return parseFloat(match[idx]+match[idx+1])*60 + parseFloat(match[idx]+match[idx+2]) + refDate.getTimezoneOffset(); - } - - // formats number with format string (e.g. "#.000", "#,#", "00000", "000.00", "000.000.000,00", "000,000,000.##") - // choice syntax: :|:|... - // e.g. 0:no item|1:one item|>=2:# items - // ="null" used to compare with nulls. - // choice also works with strings or bools, e.g. ERR:error|WAR:warning|FAT:fatal|ok - function formatValue(fmt, value) { - var format = replace(fmt, /^\?/); - if (isDate(value)) { - var timezone, match; - - if (match = /^\[(([+-])(\d\d)(\d\d))\]\s*(.*)/.exec(format)) { - timezone = match[1]; - value = dateAdd(value, 'minutes', getTimezone(match, 2, value)); - format = match[5]; - } - - return replace(format, /(\w)(\1*)(?:\[([^\]]+)\])?/g, function(s, placeholderChar, placeholderDigits, params) { - var val = FORMAT_DATE_MAP[placeholderChar]; - if (val) { - var d = value['get' + val[0]](); - var optionArray = (params && params.split(',')); - - if (isList(val[1])) - d = (optionArray || val[1])[d]; - else - d = val[1](d, optionArray, timezone); - if (d != _null && !isString(d)) - d = pad(placeholderDigits.length+1, d); - return d; - } - else - return s; - }); - - } - else - return find(format.split(/\s*\|\s*/), function(fmtPart) { - var match, numFmtOrResult; - if (match = /^([<>]?)(=?)([^:]*?)\s*:\s*(.*)$/.exec(fmtPart)) { - var cmpVal1 = value, cmpVal2 = +(match[3]); - if (isNaN(cmpVal2) || !isNumber(cmpVal1)) { - cmpVal1 = (cmpVal1==_null) ? "null" : toString(cmpVal1); // not ""+value, because undefined is treated as null here - cmpVal2 = match[3]; - } - if (match[1]) { - if ((!match[2] && cmpVal1 == cmpVal2 ) || - (match[1] == '<' && cmpVal1 > cmpVal2) || - (match[1] == '>' && cmpVal1 < cmpVal2)) - return _null; - } - else if (cmpVal1 != cmpVal2) - return _null; - numFmtOrResult = match[4]; - } - else - numFmtOrResult = fmtPart; - - if (isNumber(value)) - return numFmtOrResult.replace(/[0#](.*[0#])?/, function(numFmt) { - var decimalFmt = /^([^.]+)(\.)([^.]+)$/.exec(numFmt) || /^([^,]+)(,)([^,]+)$/.exec(numFmt); - var signed = value < 0 ? '-' : ''; - var numData = /(\d+)(\.(\d+))?/.exec((signed?-value:value).toFixed(decimalFmt ? decimalFmt[3].length:0)); - var preDecimalFmt = decimalFmt ? decimalFmt[1] : numFmt; - var postDecimal = decimalFmt ? processNumCharTemplate(decimalFmt[3], replace(numData[3], /0+$/), true) : ''; - - return (signed ? '-' : '') + - (preDecimalFmt == '#' ? numData[1] : processNumCharTemplate(preDecimalFmt, numData[1])) + - (postDecimal.length ? decimalFmt[2] : '') + - postDecimal; - }); - else - return numFmtOrResult; - }); - } - // returns date; null if optional and not set; undefined if parsing failed - function parseDate(fmt, date) { - var indexMap = {}; // contains reGroupPosition -> typeLetter or [typeLetter, value array] - var reIndex = 1; - var timezoneOffsetMatch; - var timezoneIndex; - var match; - - var format = replace(fmt, /^\?/); - if (format!=fmt && !trim(date)) - return _null; - - if (match = /^\[([+-])(\d\d)(\d\d)\]\s*(.*)/.exec(format)) { - timezoneOffsetMatch = match; - format = match[4]; - } - - var parser = new RegExp(format.replace(/(.)(\1*)(?:\[([^\]]*)\])?/g, function(wholeMatch, placeholderChar, placeholderDigits, param) { - if (/[dmhkyhs]/i.test(placeholderChar)) { - indexMap[reIndex++] = placeholderChar; - var plen = placeholderDigits.length+1; - return "(\\d"+(plen<2?"+":("{1,"+plen+"}"))+")"; - } - else if (placeholderChar == 'z') { - timezoneIndex = reIndex; - reIndex += 3; - return "([+-])(\\d\\d)(\\d\\d)"; - } - else if (/[Nna]/.test(placeholderChar)) { - indexMap[reIndex++] = [placeholderChar, param && param.split(',')]; - return "([a-zA-Z\\u0080-\\u1fff]+)"; - } - else if (/w/i.test(placeholderChar)) - return "[a-zA-Z\\u0080-\\u1fff]+"; - else if (/\s/.test(placeholderChar)) - return "\\s+"; - else - return escapeRegExp(wholeMatch); - })); - - if (!(match = parser.exec(date))) - return undef; - - var ctorArgs = [0, 0, 0, 0, 0, 0, 0]; - for (var i = 1; i < reIndex; i++) { - var matchVal = match[i]; - var indexEntry = indexMap[i]; - if (isList(indexEntry)) { // for a, n or N - var placeholderChar = indexEntry[0]; - var mapEntry = PARSE_DATE_MAP[placeholderChar]; - var ctorIndex = mapEntry[0]; - var valList = indexEntry[1] || mapEntry[1]; - var listValue = find(valList, function(v, index) { if (startsWith(matchVal.toLowerCase(), v.toLowerCase())) return index; }); - if (listValue == _null) - return undef; - if (placeholderChar == 'a') - ctorArgs[ctorIndex] += listValue * 12; - else - ctorArgs[ctorIndex] = listValue; - } - else if (indexEntry) { // for numeric values (yHmMs) - var value = parseFloat(matchVal); - var mapEntry = PARSE_DATE_MAP[indexEntry]; - if (isList(mapEntry)) - ctorArgs[mapEntry[0]] += value - mapEntry[1]; - else - ctorArgs[mapEntry] += value; - } - } - var d = new Date(ctorArgs[0], ctorArgs[1], ctorArgs[2], ctorArgs[3], ctorArgs[4], ctorArgs[5], ctorArgs[6]); - return dateAdd(d, 'minutes', -getTimezone(timezoneOffsetMatch, 1, d) - getTimezone(match, timezoneIndex, d)); - } - // format ?##00,00## - // returns number; null if optional and not set; undefined if parsing failed - function parseNumber(fmt, value) { - var format = replace(fmt, /^\?/); - if (format!=fmt && !trim(value)) - return _null; - var decSep = (/(^|[^0#.,])(,|[0#.]*,[0#]+|[0#]+\.[0#]+\.[0#.,]*)($|[^0#.,])/.test(format)) ? ',' : '.'; - var r = parseFloat(replace(replace(replace(value, decSep == ',' ? /\./g : /,/g), decSep, '.'), /^[^\d-]*(-?\d)/, '$1')); - return isNaN(r) ? undef : r; - } - function now() { - return new Date(); - } - function dateClone(date) { - return new Date(+date); - } - function capWord(w) { - return w.charAt(0).toUpperCase() + w.substr(1); - } - function dateAddInline(d, cProp, value) { - d['set'+cProp](d['get'+cProp]() + value); - return d; - } - function dateAdd(date, property, value) { - if (value == _null) - return dateAdd(now(), date, property); - return dateAddInline(dateClone(date), capWord(property), value); - } - function dateMidnight(date) { - var od = date || now(); - return new Date(od.getFullYear(), od.getMonth(), od.getDate()); - } - function dateDiff(property, date1, date2) { - var d1t = +date1; - var d2t = +date2; - var dt = d2t - d1t; - if (dt < 0) - return -dateDiff(property, date2, date1); - - var propValues = {'milliseconds': 1, 'seconds': 1000, 'minutes': 60000, 'hours': 3600000}; - var ft = propValues[property]; - if (ft) - return dt / ft; - - var cProp = capWord(property); - var calApproxValues = {'fullYear': 8.64e7*365, 'month': 8.64e7*365/12, 'date': 8.64e7}; // minimum values, a little bit below avg values - var minimumResult = Math.floor((dt / calApproxValues[property])-2); // -2 to remove the imperfections caused by the values above - - var d = dateAddInline(new Date(d1t), cProp, minimumResult); - for (var i = minimumResult; i < minimumResult*1.2+4; i++) { // try out 20% more than needed, just to be sure - if (+dateAddInline(d, cProp, 1) > d2t) - return i; - } - // should never ever be reached - } - - function ucode(a) { - return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - } - - function escapeJavaScriptString(s) { - return replace(s, /[\x00-\x1f'"\u2028\u2029]/g, ucode); - } - - // reimplemented split for IE8 - function split(str, regexp) { - - return str.split(regexp); - } - - function template(template, escapeFunction) { - if (templateCache[template]) - return templateCache[template]; - else { - var funcBody = 'with(_.isObject(obj)?obj:{}){'+ - map(split(template, /{{|}}}?/g), function(chunk, index) { - var match, c1 = trim(chunk), c2 = replace(c1, /^{/), escapeSnippet = (c1==c2) ? 'esc(' : ''; - if (index%2) { // odd means JS code - if (match = /^each\b(\s+([\w_]+(\s*,\s*[\w_]+)?)\s*:)?(.*)/.exec(c2)) - return 'each('+(trim(match[4])?match[4]:'this')+', function('+match[2]+'){'; - else if (match = /^if\b(.*)/.exec(c2)) - return 'if('+match[1]+'){'; - else if (match = /^else\b\s*(if\b(.*))?/.exec(c2)) - return '}else ' + (match[1] ? 'if('+match[2] +')' : '')+'{'; - else if (match = /^\/(if)?/.exec(c2)) - return match[1] ? '}\n' : '});\n'; - else if (match = /^(var\s.*)/.exec(c2)) - return match[1]+';'; - else if (match = /^#(.*)/.exec(c2)) - return match[1]; - else if (match = /(.*)::\s*(.*)/.exec(c2)) - return 'print('+escapeSnippet+'_.formatValue("'+escapeJavaScriptString(match[2])+'",'+(trim(match[1])?match[1]:'this')+(escapeSnippet&&')')+'));\n'; - else - return 'print('+escapeSnippet+(trim(c2)?c2:'this')+(escapeSnippet&&')')+');\n'; - } - else if (chunk){ - return 'print("'+escapeJavaScriptString(chunk)+'");\n'; - } - }).join('')+'}'; - var f = (new Function('obj', 'each', 'esc', 'print', '_', funcBody)); - var t = function(obj, thisContext) { - var result = []; - f.call(thisContext || obj, obj, function(obj, func) { - if (isList(obj)) - each(obj, function(value, index) { func.call(value, value, index); }); - else - eachObj(obj, function(key, value) { func.call(value, key, value); }); - }, escapeFunction || nonOp, function() {call(result['push'], result, arguments);}, _); - return result.join(''); - }; - if (templates.push(t) > MAX_CACHED_TEMPLATES) - delete templateCache[templates.shift()]; - return templateCache[template] = t; - } - } - - function escapeHtml(s) { - return replace(s, /[<>'"&]/g, function(s) { - return '&#'+s.charCodeAt(0)+';'; - }); - } - - function formatHtml(tpl, obj) { - return template(tpl, escapeHtml)(obj); - } - - function listBindArray(func) { - return function(arg1, arg2) { - return new M(func(this, arg1, arg2)); - }; - } - function listBind(func) { - return function(arg1, arg2, arg3) { - return func(this, arg1, arg2, arg3); - }; - } - function funcArrayBind(func) { - return function(arg1, arg2, arg3) { - return new M(func(arg1, arg2, arg3)); - }; - } - - ///#/snippet commonFunctions - ///#snippet webFunctions - - // note: only the web version has the f.item check - function isFunction(f) { - return typeof f == 'function' && !f['item']; // item check as work-around for webkit bug 14547 - } - - function isList(v) { - return v && v.length != _null && !isString(v) && !isNode(v) && !isFunction(v) && v !== _window; - } - - // used by IE impl of on() only - function push(obj, prop, value) { - (obj[prop] = (obj[prop] || [])).push(value); - } - // used by IE impl of on()/off() only - function removeFromArray(array, value) { - for (var i = 0; array && i < array.length; i++) - if (array[i] === value) - array['splice'](i--, 1); - } - - function extractNumber(v) { - return parseFloat(replace(v, /^[^\d-]+/)); - } - - // retrieves the node id of the element, create one if needed. - function getNodeId(el) { - return (el[MINIFIED_MAGIC_NODEID] = (el[MINIFIED_MAGIC_NODEID] || ++idSequence)); - } - - // collect variant that filters out duplicate nodes from the given list, returns a new array - function collectUniqNodes(list, func) { - var result = []; - var nodeIds = {}; - var currentNodeId; - - flexiEach(list, function(value) { - flexiEach(func(value), function(node) { - if (!nodeIds[currentNodeId = getNodeId(node)]) { - result.push(node); - nodeIds[currentNodeId] = true; - } - }); - }); - return result; - } - - // finds out the 'natural' height of the first element, the one if $$slide=1 - function getNaturalHeight(elementList, factor) { - var q = {'$position': 'absolute', '$visibility': 'hidden', '$display': 'block', '$height': _null}; - var oldStyles = elementList['get'](q); - var h = elementList['set'](q)['get']('clientHeight'); - elementList['set'](oldStyles); - return h*factor + 'px'; - } - - - - - // @condblock !ie8compatibility - function on(subSelector, eventSpec, handler, args, bubbleSelector) { - if (isFunction(eventSpec)) - return this['on'](_null, subSelector, eventSpec, handler, args); - else if (isString(args)) - return this['on'](subSelector, eventSpec, handler, _null, args); - else - return this['each'](function(baseElement, index) { - flexiEach(subSelector ? dollarRaw(subSelector, baseElement) : baseElement, function(registeredOn) { - flexiEach(toString(eventSpec).split(/\s/), function(namePrefixed) { - var name = replace(namePrefixed, /[?|]/g); - var prefix = replace(namePrefixed, /[^?|]/g); - var capture = (name == 'blur' || name == 'focus') && !!bubbleSelector; // bubble selectors for 'blur' and 'focus' registered as capuring! - var triggerId = idSequence++; - - // returns true if processing should be continued - function triggerHandler(eventName, event, target) { - var match = !bubbleSelector; - var el = bubbleSelector ? target : registeredOn; - if (bubbleSelector) { - var selectorFilter = getFilterFunc(bubbleSelector, registeredOn); - while (el && el != registeredOn && !(match = selectorFilter(el))) - el = el['parentNode']; - } - return (!match) || (name != eventName) || ((handler.apply($(el), args || [event, index]) && prefix=='?') || prefix == '|'); - }; - - function eventHandler(event) { - if (!triggerHandler(name, event, event['target'])) { - event['preventDefault'](); - event['stopPropagation'](); - } - }; - - registeredOn.addEventListener(name, eventHandler, capture); - - if (!registeredOn['M']) - registeredOn['M'] = {}; - registeredOn['M'][triggerId] = triggerHandler; // to be called by trigger() - - handler['M'] = collector(flexiEach, [handler['M'], function () { // this function will be called by off() - registeredOn.removeEventListener(name, eventHandler, capture); - delete registeredOn['M'][triggerId]; - }], nonOp); - - }); - }); - }); - } - // @condend !ie8compatibility - - - // @condblock !ie8compatibility - function off(handler) { - callList(handler['M']); - handler['M'] = _null; - } - // @condend !ie8compatibility - - // for remove & window.unload, IE only - function detachHandlerList(dummy, handlerList) { - flexiEach(handlerList, function(h) { - h.element.detachEvent('on'+h.eventType, h.handlerFunc); - }); - } - - function ready(handler) { - if (DOMREADY_HANDLER) - DOMREADY_HANDLER.push(handler); - else - setTimeout(handler, 0); - } - - function $$(selector, context, childrenOnly) { - return dollarRaw(selector, context, childrenOnly)[0]; - } - - function EE(elementName, attributes, children) { - var e = $(document.createElement(elementName)); - // @condblock UTIL - // this attributes != null check is only required with Util's isObject() implementation. Web's isObject() is simpler. - return (isList(attributes) || (attributes != _null && !isObject(attributes)) ) ? e['add'](attributes) : e['set'](attributes)['add'](children); - // @condend UTIL - // @cond !UTIL return (isList(attributes) || (!isObject(attributes)) ) ? e['add'](attributes) : e['set'](attributes)['add'](children); - } - - function clone(listOrNode) { - return collector(flexiEach, listOrNode, function(e) { - var c; - if (isList(e)) - return clone(e); - else if (isNode(e)) { - c = e['cloneNode'](true); - c['removeAttribute'] && c['removeAttribute']('id'); - return c; - } - else - return e; - }); - } - - /*$ - * @stop - */ - - function $(selector, context, childOnly) { - // @condblock ready - return isFunction(selector) ? ready(selector) : new M(dollarRaw(selector, context, childOnly)); - // @condend - // @cond !ready return new M(dollarRaw(selector, context)); - } - - // implementation of $ that does not produce a Minified list, but just an array - - - - - - - - - - - // @condblock !ie7compatibility - function dollarRaw(selector, context, childOnly) { - function flatten(a) { // flatten list, keep non-lists, remove nulls - return isList(a) ? collector(flexiEach, a, flatten) : a; - } - function filterElements(list) { // converts into array, makes sure context is respected - return filter(collector(flexiEach, list, flatten), function(node) { - var a = node; - while (a = a['parentNode']) - if (a == context[0] || childOnly) - return a == context[0]; - // fall through to return undef - }); - } - - if (context) { - if ((context = dollarRaw(context)).length != 1) - return collectUniqNodes(context, function(ci) { return dollarRaw(selector, ci, childOnly);}); - else if (isString(selector)) { - if (isNode(context[0]) != 1) - return []; - else - return childOnly ? filterElements(context[0].querySelectorAll(selector)) : context[0].querySelectorAll(selector); - } - else - return filterElements(selector); - - } - else if (isString(selector)) - return document.querySelectorAll(selector); - else - return collector(flexiEach, selector, flatten); - }; - // @condend !ie7compatibility - - // If context is set, live updates will be possible. - // Please note that the context is not evaluated for the '*' and 'tagname.classname' patterns, because context is used only - // by on(), and in on() only nodes in the right context will be checked - function getFilterFunc(selector, context) { - function wordRegExpTester(name, prop) { - var re = RegExp('(^|\\s+)' + name + '(?=$|\\s)', 'i'); - return function(obj) {return name ? re.test(obj[prop]) : true;}; - } - - var nodeSet = {}; - var dotPos = nodeSet; - if (isFunction(selector)) - return selector; - else if (isNumber(selector)) - return function(v, index) { return index == selector; }; - else if (!selector || selector == '*' || - (isString(selector) && (dotPos = /^([\w-]*)\.?([\w-]*)$/.exec(selector)))) { - var nodeNameFilter = wordRegExpTester(dotPos[1], 'tagName'); - var classNameFilter = wordRegExpTester(dotPos[2], 'className'); - return function(v) { - return isNode(v) == 1 && nodeNameFilter(v) && classNameFilter(v); - }; - } - else if (context) - return function(v) { - return $(selector, context)['find'](v)!=_null; // live search instead of node set, for on() - }; - else { - $(selector)['each'](function(node) { - nodeSet[getNodeId(node)] = true; - }); - return function(v) { - return nodeSet[getNodeId(v)]; - }; - } - } - - function getInverseFilterFunc(selector) { - var f = getFilterFunc(selector); - return function(v) {return f(v) ? _null : true;}; - } - ///#/snippet webFunctions - - ///#snippet extrasFunctions - function flexiEach(list, cb) { - if (isList(list)) - each(list, cb); - else if (list != _null) - cb(list, 0); - return list; - } - - function Promise() { - this['state'] = null; - this['values'] = []; - this['parent'] = null; - } - - /*$ - * @id promise - * @name _.promise() - * @syntax _.promise() - * @syntax _.promise(otherPromises...) - * @module WEB+UTIL - * - * Creates a new ##promiseClass#Promise##, optionally assimilating other promises. If no other promise is given, - * a fresh new promise is returned. - * - * The returned promise provides the methods ##fulfill() and ##reject() that can be called directly to change the promise's state, - * as well as the more powerful ##fire(). - * - * If one promise is given as parameter, the new promise assimilates the given promise as-is, and just forwards - * fulfillment and rejection with the original values. - * - * If more than one promise are given, it will assimilate all of them with slightly different rules: - *
  • the new promise is fulfilled if all assimilated promises have been fulfilled. The fulfillment values - * of all assimilated promises are given to the handler as arguments. Note that the fulfillment values themselves are always - * arrays, as a promise can have several fulfillment values in Minified's implementation.
  • - *
  • when one of the promises is rejected, the new promise is rejected immediately. The rejection handler gets the - * promises rejection value (first argument if it got several) as first argument, an array of the result values - * of all promises as a second (that means one array of arguments for each promise), and the index of the failed - * promise as third. - *
- * - * @example A simple promise that is fulfilled after 1 second, using Minified's invocation syntax: - *
var p = _.promise();
-   * setTimeout(function() {
-   *     p.fire(true);
-   * }, 1000);
-   * 
- * - * @example Request three files in parallel. When all three have been downloaded, concatenate them into a single string. - *
-   * var files = _('fileA.txt', 'fileA.txt', 'fileC.txt');
-   * var content;
-   * _.promise(files.map(function(file) {
-   *      return $.request('get', '/txts/' + file);
-   * })).then(function(fileRslt1, fileRslt2, fileRslt3) {
-   *      content = _(fileRslt1, fileRslt2, fileRslt3).map( function(result) { return result[0]; }).join('');
-   * }).error(function(status, response, xhr, url) {
-   *    alert('failed to load file '+url);
-   * });
-   * 
- * - * @param otherPromises one or more promises to assimilate (varargs). You can also pass lists of promises. - * @return the new promise. - */ - function promise() { - var deferred = []; // this function calls the functions supplied by then() - - var assimilatedPromises = arguments; - var assimilatedNum = assimilatedPromises.length; - var numCompleted = 0; // number of completed, assimilated promises - var rejectionHandlerNum = 0; - - var obj = new Promise(); - - obj['errHandled'] = function() { - rejectionHandlerNum++; - if (obj['parent']) - obj['parent']['errHandled'](); - }; - - /*$ - * @id fire - * @name promise.fire() - * @syntax _.fire(newState) - * @syntax _.fire(newState, values) - * @module WEB+UTIL - * - * Changes the state of the promise into either fulfilled or rejected. This will also notify all ##then() handlers. If the promise - * already has a state, the call will be ignored. - * - * fire() can be invoked as a function without context ('this'). Every promise has its own instance. - * - * @example A simple promise that is fulfilled after 1 second, using Minified's invocation syntax: - *
var p = _.promise();
-     * setTimeout(function() {
-     *     p.fire(true, []);
-     * }, 1000);
-     * 
- * - * @example Call fire() without a context: - *
var p = _.promise(function(resolve, reject) {
-     *     setTimeout(resolve.fire, 1000);
-     * });
-     * 
- * - * @param newState true to set the Promise to fulfilled, false to set the state as rejected. If you pass null or - * undefined, the promise's state does not change. - * @param values optional an array of values to pass to ##then() handlers as arguments. You can also pass a non-list argument, which will then - * be passed as only argument. - * @return the promise - */ - var fire = obj['fire'] = function(newState, newValues) { - if (obj['state'] == null && newState != null) { - obj['state'] = !!newState; - obj['values'] = isList(newValues) ? newValues : [newValues]; - setTimeout(function() { - each(deferred, function(f) {f();}); - }, 0); - } - return obj; - }; - - // use promise varargs - each(assimilatedPromises, function assimilate(promise, index) { - try { - if (promise['then']) - promise['then'](function(v) { - var then; - if ((isObject(v) || isFunction(v)) && isFunction(then = v['then'])) - assimilate(v, index); - else { - obj['values'][index] = array(arguments); - if (++numCompleted == assimilatedNum) - fire(true, assimilatedNum < 2 ? obj['values'][index] : obj['values']); - } - }, - function(e) { - obj['values'][index] = array(arguments); - fire(false, assimilatedNum < 2 ? obj['values'][index] : [obj['values'][index][0], obj['values'], index]); - }); - else - promise(function() {fire(true, array(arguments));}, function() {fire(false, array(arguments)); }); - } - catch (e) { - fire(false, [e, obj['values'], index]); - } - }); - - /*$ - * @id stop - * @name promise.stop() - * @syntax promise.stop() - * @module WEB+UTIL - * Stops an ongoing operation, if supported. Currently the only promises supporting this are those returned by ##request(), ##animate(), ##wait() and - * ##asyncEach(). - * stop() invocation will be propagated over promises returned by ##then() and promises assimilated by ##promise(). You only need to invoke stop - * with the last promise, and all dependent promises will automatically stop as well. - * - * stop() can be invoked as a function without context ('this'). Every promise has its own instance. - * - * @return In some cases, the stop() can return a value. This is currently only done by ##animate() and ##wait(), which will return the actual duration. - * ##asyncEach()'s promise will also return any value it got from the promise that it stopped. - * - * @example Animation chain that can be stopped. - *
-     * var div = $('#myMovingDiv').set({$left: '0px', $top: '0px'});
-     * var prom = div.animate({$left: '200px', $top: '0px'}, 600, 0)
-     *    .then(function() {
-     *           return _.promise(div.animate({$left: '200px', $top: '200px'}, 800, 0),
-     *                            div.animate({$backgroundColor: '#f00'}, 200));
-     *    }).then(function() {
-     *           return div.animate({$left: '100px', $top: '100px'}, 400);
-     *    });
-     *
-     * $('#stopButton').on('click', prom.stop);
-     * 
- */ - obj['stop'] = function() { - each(assimilatedPromises, function(promise) { - if (promise['stop']) - promise['stop'](); - }); - - return obj['stop0'] && call(obj['stop0']); - }; - - /*$ - * @id then - * @name promise.then() - * @syntax promise.then() - * @syntax promise.then(onSuccess) - * @syntax promise.then(onSuccess, onError) - * - * @module WEB - * Registers two callbacks that will be invoked when the ##promise#Promise##'s asynchronous operation finished - * successfully (onSuccess) or an error occurred (onError). The callbacks will be called after - * then() returned, from the browser's event loop. - * You can chain then() invocations, as then() returns another Promise object that you can attach to. - * - * The full distribution of Minified implements the Promises/A+ specification, allowing interoperability with other Promises frameworks. - * - * Note: If you use the Web module, you will get a simplified Promises implementation that cuts some corners. The most notable - * difference is that when a then() handler throws an exception, this will not be caught and the promise returned by - * then will not be automatically rejected. - * - * @example Simple handler for an HTTP request. Handles only success and ignores errors. - *
-     * $.request('get', '/weather.html')
-     *     .then(function(txt) {
-     *        alert('Got response!');
-     *     });
-     * 
- * - * @example Including an error handler. - *
-     * $.request('get', '/weather.html')
-     *     .then(function(txt) {
-     *        alert('Got response!');
-     *     }, function(err) {
-     *        alert('Error!');
-     *     }));
-     * 
- * - * @example Chained handler. - *
-     * $.request('get', '/weather.do')
-     *     .then(function(txt) {
-     *        showWeather(txt);
-     *     }
-     *     .then(function() {
-     *        return $.request('get', '/traffic.do');
-     *     }
-     *     .then(function(txt) {
-     *        showTraffic(txt);
-     *     }
-     *     .then(function() {
-     *        alert('All result displayed');
-     *     }, function() {
-     *        alert('An error occurred');
-     *     });
-     * 
- * - * @param onSuccess optional a callback function to be called when the operation has been completed successfully. The exact arguments it receives depend on the operation. - * If the function returns a ##promise#Promise##, that Promise will be evaluated to determine the state of the promise returned by then(). If it returns any other value, the - * returned Promise will also succeed. If the function throws an error, the returned Promise will be in error state. - * Pass null or undefined if you do not need the success handler. - * @param onError optional a callback function to be called when the operation failed. The exact arguments it receives depend on the operation. If the function returns a ##promise#Promise##, that promise will - * be evaluated to determine the state of the Promise returned by then(). If it returns anything else, the returned Promise will - * have success status. If the function throws an error, the returned Promise will be in the error state. - * You can pass null or undefined if you do not need the error handler. - * @return a new ##promise#Promise## object. If you specified a callback for success or error, the new Promises's state will be determined by that callback if it is called. - * If no callback has been provided and the original Promise changes to that state, the new Promise will change to that state as well. - */ - var then = obj['then'] = function (onFulfilled, onRejected) { - var promise2 = promise(); - var callCallbacks = function() { - try { - var f = (obj['state'] ? onFulfilled : onRejected); - if (isFunction(f)) { - (function resolve(x) { - try { - var then, cbCalled = 0; - if ((isObject(x) || isFunction(x)) && isFunction(then = x['then'])) { - if (x === promise2) - throw new TypeError(); - then.call(x, function(x) { if (!cbCalled++) resolve(x); }, function(value) { if (!cbCalled++) promise2['fire'](false, [value]);}); - promise2['stop0'] = x['stop']; - } - else - promise2['fire'](true, [x]); - } - catch(e) { - if (!(cbCalled++)) { - promise2['fire'](false, [e]); - if (!rejectionHandlerNum) - throw e; - } - } - })(call(f, undef, obj['values'])); - } - else - promise2['fire'](obj['state'], obj['values']); - } - catch (e) { - promise2['fire'](false, [e]); - if (!rejectionHandlerNum) - throw e; - } - }; - if (isFunction(onRejected)) - obj['errHandled'](); - promise2['stop0'] = obj['stop']; - promise2['parent'] = obj; - if (obj['state'] != null) - setTimeout(callCallbacks, 0); - else - deferred.push(callCallbacks); - return promise2; - }; - - /*$ - * @id always - * @group REQUEST - * @name promise.always() - * @syntax promise.always(callback) - * @configurable default - * @module WEB+UTIL - * Registers a callback that will always be called when the ##promise#Promise##'s operation ended, no matter whether the operation succeeded or not. - * This is a convenience function that will call ##then() with the same function for both arguments. It shares all of its semantics. - * - * @example Simple handler for a HTTP request. - *
-     * $.request('get', '/weather.html')
-     *     .always(function() {
-     *        alert('Got response or error!');
-     *     });
-     * 
- * - * @param callback a function to be called when the operation has been finished, no matter what its result was. The exact arguments depend on the operation and may - * vary depending on whether it succeeded or not. If the function returns a ##promise#Promise##, that Promise will - * be evaluated to determine the state of the returned Promise. If provided and it returns regularly, the returned promise will - * have success status. If it throws an error, the returned Promise will be in the error state. - * @return a new ##promise#Promise## object. Its state is determined by the callback. - */ - obj['always'] = function(func) { return then(func, func); }; - - /*$ - * @id error - * @group REQUEST - * @name promise.error() - * @syntax promise.error(callback) - * @configurable default - * @module WEB, UTIL - * Registers a callback that will be called when the operation failed. - * This is a convenience function that will invoke ##then() with only the second argument set. It shares all of its semantics. - * - * @example Simple handler for a HTTP request. - *
-     * $.request('get', '/weather.html')
-     *     .error(function() {
-     *        alert('Got error!');
-     *     });
-     * 
- * - * @param callback a function to be called when the operation has failed. The exact arguments depend on the operation. If the function returns a ##promise#Promise##, that Promise will - * be evaluated to determine the state of the returned Promise. If it returns regularly, the returned Promise will - * have success status. If it throws an error, the returned Promise will be in error state. - * @return a new ##promise#Promise## object. Its state is determined by the callback. - */ - obj['error'] = function(func) { return then(0, func); }; - - return obj; - } - - ///#/snippet extrasFunctions - ///#snippet extrasDocs - /*$ - * @id length - * @group SELECTORS - * @requires dollar - * @name list.length - * @syntax length - * @module WEB, UTIL - * - * Contains the number of elements in the ##list#Minified list##. - * - * @example With Web module: - *
-   * var list = $('input');
-   * var myValues = {};
-   * for (var i = 0; i < list.length; i++)
-   *    myValues[list[i].name] = list[i].value;
-   * 
- * - * @example With Util module: - *
-   * var list = _(1, 2, 3);
-   * var sum = 0;
-   * for (var i = 0; i < list.length; i++)
-   *    sum += list[i];
-   * 
- */ - /*$ - * @stop - */ - ///#/snippet extrasDocs - - ///#snippet utilM - - /* - * syntax: M(list, assimilateSublists) - * M(null, singleElement) - * - * - */ - /** @constructor */ - function M(list, assimilateSublists) { - var self = this, idx = 0; - if (list) - for (var i = 0, len = list.length; i < len; i++) { - var item = list[i]; - if (assimilateSublists && isList(item)) - for (var j = 0, len2 = item.length; j < len2; j++) - self[idx++] = item[j]; - else - self[idx++] = item; - } - else - self[idx++] = assimilateSublists; - - self['length'] = idx; - self['_'] = true; - } - - function _() { - return new M(arguments, true); - } - - ///#/snippet utilM - - //// LIST FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - copyObj({ - ///#snippet utilListFuncs - /*$ - * @id each - * @group LIST - * @requires - * @configurable default - * @name .each() - * @altname _.each() - * @syntax list.each(callback) - * @syntax list.each(callback, ctx) - * @syntax _.each(list, callback) - * @syntax _.each(list, callback, ctx) - * @module UTIL, WEB - * Invokes the given function once for each item in the list. The function will be called with the item as first parameter and - * the zero-based index as second. Unlike JavaScript's built-in forEach() it will be invoked for each item in the list, - * even if it is undefined. - * - * @example Creates the sum of all list entries. - *
-     * var sum = 0;
-     * _(17, 4, 22).each(function(item, index) {
-     *     sum += item;
-     * });
-     * 
- * - * @example The previous example with a native array: - *
-     * var sum = 0;
-     * _.each([17, 4, 22], function(item, index) {
-     *     sum += item;
-     * });
-     * 
- * - * @example This goes through all h2 elements of the class 'section' on a web page and changes their content: - *
-     * $('h2.section').each(function(item, index) {
-     *     item.innerHTML = 'Section ' + index + ': ' + item.innerHTML;
-     * });
-     * 
- * - * @param list a list to iterate. Can be an array, a ##list#Minified list## or any other array-like structure with - * length property. - * @param callback The callback function(item, index) to invoke for each list element. - *
item
The current list element.
- *
index
The second the zero-based index of the current element.
- *
this
The given context if not null. Otherwise the list.
- * The callback's return value will be ignored. - * @param ctx optional a context to pass to the callback as 'this'. Only supported in UTIL module. - * @return the list - * - * @see ##per() works like each(), but wraps the list elements in a list. - * @see ##find() can be used instead of each() if you need to abort the loop. - * @see ##eachObj() iterates through the properties of an object. - */ - 'each': listBind(each), - - /*$ - * @id filter - * @group LIST - * @requires - * @configurable default - * @name .filter() - * @altname _.filter() - * @syntax list.filter(filterFunc) - * @syntax list.filter(filterFunc, ctx) - * @syntax list.filter(value) - * @syntax _.filter(list, filterFunc) - * @syntax _.filter(list, filterFunc, ctx) - * @syntax _.filter(list, value) - * @module WEB, UTIL - * Creates a new ##list#Minified list## by taking an existing list and omitting certain elements from it. You - * can either specify a callback function to approve those items that will be in the new list (all modules), or - * you can pass a value to remove from the new list (Util module only). - * - * If the callback function returns true, the item is shallow-copied in the new list, otherwise it will be removed. - * For values, a simple equality operation (==) will be used. - * - * @example Removing all instances of the number 10 from a list: - *
-     * var list = _([4, 10, 22, 7, 2, 19, 10]).filter(10);
-     * 
- * - * @example Removing all numbers over 10 from a list: - *
-     * var list = _([4, 22, 7, 2, 19]).filter(function(item, index) {
-     *     return item <= 10;
-     * });
-     * 
- * - * @example The previous example with a native array is input. Note that the result is always a ##list#Minified list##: - *
-     * var list = _.filter([4, 22, 7, 2, 19], function(item, index) {
-     *     return item <= 10;
-     * });
-     * 
- * - * @example Creates a list of all unchecked checkboxes on a web page: - *
-     * var list = $('input').filter(function(item, index) {
-     *     return item.getAttribute('type') == 'checkbox' && item.checked;
-     * });
-     * 
- * - * @param list a list to filter. A list to use as input. Can be an array, a ##list#Minified list## or any other array-like structure with - * length property. - * @param filterFunc The filter callback function(item, index) that decides which elements to include: - *
item
The current list element.
- *
index
The second the zero-based index of the current element.
- *
this
The given context if not null. Otherwise the list.
- *
(callback return value)
true to include the item in the new list, false to omit it.
- * @param ctx optional a context to pass to the callback as 'this'. Only supported in UTIL module. - * @param value a value to remove from the list. It will be determined which elements to remove using ==. Must not - * be a function. Requires Util module. - * @return the new, filtered ##list#list## - * - * @see ##only() offers selector-based filtering. - */ - 'filter': listBindArray(filter), - - /*$ - * @id map - * @group LIST - * @requires - * @configurable default - * @name .map() - * @altname _.map() - * @syntax list.map(mapFunc) - * @syntax list.map(mapFunc, ctx) - * @syntax _.map(list, mapFunc) - * @syntax _.map(list, mapFunc, ctx) - * @module UTIL - * Creates a new ##list#Minified list## from the current list using the given callback function. - * The callback is invoked once for each element of the current list. The callback results will be added to the result list. - * - * map() is a simpler version of ##collect(). Unlike collect(), it always creates lists of the same size as the input list, but - * it is easier to use if the resulting list should contain nulls or nested list. - * - * @example Goes through a list of numbers and creates a new list with each value increased by 1: - *
-     * var inced = _(3, 7, 11, 5, 19, 3).map(function(number, index) {
-     *     return number + 1;
-     * });
-     * 
- * - * @example The previous example with a native array is input. Note that the result is always a ##list#Minified list##: - *
-     * var inced = _.map([3, 7, 11, 5, 19, 3], function(number, index) {
-     *     return number + 1;
-     * });
-     * 
- * - * @param list a list to transform. Can be an array, a ##list#Minified list## or any other array-like structure with - * length property. - * @param mapFunc The callback function(item, index) to invoke for each item: - *
item
The current list element.
index
The second the zero-based index of the current element.
- *
this
The given context if not null. Otherwise the list.
- *
(callback return value)
This value will replace the original value in the new list.
- * @param ctx optional a context to pass to the callback as 'this'. - * @return the new ##list#list## - * - * @see ##collect() is a more powerful version of map(). - */ - 'map': listBindArray(map), - - /*$ - * @id find - * @group LIST - * @requires - * @configurable default - * @name .find() - * @altname _.find() - * @syntax list.find(findFunc) - * @syntax list.find(element) - * @syntax list.find(findFunc, startIndex) - * @syntax list.find(element, startIndex) - * @syntax _.find(list, findFunc) - * @syntax _.find(list, element) - * @syntax _.find(list, findFunc, startIndex) - * @syntax _.find(list, element, startIndex) - * @module WEB, UTIL - * Finds a specific value in the list. There are two ways of calling find(): - *
    - *
  1. With a value as argument. Then find() will search for the first occurrence of an identical value in the list, - * using the '===' operator for comparisons, and return the index. If it is not found, - * find() returns undefined.
  2. - *
  3. With a callback function. find() will then call the given function for each list element until the function - * returns a value that is not null or undefined. This value will be returned.
  4. - *
- * - * find() can also be used as an alternative to ##each() if you need to abort the loop. - * - * @example Finds the first negative number in the list: - *
-     * var i = _(1, 2, -4, 5, 2, -1).find(function(value, index) { if (value < 0) return index; }); // returns 2
-     * 
- - * @example Finds the index of the first 5 in the array: - *
-     * var i = _.find([3, 6, 7, 6, 5, 4, 5], 5); // returns 4 (index of first 5)
-     * 
- * - * @example Determines the position of the element with the id '#wanted' among all li elements: - *
-     * var elementIndex = $('li').find($$('#wanted'));
-     * 
- * - * @example Goes through the elements to find the first div that has the class 'myClass', and returns this element: - *
-     * var myClassElement = $('div').find(function(e) { if ($(e).is('.myClass')) return e; });
-     * 
- * - * @param list A list to use as input. Can be an array, a ##list#Minified list## or any other array-like structure with - * length property. - * @param findFunc The callback function(item, index) that will be invoked for every list item until it returns a non-null value: - *
item
The current list element.
index
The second the zero-based index of the current element.
- *
this
This list.
- *
(callback return value)
If the callback returns something other than null or - * undefined, find() will return it directly. Otherwise it will continue.
- * @param element the element to search for - * @param startIndex optional the 0-based index of the first element to search. - * @return if called with an element, either the element's index in the list or undefined if not found. If called with a callback function, - * it returns either the value returned by the callback or undefined. - * - * @see ##findLast() is the equivalent to find() for the list's end. - */ - 'find': listBind(find), - - /*$ - * @stop - */ - dummySort:0 - , - ///#/snippet utilListFuncs - ///#snippet webListFuncs - - /*$ - * @id add - * @group ELEMENT - * @requires dollar each - * @configurable default - * @name .add() - * @syntax list.add(text) - * @syntax list.add(node) - * @syntax list.add(list) - * @syntax list.add(factoryFunction) - * @module WEB - * Adds the given node(s) as children to the list's HTML elements. If a string has been given, it will be added as text node. - * DOM nodes will be added directly. If you pass a list, all its elements will be added using the rules above. - * - * When you pass a DOM node and the target list has more than one element, the original node will be added to the first list element, - * and ##clone#clones## to all following list elements. - * - * ##EE(), ##HTML() and ##clone() are compatible with add() and can help you create new HTML nodes. - * - * @example Using the following HTML: - *
-     * <div id="comments">Here is some text.<br/></div>
-     * 
- * The next line appends a text node to the div: - *
-     * $('#comments').add('Some additional text.');
-     * 
- * This results in: - *
-     * <div id="comments">Here is some text.<br/>Some additional text.</div>
-     * 
- * - * @example Using the following HTML: - *
-     * <ul id="myList">
-     *   <li>First list entry</li>
-     *   <li>Second list entry</li>
-     * </ul>
-     * 
- * The following Javascript adds an element to the list: - *
-     * $('#myList').add(EE('li', 'My extra point');
-     * 
- * This results in - *
-     * <ul id="myList">
-     *   <li>First list entry</li>
-     *   <li>Second list entry</li>
-     *   <li>My extra point</li>
-     * </ul>
-     * 
- * - * @example Use a list to add several elements at once: - *
-     * $('#comments').add([
-     *      EE('br'),
-     *     'Some text',
-     *     EE('span', {'className': 'highlight'}, 'Some highlighted text')
-     * ]);
-     * 
- * - * @example If you need to customize the content, you can write a factory function: - *
-     * $('.chapter').add(function(parent, index) { return EE('h2', 'Chapter number ' + index); });
-     * 
- * - * @param text a string or number to add as text node - * @param node a DOM node to add to the list. If the list has more than one element, the given node will be added to the first element. - * For all additional elements, the node will be cloned using ##clone(). - * @param list a list containing text and/or nodes. May also contain nested lists with nodes or text.. - * @param factoryFunction a function(listItem, listIndex) that will be invoked for each list element to create the nodes: - *
listItem
The list element that will receive the new children.
- *
listIndex
The index of the list element that will receive the new children.
- *
(callback return value)
The node(s) to be added to the list element. - * Can be either a string for a text node, an HTML element or a list containing strings and/or DOM nodes. - * If a function is returned, it will be invoked recursively with the same arguments.
- * @return the current list - * - * @see ##fill() works like add(), but deletes all children before adding the new nodes. - * @see ##addFront() adds nodes as first child, not as last. - * @see ##addAfter() adds nodes not as children but as siblings. - * @see ##addBefore() also adds nodes not as children but as siblings. - * @see ##replace() replaces existing nodes. - */ - 'add': function (children, addFunction) { - return this['each'](function(e, index) { - var lastAdded; - function appendChildren(c) { - if (isList(c)) - flexiEach(c, appendChildren); - else if (isFunction(c)) - appendChildren(c(e, index)); - else if (c != _null) { // must check null, as 0 is a valid parameter - var n = isNode(c) ? c : document.createTextNode(c); - if (lastAdded) - lastAdded['parentNode']['insertBefore'](n, lastAdded['nextSibling']); - else if (addFunction) - addFunction(n, e, e['parentNode']); - else - e.appendChild(n); - lastAdded = n; - } - } - appendChildren(index &&!isFunction(children) ? clone(children) : children); - }); - }, - - /*$ - * @id on - * @group EVENTS - * @requires dollar each - * @configurable default - * @name .on() - * @syntax list.on(names, eventHandler) - * @syntax list.on(selector, names, eventHandler) - * @syntax list.on(names, customFunc, args) - * @syntax list.on(selector, names, customFunc, args) - * @syntax list.on(names, eventHandler, bubbleSelector) - * @syntax list.on(names, customFunc, args, bubbleSelector) - * @module WEB - * Registers the function as event handler for all items in the list. - * - * By default, Minified cancels event propagation and disables element's default behavior for all elements that have an event handler. - * You can override this, either by prefixing the event name with a '|', or by prefixing them with '?' and returning a true - * in the handler. Both will reinstate the original JavaScript behavior. - * - * Handlers are called with the original event object as first argument, the index of the source element in the - * list as second argument and 'this' set to the source element of the event (e.g. the button that has been clicked). - * - * Instead of the event objects, you can also pass an array of arguments that will be passed instead of event object and index. - * - * Optionally you can specify two a selector strings to qualify only certain events. The first one is a selector - * that allows you to select only specific children of the list elements. This is mostly useful for adding events to DOM trees - * generated using ##HTML() or ##EE(). - * - * The second type of selector is the bubble selector that allows you to receive only events that bubbled up from - * elements matching the selector. The selector is executed in the context of the element you registered on to identify whether the - * original target of the event qualifies. If not, the handler is not called. - * - * Minified always registers event handlers with event bubbling enabled. Event capture is not supported. - * - * Event handlers can be unregistered using #off#$.off(). - * - * @example Adds a handler to all divs which paints the div background color to red when clicked. - *
-     * $('div').on('click', function() {
-     *    this.style.backgroundColor = 'red';    // 'this' contains the element that caused the event
-     * });
-     * 
- * - * @example Registers a handler to call a method setStatus('running') using an inline function: - *
-     * $('#myButton').on('click', function() {
-     *    setStatus('running');
-     * });
-     * 
- * The previous example can bere written like this, using on()'s args parameter: - *
-     * $('#myButton').on('click', setStatus, ['running']);
-     * 
- * - * @example Adds two handlers on an input field. The event names are prefixed with '|' and thus keep their original behavior: - *
-     * $('#myInput').on('|keypress |keydown', function() {
-     *    // do something
-     * });
-     * 
- * - * @example Adds a click handler that will abort the operation by returning false, unless the user confirms it: - *
-     * $('#myLink').on('?click', function() {
-     *    return window.confirm('Really leave?');
-     * });
-     * 
- * - * @example Adds a button and registers a click handler for it using a sub-selector. - *
-     * $('#myForm').add(HTML("<li><button>click me</button></li>").on('button', 'click', myClickHandler));
-     * 
- * - * @example Adds listeners for all clicks on a table's rows using the bubble selector 'tr'. - *
-     * $('#table').on('change', 'tr', function(event, index, selectedIndex) {
-     *    alert("Click on table row number: " + selectedIndex);
-     * }, 'tr');
-     * 
- * Please note that bubble selectors will even listen to events for - * table rows that have been added after you registered for the events. - * - * @param selector optional a selector string for ##dollar#$()## to register the event only on those children of the list elements that - * match the selector. - * Supports all valid parameters for $() except functions. - * @param names the space-separated names of the events to register for, e.g. 'click'. Case-sensitive. The 'on' prefix in front of - * the name must not used. You can register the handler for more than one event by specifying several - * space-separated event names. If the name is prefixed - * with '|' (pipe), the event will be passed through and the event's default actions will be executed by the browser. - * If the name is prefixed with '?', the event will only be passed through if the handler returns true. - * @param eventHandler the callback function(event, index) to invoke when the event has been triggered: - *
- *
event
The original DOM event object.
- *
index
The index of the target object in the ##list#Minified list## .
- *
this
A ##list#Minified list## containing the target element as only item (same as event.target).
- *
(callback return value)
The return value will only be used if the event name prefix was '?'. - * Then, a return value false will stop all further processing of the event and disable event bubbling. - * true will keep the event alive.
- *
- * @param customFunc a function to be called instead of a regular event handler with the arguments given in args. - * 'this' will be a ##list#Minified list## containing the target element as only item (same element as event.target). - * @param args optional an array of arguments to pass to the custom callback function instead of the event objects. If omitted, the function is - * called as event handler with the event object as argument. - * @param bubbleSelector optional a selector string for ##dollar#$()## to receive only events that bubbled up from an - * element that matches this selector. - * Supports all valid parameters for $() except functions. Analog to ##is(), - * the selector is optimized for the simple patterns '.classname', 'tagname' and 'tagname.classname'. - * @return the list - * @see ##off() allows you to unregister an event handler. - * @see ##onClick() as a shortcut for 'click' events. - * @see ##onOver() to simplify mouseover/mouseout events. - * @see ##onFocus() as convenient way to register for focus events. - * @see ##onChange() to get notified when an input's content changes. - */ - 'on': on, - - /*$ - * @id trigger - * @group EVENTS - * @requires on each - * @configurable default - * @name .trigger() - * @syntax list.trigger(name) - * @syntax list.trigger(name, eventObject) - * @module WEB - * - * Triggers event handlers registered with ##on(). - * Any event that has been previously registered using ##on() can be invoked with trigger(). Please note that - * it will not simulate the default behavior on the elements, such as a form submit when you click on a submit button. Event bubbling - * is supported, thus unless there's an event handler that cancels the event, the event will be triggered on all parent elements. - * - * - * @example Simulates a 'click' event on the button. - *
-     * $('#myButton').trigger('click');
-     * 
- * - * @param name a single event name to trigger - * @param eventObj optional an object to pass to the event handler, provided the handler does not have custom arguments. - * Anything you pass here will be directly given to event handlers as event object, so you need to know what - * they expect. - * @return the list - * @see ##on() registers events that can be triggered. - */ - 'trigger': function (eventName, eventObj) { - return this['each'](function(element, index) { - var bubbleOn = true, el = element; - while(el && bubbleOn) { - eachObj(el['M'], function(id, f) { - bubbleOn = bubbleOn && f(eventName, eventObj, element); - }); - el = el['parentNode']; - } - }); - } - - /*$ - * @stop - */ - // @cond !trigger dummyTrigger:0 - , - ///#/snippet webListFuncs - ///#snippet extrasListFuncs - - /*$ - * @stop - */ - dummyHt:0 - ///#/snippet extrasListFuncs - }, M.prototype); - - //// DOLLAR FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - copyObj({ - ///#snippet webDollarFuncs - /*$ - * @id request - * @group REQUEST - * @requires - * @configurable default - * @name $.request() - * @syntax $.request(method, url) - * @syntax $.request(method, url, data) - * @syntax $.request(method, url, data, settings) - * @module WEB - * Initiates a HTTP request to the given URL, using XMLHttpRequest. It returns a ##promiseClass#Promise## object that allows you to obtain the result. - * - * @example Invokes a REST web service and parses the resulting document using JSON: - *
-     * $.request('get', 'http://service.example.com/weather', {zipcode: 90210})
-     *    .then(function(txt) {
-     *         var json = $.parseJSON(txt);
-     *         $('#weatherResult').fill('Today's forecast is is: ' + json.today.forecast);
-     *    })
-     *    .error(function(status, statusText, responseText) {
-     *         $('#weatherResult').fill('The weather service was not available.');
-     *    });
-     * 
- * - * @example Sending a JSON object to a REST web service: - *
-     * var myRequest = {         // create a request object that can be serialized via JSON
-     *      request: 'register',
-     *      entries: [
-     *        {name: 'Joe',
-     *      	    job: 'Plumber'
-     *        }
-     *      ]};
-     *
-     * function failureHandler() {
-     *   $('#registrationResult').fill('Registration failed');
-     * }
-     *
-     * $.request('post', 'http://service.example.com/directory', $.toJSON(myRequest))
-     *     .then(function(txt) {
-     *        if (txt == 'OK')
-     *             $('#registrationResult').fill('Registration succeeded');
-     *        else
-     *              failureHandler();
-     *        })
-     *     .error(failureHandler);
-     * 
- * - * @example Using HTTP authentication and a custom XMLHttpRequest property. - *
var handler = $.request('get', 'http://service.example.com/userinfo', null, {xhr: {withCredentials: true}, user: 'me', pass: 'secret'});
- * - * - * @param method the HTTP method, e.g. 'get', 'post' or 'head' (rule of thumb: use 'post' for requests that change data - * on the server, and 'get' to request data). Not case sensitive. - * @param url the server URL to request. May be a relative URL (relative to the document) or an absolute URL. Note that unless you do something - * fancy on the server (keyword to google: Access-Control-Allow-Origin), you can only call URLs on the server your script originates from. - * @param data optional data to send in the request, either as POST body or as URL parameters. It can be either a plain object as map of - * parameters (for all HTTP methods), a string (for all HTTP methods), a DOM document ('post' only) or a FormData object ('post' only). - * If the method is 'post', it will be sent as body, otherwise parameters are appended to the URL. In order to send several parameters with the - * same name, use an array of values in the map. Use null as value for a parameter without value. - * @param settings optional a map of additional parameters. Supports the following properties (all optional): - *
headers
a map of HTTP headers to add to the request. Note that you should use the proper capitalization for the - * header 'Content-Type', if you set it, because otherwise it may be overwritten.
- *
xhr
a map of properties to set in the XMLHttpRequest object before the request is sent, for example {withCredentials: true}.
- *
user
username for HTTP authentication, together with the pass parameter
- *
pass
password for HTTP authentication, together with the user parameter
- *
- * @return a ##promiseClass#Promise## containing the request's status. If the request has successfully completed with a HTTP status 2xx, - * the promise's completion handler will be called as function(text, xhr): - *
text
The response sent by the server as text.
- *
xhr
The XMLHttpRequest used for the request. This allows you to retrieve the response in different - * formats (e.g. responseXml for an XML document), to retrieve headers and more.
- * The failure handler will be called as function(statusCode, statusText, text): - *
statusCode
The HTTP status (never 200; 0 if no HTTP request took place).
- *
text
The response's body text, if there was any, or the exception as string if the browser threw one.
- *
xhr
The XMLHttpRequest used for the request. This allows you to retrieve the response in different - * formats (e.g. responseXml for an XML document), to retrieve headers and more..
- * The returned promise supports ##stop(). Calling stop() will invoke the XHR's abort() method. - * The underlying XmlHttpRequest can also be obtained from the promise's xhr property. - * - * @see ##values() serializes an HTML form in a format ready to be sent by $.request. - * @see ##$.parseJSON() can be used to parse JSON responses. - * @see ##$.toJSON() can create JSON messages. - * @see ##_.format() can be useful for creating REST-like URLs, if you use JavaScript's built-in escape() function. - */ - 'request': function (method, url, data, settings0) { - var settings = settings0 || {}; - var xhr, callbackCalled = 0, prom = promise(), dataIsMap = data && (data['constructor'] == settings['constructor']); - try { - prom['xhr'] = xhr = new XMLHttpRequest(); - - prom['stop0'] = function() { xhr['abort'](); }; - // @condend - - if (dataIsMap) { // if data is parameter map... - data = collector(eachObj, data, function processParam(paramName, paramValue) { - return collector(flexiEach, paramValue, function(v) { - return encodeURIComponent(paramName) + ((v != _null) ? '=' + encodeURIComponent(v) : ''); - }); - }).join('&'); - } - - if (data != _null && !/post/i.test(method)) { - url += '?' + data; - data = _null; - } - - xhr['open'](method, url, true, settings['user'], settings['pass']); - if (dataIsMap && /post/i.test(method)) - xhr['setRequestHeader']('Content-Type', 'application/x-www-form-urlencoded'); - - eachObj(settings['headers'], function(hdrName, hdrValue) { - xhr['setRequestHeader'](hdrName, hdrValue); - }); - eachObj(settings['xhr'], function(name, value) { - xhr[name] = value; - }); - - xhr['onreadystatechange'] = function() { - if (xhr['readyState'] == 4 && !callbackCalled++) { - if (xhr['status'] >= 200 && xhr['status'] < 300) - prom['fire'](true, [xhr['responseText'], xhr]); - else - prom['fire'](false, [xhr['status'], xhr['responseText'], xhr]); - } - }; - - xhr['send'](data); - } - catch (e) { - if (!callbackCalled) - prom['fire'](false, [0, _null, toString(e)]); - } - - return prom; - }, - - /* - * JSON Module. Uses browser built-ins or json.org implementation if available. Otherwise its own implementation, - * originally based on public domain implementation http://www.JSON.org/json2.js / http://www.JSON.org/js.html. - * Extremely simplified code, made variables local, removed all side-effects (especially new properties for String, Date and Number). - */ - - /*$ - * @id ready - * @group EVENTS - * @requires ready_vars ready_init - * @configurable default - * @name $.ready() - * @syntax $.ready(handler) - * @module WEB - * Registers a handler to be called as soon as the HTML has been fully loaded in the browser. Does not necessarily wait for images and other elements, - * only the main HTML document needs to be complete. On older browsers it is the same as window.onload. - * - * If you call ready() after the page is completed, the handler is scheduled for invocation in the event loop as soon as possible. - * - * A shortcut for ready() is to call ##dollar#$()## with the handler function. It does the same with fewer characters. - * - * @example Registers a handler that sets some text in an element: - *
-     * $.ready(function() {
-     *   $('#someElement').fill('ready() called');
-     * });
-     * 
- * - * @param handler the function() to be called when the HTML is ready. - * @see ##dollar#$()## calls ready() when invoked with a function, offering a more convenient syntax. - */ - 'ready': ready, - - /*$ - * @stop - */ - dummyOff:null - , - ///#/snippet webDollarFuncs - ///#snippet extrasDollarFuncs - - /*$ - * @id wait - * @group EVENTS - * @configurable default - * @requires promise - * @name $.wait() - * @syntax $.wait() - * @syntax $.wait(durationMs) - * @syntax $.wait(durationMs, args) - * @module WEB+UTIL - * - * Creates a new ##promise#Promise## that will be fulfilled as soon as the specified number of milliseconds have passed. This is mainly useful for animation, - * because it allows you to chain delays into your animation chain. - * - * The operation can be interrupted by calling the promise's ##stop() function. - * - * @example Chained animation using Promise callbacks. The element is first moved to the position 200/0, then to 200/200, waits for 50ms - * and finally moves to 100/100. - *
-     * var div = $('#myMovingDiv').set({$left: '0px', $top: '0px'});
-     * div.animate({$left: '200px', $top: '0px'}, 600, 0)
-     *    .then(function() {
-     *           div.animate({$left: '200px', $top: '200px'}, 800, 0);
-     *    }).then(function() {
-     *    	     return _.wait(50);
-     *    }).then(function() {
-     *           div.animate({$left: '100px', $top: '100px'}, 400);
-     *    });
-     * });
-     * 
- * - * - * @param durationMs optional the number of milliseconds to wait. If omitted, the promise will be fulfilled as soon as the browser can run it - * from the event loop. - * @param args optional an array or list of arguments to pass to the promise handler - * @return a ##promise#Promise## object that will be fulfilled when the time is over, or fail when the promise's ##stop() has been called. - * The promise argument of a fulfilled promise is the args parameter as given to wait(). The returned promise supports ##stop() - * to interrupt the promise. - */ - 'wait': function(durationMs, args) { - var p = promise(); - var id = setTimeout(function() { - p['fire'](true, args); - }, durationMs); - p['stop0'] = function() { p['fire'](false); clearTimeout(id); }; - return p; - } - - /*$ - * @stop - */ - // @cond !wait dummyWait:0 - - ///#/snippet extrasDollarFuncs - }, $); - - //// UNDERSCORE FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - copyObj({ - ///#snippet utilUnderscoreFuncs - // @condblock filter - 'filter': funcArrayBind(filter), - // @condend - // @condblock map - 'map': funcArrayBind(map), - // @condend - // @condblock each - 'each': each, - // @condend - // @condblock each - 'toObject': toObject, - // @condend - // @condblock find - 'find': find, - // @condend - - /*$ - * @id extend - * @group OBJECT - * @requires - * @configurable default - * @name _.extend() - * @syntax _.extend(target, src...) - * @module UTIL - * Copies every property of the source objects into the first object. The source objects are specified using variable arguments. - * There can be more than one. - * The properties are copied as shallow-copies. - * - * Please note: Unlike jQuery, extend does not directly add a function to extend Minified, although - * you can use it to for this. To add a function to ##list#Minified lists##, add a property to - * ##M#MINI.M##. If you want to extend $ or _, just assign the new function(s) as property. - * - * @example Copying properties: - *
var target = {a:3, c: 3};
-     * _.extend(target, {a: 1, b: 2}); // target is now {a: 1, b: 2, c: 3}
- * - * @example Using several source values: - *
var extend = _.extend({a: 1, b: 2}, {a:3, c: 3}, {d: 5}); // target is now {a: 1, b: 2, c: 3, d: 5}
- * - * @param target the object to copy to - * @param src the object(s) to copy from. Variable argument, there can be any number of sources. Nulls and undefined - * parameters will be ignored. - * @return the target - * - * @see ##_.copyObj() is very similar to extend(), but with a slightly different and more straightforward syntax. - * @see ##_.merge() copies a list of objects into a new object. - */ - 'extend': function(target) { - return merge(sub(arguments, 1), target); - }, - - /*$ - * @id template - * @group FORMAT - * @requires date_constants - * @configurable default - * @name _.template() - * @syntax _.template(template) - * @syntax _.template(template, escapeFunction) - * @module UTIL - * Parses a Handlebars-like template to create a reusable template function. - * - * The syntax of the template uses a syntax that superficially looks like - * Handlebars. Unlike Handlebars, it is based on raw JavaScript expressions and thus gives you - * complete freedom, but also offers you shortcuts for formatting, iteration and conditionals. - * - * Every template can receive exactly one object as input. If you need more than one value as input, put all required values - * into an object. - * - * Use double curly braces to embed a JavaScript expression and insert its result: - *
{{a}} plus {{b}} is {{a+b}}
- * - * To use such a template, create it with template() and then execute the resulting function: - *
var myTemplate = _.template('{{a}} plus {{b}} is {{a+b}}');
-     * var result = myTemplate({a: 5, b: 7});
- * If you pass an object as input, its properties will be mapped using JavaScript's with - * statement and are available as variables throughout the template. - * - * If you have only a simple value to render, you can pass it directly and access it through the pre-defined - * variable obj: - *
var myTemplate = _.template('The result is {{obj}}.');
-     * var result = myTemplate(17);
- * Alternatively, you could also access the input as this, but be aware that JavaScript wraps simples types - * such as Number and Boolean. this is the default, so you can omit it to get the same result: - *
var myTemplate = _.template('The result is {{ }}.');
-     * var result = myTemplate(17);
- * - * Minified templates can use ##_.formatValue() formats directly. Just separate them from the expression by - * a double-colon: - *
The price is {{obj::#.00}}.
- * - * Conditions can be expressed using if and else: - *
Hello {{if visits==0}}New{{else if visits<10}}Returning{{else}}Regular{{/if}} Customer.
- * You can use any JavaScript expression as condition. - * - * Use each to iterate through a list: - *
var myTemplate = _.template(
-     * 	   '{{each names}}{{this.firstName}} {{this.lastName}}{{/each}}');
-     * var result = myTemplate({names: [{firstName: 'Joe', lastName: 'Jones'},
-     *                                  {firstName: 'Marc', lastName: 'Meyer'}]});
- * each will iterate through the members of the given object. It - * calls its body for each item and put a reference to the item into this. - * Optionally, you can specify up to two variables to store the value in and - * the zero-based index of the current item: - *
var myTemplate = _.template(
-     * 	   '{{each value, index: names}}{{index}}. {{value.firstName}} {{value.lastName}}{{/each}}');
-     * 
- * - * If you do not pass an expression to each, it will take the list from this: - *
var myTemplate = _.template('{{each value:}}{{value}};{{/each}}');
-     * var result = myTemplate([1, 2, 3]);
- * - * Beside lists, you can also iterate through the properties of an object. The property name will be stored - * in the first given parameter and the value in this and the second parameter: - *
var myTemplate = _.template('{{each key, value: nicknames}}{{key}}: {{value}}{{/each}}');
-     * var result = myTemplate({nicknames: {Matt: 'Matthew', John: 'Jonathan'} });
- * - * Shorter version of the previous example that uses this for the value: - *
var myTemplate = _.template('{{each key: nicknames}}{{key}}: {{this}}{{/each}}');
- * - * If you do not need the key, you can omit the variable specification: - *
var myTemplate = _.template('{{each nicknames}}{{this}}{{/each}}');
- * - * You can define your own variables, using the regular JavaScript syntax, with 'var': - *
var myTemplate = _.template('{{var s=very.long.name, sum=a+b;}}{{s.desc}}, {{sum}}');
- * - * In some situations, it may be inevitable to embed raw JavaScript in the template. - * To embed JavaScript code, prefix the code with a '#': - *
var myTemplate = _.template(
-     *     '{{each}}{{#var sum = 0; for (var i = 0; i < 3; i++) sum += this.numbers[i]; }}{{sum}}{{/each}}');
-     * var result = myTemplate([['Foreword', 'Intro'], ['Something', 'Something else']]);
- * - * - * By default, all output will be escaped. You can prevent this by using triple-curly-braces: - *
Here's the original: {{{rawText}}}
. - * - * The template's JavaScript code is executed in a sandbox without access to global variables. Minified defines the - * following variables for you: - * - * - * - * - * - * - * - *
NameDesciption
thisThe template object outside of each. Inside eachs, the current value.
objThe parameter given to the template function.
_A reference to Minified Util.
escThe escape function given when the template has been defined. If no function has been given, - * a default function that returns the input unmodified.
printA function(text,...) that appends one or more strings to the template result.
eachA function(listOrObject, eachCallback) that can iterate over lists or object properties. - * The eachCallback is a function(key, value) for objects or function(value, index) - * for arrays that will be invoked for each item. - *
- * - * Every template you create is already cached, so it not an expensive operation to call ##_.template() a second - * time with the same template. However, because of caching, you should be careful when creating templates - * dynamically, as this will fill the cache up quickly. - * - * @param template The template as a string using the syntax described below. - * @param escapeFunction optional The callback function(inputString) that will be used - * to escape all output: - *
inputString
The string to escape.
- *
(callback return value)
The escaped string.
- * If no escapeFunction has been given, the output will not be escaped. - * ##_.escapeHtml() can be used as an escape function for HTML, and ##_.escapeRegExp() for regular expressions. - * JavaScript's built-in escape() function can escape URL components. - * @return the value returned by the last invocation of func - * - * @see ##_.format() shares template()'s syntax but returns the result directly. - * @see ##_.formatHtml() is a variant of format() with HTML escaping. - * @see ##_.escapeHtml() can be used by template() to escape HTML. - * @see ##_.escapeRegExp() can be used by template() to escape regular expressions. - * @see ##HTML() creates a HTML element tree from a template. - */ - 'template': template, - - /*$ - * @stop - */ - - dummyFormatHtml:0 - , - - ///#/snippet utilUnderscoreFuncs - ///#snippet extrasUnderscoreFuncs - // @condblock promise - 'promise': promise - // @condend promise - - /*$ - * @stop - */ - // @cond !promise dummyPromise:0 - - ///#/snippet extrasUnderscoreFuncs - }, _); - - ////INITIALIZATION //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ///#snippet webInit - /*$ - * @id ready_init - * @dependency - */ - document.addEventListener("DOMContentLoaded", function() { - callList(DOMREADY_HANDLER); - DOMREADY_HANDLER = _null; - }, false); - /*$ - @stop - */ - - - ///#/snippet webInit - - return { - ///#snippet extrasExports - - /*$ - * @stop - */ - - ///#/snippet extrasExports - ///#snippet utilExports - /*$ - * @id underscore - * @group LIST - * @name _() - * @syntax _(item...) - * @configurable default - * @module UTIL - * Creates a new Minified list. Supports variable arguments so you can add items directly to the list. For arguments that are lists - * (as defined by ##_.isList()), the list content will be added to the new list. Unlike #dollar#$()#, this is not done recursively - * and thus you can create a list of lists by wrapping arguments in a list. Another difference between _() and $() - * is that $() will automatically remove null values while _() will keep them. - * - * @example Creating an empty list: - *
_()
- * - * @example Creating a list with three items: - *
_(1, 2, 3)
- * - * @example Creating the same list, but by passing an array. One array level will be flattened: - *
_([1, 2, 3])
- * - * @example Creating a list containing the arrays [1, 2] and [3, 4]. - *
_([[1, 2], [3, 4]])
- * - * @example Merging two lists: - *
var a = _("a", "b", "c");
-     * var b = _("x", "y", "z");
-     * var merged = _(a, b);    // contains _("a", "b", "c", "x", "y", "z")
-     * 
- * - * @example Adding two elements to a list: - *
var a = _(1, 2, 3);
-     * var a4 = _(a, 4);       // contains _(1, 2, 3, 4)
-     * 
- * - * @example Mixing different list types and single elements: - *
_(1, [], [2, 3], _(), _(4, 5)); // same content as _(1, 2, 3, 4, 5)
- * - * @param item an item to add to the new list. If it is a list (as defined by ##_.isList()), its content will be to the new - * ##Minified list#list## (but NOT recursively). - */ - '_': _, - /*$ - * @stop - */ - ///#/snippet utilExports - ///#snippet webExports - - /*$ - * @id dollar - * @group SELECTORS - * @requires - * @dependency yes - * @name $() - * @syntax $() - * @syntax $(selector) - * @syntax $(selector, context) - * @syntax $(selector, context, childOnly) - * @syntax $(list) - * @syntax $(list, context) - * @syntax $(list, context, childOnly) - * @syntax $(object) - * @syntax $(object, context) - * @syntax $(object, context, childOnly) - * @syntax $(domreadyFunction) - * @module WEB - * Creates a new ##list#Minified list##, or register a DOMReady-handler. - * The most common usage is with a CSS-like selector. $() will then create a list containing all elements of the current HTML - * document that fulfill the filter conditions. Alternatively you can also specify a list of objects or a single object. - * Nested lists will automatically be flattened, and nulls will automatically be removed from the resulting list. - * If you call $() without any arguments, it will return an empty list. - * - * Additionally, you can specify a second argument to provide a context. Contexts only make sense if you selected - * HTML nodes with the first parameter. Then the context limits the resulting list to include only those nodes - * that are descendants of the context nodes. The context can be either a selector, a list or a single HTML node, and will be - * processed like the first argument. A third arguments allows you to limit the list to - * only those elements that are direct children of the context nodes (so a child of a child would be filtered out). - * - * The lists created by $() are the same type as the ##list#Minified lists## created by Util's #underscore#_() constructor and other - * Util methods. All Util methods work on lists created by $(). If you want to add your own methods to those lists, - * use ##M#MINI.M##. - * - * As a special shortcut, if you pass a function to $(), it will be registered using #ready#$.ready() to be executed - * when the DOM model is complete. - * - * @example A simple selector to find an element by id. - *
-     * var l0 = $('#myElementId');
-     * 
- * - * @example You can pass an object reference to create a list containing only this element: - *
-     * var l1 = $(document.getElementById('myElementId'));
-     * 
- * - * @example Lists and arrays will be copied: - *
-     * var l2 = $([elementA, elementB, elementC]);
-     * 
- * - * @example Lists will be automatically flattened and nulls removed. So this list l3 has the same content as l2: - *
-     * var l3 = $([elementA, [elementB, null, elementC], null]);
-     * 
- * - * @example This is a simple selector to find all elements with the given class. - *
-     * var l4 = $('.myClass');
-     * 
- * - * @example A selector to find all elements of the given type. - *
-     * var l5 = $('input'); // finds all input elements
-     * 
- * - * @example A selector to find all elements with the given type and class. - *
-     * var l6 = $('input.myRadio'); // finds all input elements with class 'myRadio'
-     * 
- * - * @example A selector to find all elements that are descendants of the given element. - *
-     * var l7 = $('#myForm input'); // finds all input elements contained in the element myForm
-     * 
- * - * @example A selector to find all elements that have either a CSS class 'a' or class 'b': - *
-     * var l8 = $('.a, .b'); // finds all elements that have class a or class b
-     * 
- * - * @example A selector that finds all elements that are descendants of the element myDivision, are inside an element with the - * class .myForm and are input elements: - *
-     * var l9 = $('#myDivision .myForm input');
-     * 
- * - * @example Contexts can make it easier to specify ancestors: - *
-     * var l10 = $('.myRadio', '#formA, #formB, #formC');
-     * 
- * The result is identical to: - *
-     * var l10 = $('#formA .myRadio, #formB .myRadio, #formC .myRadio');
-     * 
- * - * @example Using one of the list functions, ##set(), on the list, and setting the element's text color. '$' at the beginning of the property name sets a CSS value. - *
-     * $('#myElementId').set('$color', 'red');
-     * 
- * - * @example Most list methods return the list you invoked them on, allowing you to chain them: - *
-     * $('#myForm .myRadio').addClass('uncheckedRadio')
-     *                      .set('checked', true)
-     *                      .on('click', function() {
-     *                             $(this).set({@: 'uncheckedRadio');
-     *                      });
-     * 
- * - * @example Using $() as a #ready#$.ready() shortcut: - *
-     * $(function() {
-     *   // in here you can safely work with the HTML document
-     * });
-     * 
- * - * @param selector a simple, CSS-like selector for HTML elements. It supports '#id' (lookup by id), '.class' (lookup by class), - * 'element' (lookup by elements) and 'element.class' (combined class and element). Use commas to combine several selectors. - * You can also join two or more selectors by space to find elements which are descendants of the previous selectors. - * For example, use 'div' to find all div elements, '.header' to find all elements containing a class name called 'header', and - * 'a.popup' for all a elements with the class 'popup'. To find all elements with 'header' or 'footer' class names, - * write '.header, .footer'. To find all divs elements below the element with the id 'main', use '#main div'. - * The selector "*" will return all elements. - * @param list a list to copy. It can be an array, another Minified list, a DOM nodelist or anything else that has a length property and - * allows read access by index. A shallow copy of the list will be returned. Nulls will be automatically removed from the copy. Nested lists - * will be flattened, so the result only contains nodes. - * @param object an object to create a single-element list containing only the object. If the argument is null, an empty list will be returned. - * @param domreadyFunction a function to be registered using #ready#$.ready(). - * @param context optional an optional selector, node or list of nodes which specifies one or more common ancestor nodes for the selection. The context can be specified as - * a selector, a list or using a single object, just like the first argument. - * The returned list will contain only descendants of the context nodes. All others will be filtered out. - * @param childOnly optional if set, only direct children of the context nodes are included in the list. Children of children will be filtered out. If omitted or not - * true, all descendants of the context will be included. - * @return the array-like ##list#Minified list## object containing the content specified by the selector. - * Please note that if the first argument was a list, the existing order will be kept. If the first argument was a simple selector, the nodes are in document order. - * If you combined several selectors using commas, only the individual results of the selectors will keep the document order, - * but will then be joined to form a single list. This list will - * not be in document order anymore, unless you use a build without legacy IE support. - * Duplicate nodes will be removed from selectors, but not from lists. - * - * @see #underscore#_() is Util's alternative constructor for ##list#Minified lists## - * @see ##dollardollar#$$()## works like $(), but returns the resulting list's first element. - */ - '$': $, - - /*$ - * @id M - * @name M - * @syntax MINI.M - * @module WEB, UTIL - * - * Exposes the internal class used by all ##list#Minified lists##. This is mainly intended to allow you adding your - * own functions. - * - * @example Adding a function printLength() to M: - *
-     * MINI.M.prototype.printLength = function() { console.log(this.length); };
-     * 
- */ - 'M': M, - - /*$ - * @id getter - * @requires get - * @name MINI.getter - * @syntax MINI.getter - * @module WEB - * - * Exposes a map of prefix handlers used by ##get(). You can add support for a new prefix in get() - * by adding a function to this map. The prefix can be any string consisting solely of non-alphanumeric characters - * that's not already used by Minified. - * - * You must not replace getters by a new map, but must always modify the existing map. - * - * The function's signature is function(list, name) where - *
list
Is the Minified list to get the value from. By convention you should always use only the first element. The list is - * non-empty and the first elememt can't be null or undefined (get() automatically returns undefined in - * all other case).
- *
name
The name of the property. That's the part AFTER the prefix.
- *
(callback return value)
The value to return to the user.
- * - * @example Adding a shortcut '||' for accessing border style properties: - *
-     * MINI.getter['||'] = function(list, name) {
-     * 	return list.get('$border' + name.replace(/^[a-z]/, function(a) { return a.toUpperCase()});
-     * };
-     *
-     * var borderColor = $('#box').get('||color'); // same as '$borderColor'
-     * var borderLeftRadius = $('#box').get('||leftRadius'); // same as '$borderLeftRadius'
-     * 
- * - * @example Adding XLink attribute support to get(). This is useful if you work with SVG. The prefix is '>'. - *
-     * MINI.getter['>'] = function(list, name) {
-     * 	return list[0].getAttributeNS('http://www.w3.org/1999/xlink', name);
-     * };
-     *
-     * var xlinkHref = $('#svgLink').get('>href');
-     * 
- */ - 'getter': getter, - - /*$ - * @id setter - * @requires set - * @name MINI.setter - * @syntax MINI.setter - * @module WEB - * - * Exposes a map of prefix handlers used by ##set(). You can add support for a new prefix in set() - * by adding a function to this map. The prefix can be any string consisting solely of non-alphanumeric characters - * that's not already used by Minified. - * - * You must not replace setters by a new map, but must always modify the existing map. - * - * The function's signature is function(list, name, value) where - *
list
Is the Minified list to use.
- *
name
The name of the property. That's the part AFTER the prefix.
- *
value
Either the value to set, or a callback function to create the value that you must call for each - * value (see ##set() ).
- *
- * - * If you provide complete ##get() and ##set() support for a prefix, you are also able to use it in other Minified - * function such as ##animate() and ##toggle(). - * - * @example Adding a shortcut '||' for accessing border style properties. As it's just calling ##set() for an existing - * property, it is not required to extra code for the callback. - *
-     * MINI.setter['||'] = function(list, name, value) {
-     * 	list.set('$border' + name.replace(/^[a-z]/, function(a) { return a.toUpperCase()}, value);
-     * };
-     *
-     * $('#box').set('||color', 'red');   // same as set('$borderColor', 'red')
-     * $('#box').set('||leftRadius', 4);  // same as set('$borderLeftRadius', 4)
-     * 
- * - * @example Adding XLink attribute support to set(). This is useful if you work with SVG. The prefix is '>'. - *
-     * MINI.setter['>'] = function(list, name, value) {
-     * 	list.each(function(obj, index) {
-     * 		var v;
-     * 		if (_.isFunction(value))
-     * 			v = value(obj.getAttributeNS('http://www.w3.org/1999/xlink', name), index, obj);
-     * 		else
-     * 			v = value;
-     *
-     *		if (v == null)
-     *			obj.removeAttributeNS('http://www.w3.org/1999/xlink', name);
-     *		else
-     *			obj.setAttributeNS('http://www.w3.org/1999/xlink', name, v);
-     *	});
-     * };
-     *
-     * $('#svgLink').set('>href', 'http://minifiedjs.com/');
-     * 
- */ - 'setter': setter - /*$ - * @stop - */ - ///#/snippet webExports - }; - - ///#snippet commonAmdEnd -}); -///#/snippet commonAmdEnd -///#snippet webDocs - -/*$ - * @id list - * @name Minified Lists - * @module WEB, UTIL - * - * Minified lists are Array-like objects provided by Minified. Like a regular JavaScript array, - * they provide a length property and you can access their content using the index operator (a[5]). - * However, they do not provide the same methods as JavaScript's native array and are designed to be immutable, so - * there is no direct way to add something to a Minified list. Instead Minified provides a number of functions and methods - * that take a list and create a modified copy which, for example, may contain additional elements. - * - * Minified lists are typically created either using the Web module's #dollar#$() function or with the Util module's - * #underscore#_() function, but many functions in the Util module also return a Minified list. - * - * The Util module provides a function ##_.array() that converts a Minified list to a regular JavaScript array. - */ - -/*$ - * @id promiseClass - * @name Promise - * @module WEB, UTIL - * - * Promises are objects that represent the future result of an asynchronous operation. When you start such an operation, using #request#$.request(), - * ##animate(), or ##wait(), you will get a Promise object that allows you to get the result as soon as the operation is finished. - * - * Minified's full distribution ships with a Promises/A+-compliant implementation of Promises that should - * be able to interoperate with most other Promises implementations. Minified's Web module in stand-alone distribution comes with a limited implementation. - * See below for details. - * - * What may be somewhat surprising about this Promises specification is that the only standard-compliant way to access the result is to - * register callbacks. They will be invoked as soon as the operation is finished. - * If the operation already ended when you register the callbacks, the callback will then just be called from the event loop as soon - * as possible (but never while the ##then() you register them with is still running).
- * This design forces you to handle the operation result asynchronously and disencourages 'bad' techniques such as polling. - * - * The central method of a Promise, and indeed the only required function in Promises/A+, is ##then(). It allows you to register - * two callback methods, one for success (called 'fulfillment' in Promises/A+ terminology) and one for failures (called 'rejection' in Promises/A+). - * - * This example shows you how to use then(): - *
- * $.request('get', 'http://example.com/weather?zip=90210')
- *  .then(function success(result) {
- *      alert('The weather is ' + result);
- *  }, function error(exception) {
- *  	alert('Something went wrong');
- *  });
- * 
- * - * What makes Promises so special is that ##then() itself returns a new Promise, which is based on the Promise then() was called on, but can be - * modified by the outcome of callbacks. Both arguments to then() are optional, and you can also write the code like this: - *
- * $.request('get', 'http://example.com/weather?zip=90210')
- *  .then(function success(result) {
- *      alert('The weather is ' + result);
- *  })
- *  .then(null, function error(exception) {
- *  	alert('Something went wrong');
- *  });
- * 
- * - * Because the first ##then() returns a new Promise based on the original Promise, the second then() will handle errors of the request just like - * the first one did. There is only one subtle difference in the second example: the error handler will not only be called if the request failed, - * but also when the request succeded but the success handler threw an exception. That's one of the two differences between the original Promise and - * the Promise returned by then(). Any exception thrown in a callback causes the new Promise to be in error state. - * - * Before I show you the second difference between the original Promise and the new Promise, let me make the example a bit more readable - * by using ##error(), which is not part of Promises/A+, but a simple extension by Minified. It just registers the failure callback without - * forcing you to specify null as first argument: - *
- * $.request('get', 'http://example.com/weather?zip=90210')
- *  .then(function success(result) {
- *      alert('The weather is ' + result);
- *  })
- *  .error(function error(exception) {  // error(callback) is equivalent to then(null, callback)
- *  	alert('Something went wrong');
- *  });
- * 
- * - * A very powerful capability of Promises is that you can easily chain them. If a ##then() callback returns a value, the new Promise returned - * by then() will be marked as success (fulfilled) and this value is the result of the operation. If a callback returns a Promise, - * the new Promise will assume the state of the returned Promise. You can use the latter to create chains of asynchronous operations, - * but you still need only a single error handler for all of them and you do not need to nest functions to achieve this: - *
- * $.request('get', 'http://example.com/zipcode?location=Beverly+Hills,+CA')
- *  .then(function(resultZip) {
- *      return $.request('get', 'http://example.com/weather', {zip: resultZip});
- *  })
- *  .then(function(resultWeather) {
- *      alert('The weather in Beverly Hills is ' + resultWeather);
- *  })
- *  .error(function(exception) {
- *  	alert('Something went wrong');
- *  });
- * 
- * - * Only the full Minified distribution allows you to create promises yourself, using the ##promise() function. The Promises/A+ - * specification does not specify how to fulfill a promise, but in Minified's implementation every Promise object has a function fire() - * that needs to be called when the promise result is ready. It requires two arguments. - * The first is a boolean, true for a successful operation and false for a failure. The second is an array or list containing the - * arguments to call the corresponding ##then() handler with. - * - * The following example is a function, similar to ##wait(), that returns a Promise which succeeds after the given amount - * of milliseconds has passed. - * It then fulfills the promise with the number of milliseconds as argument. - * - *
- * function timeout(durationMs) {
- *		var p = _.promise();
- *		setTimeout(function() { p.fire(true, [durationMs]); }, durationMs);
- *		return p;
- * }
- * 
- * Call it like this: - *
- * timeout(1000).then(function(ms) { window.alert(ms+ ' milliseconds have passed.'); });
- * 
- * - *

Limited Promises Implementation in Web module

- * If you use only the Web module, instead of the full implementation, the promises implementation is not fully Promises/A+ compliant. - * One major difference is that it does not allow you create promises yourself. The only way to get a promise in the Web module - * is from functions like ##animate() and ##request(). The other difference is that the interoperability with other promises frameworks - * is limited, even though it should be good enough most of the time. - * - * There are two things you may run into when you use Web's simplified implementation with a complete implementation: - *
  1. The simplified implementation does not support recursive thenables. So when you register callbacks with ##then(), - * you can return a promise or a thenable, but only if that promise is not also returning a promise.
  2. - *
  3. Many corner cases required by the Promises/A+ specification are not handled. When interoperating using - * reasonable implementations, you may never run into this, but Promises/A+ has detailed rules for things like ##then() - * methods implemented as dynamic getter and returning a new value on each invocation or throwing exceptions. If you need - * a water-proof implementation, you need to use the complete implementation in Minified's full package.
- */ -/*$ - * @stop - */ - -///#/snippet webDocs - diff --git a/src/styles/items/_color.scss b/src/styles/items/_color.scss index df3f92f..3213800 100644 --- a/src/styles/items/_color.scss +++ b/src/styles/items/_color.scss @@ -9,6 +9,11 @@ box-shadow: $box-shadow-small-components; } + input:disabled ~ .value, + input:disabled ~ .label { + opacity: 0.25; + } + .picker-wrap { left: 0; top: 0; diff --git a/src/templates/items/color.tpl b/src/templates/items/color.tpl index 1d63192..b5692b8 100755 --- a/src/templates/items/color.tpl +++ b/src/templates/items/color.tpl @@ -1,9 +1,9 @@