// minified.js config start -- use this comment to re-create a configuration in the Builder
// - Only sections add, always, amdsupport, copyobj, dollardollar,
// - each, eachobj, equals, error, extend, find, format, formathtml, get, ht,
// - html, isobject, off, on, ready, request, select, set, 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 <var>require()</var> 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 <var>require</var> is very simple and will only support Minified and other libraries designed
* for Minfied, but <strong>no real AMD libraries</strong>. 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 <var>undefined</var>.
*
* @see ##define() allows you to define modules that can be obtained using <var>require()</var>.
*/
/*$
* @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,
* <var>define()</var> will not be set and you can use the AMD loader's (more powerful) variant.
*
* Minified's versions of <var>require()</var> and <var>define()</var> 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:
* <pre>
* 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');
* </pre>
*
* @param name the name of the module to request. In Minified's implementation, only 'minified' is supported.
* @param factoryFunction is a <code>function(require)</code> 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.
* <dl><dt>require</dt><dd>A reference to ##require(). While you could use <var>require()</var> from the global
* context, this would prevent backward compatibility with AMD.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>The reference to be returned by ##require().</dd></dl>
*
* @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 <code>define()</code> 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.<function()>} */
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: <cmp><value>:<format>|<cmp><value>:<format>|...
// e.g. 0:no item|1:one item|>=2:# items
// <value>="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:
* <ul><li>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.</li>
* <li>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.
* </li></ul>
*
* @example A simple promise that is fulfilled after 1 second, using Minified's invocation syntax:
* <pre>var p = _.promise();
* setTimeout(function() {
* p.fire(true);
* }, 1000);
* </pre>
*
* @example Request three files in parallel. When all three have been downloaded, concatenate them into a single string.
* <pre>
* 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);
* });
* </pre>
*
* @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.
*
* <var>fire()</var> 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:
* <pre>var p = _.promise();
* setTimeout(function() {
* p.fire(true, []);
* }, 1000);
* </pre>
*
* @example Call <var>fire()</var> without a context:
* <pre>var p = _.promise(function(resolve, reject) {
* setTimeout(resolve.fire, 1000);
* });
* </pre>
*
* @param newState <var>true</var> to set the Promise to fulfilled, <var>false</var> to set the state as rejected. If you pass <var>null</var> or
* <var>undefined</var>, 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.
*
* <var>stop()</var> can be invoked as a function without context ('this'). Every promise has its own instance.
*
* @return In some cases, the <var>stop()</var> 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.
* <pre>
* 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);
* </pre>
*/
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 (<var>onSuccess</var>) or an error occurred (<var>onError</var>). The callbacks will be called after
* <var>then()</var> returned, from the browser's event loop.
* You can chain <var>then()</var> invocations, as <var>then()</var> 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.
*
* <strong>Note:</strong> 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 <code>then()</code> handler throws an exception, this will not be caught and the promise returned by
* <code>then</code> will not be automatically rejected.
*
* @example Simple handler for an HTTP request. Handles only success and ignores errors.
* <pre>
* $.request('get', '/weather.html')
* .then(function(txt) {
* alert('Got response!');
* });
* </pre>
*
* @example Including an error handler.
* <pre>
* $.request('get', '/weather.html')
* .then(function(txt) {
* alert('Got response!');
* }, function(err) {
* alert('Error!');
* }));
* </pre>
*
* @example Chained handler.
* <pre>
* $.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');
* });
* </pre>
*
* @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 <var>then()</var>. 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 <var>null</var> or <var>undefined</var> 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 <var>then()</var>. 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 <var>null</var> or <var>undefined</var> 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.
* <pre>
* $.request('get', '/weather.html')
* .always(function() {
* alert('Got response or error!');
* });
* </pre>
*
* @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.
* <pre>
* $.request('get', '/weather.html')
* .error(function() {
* alert('Got error!');
* });
* </pre>
*
* @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:
* <pre>
* var list = $('input');
* var myValues = {};
* for (var i = 0; i < list.length; i++)
* myValues[list[i].name] = list[i].value;
* </pre>
*
* @example With Util module:
* <pre>
* var list = _(1, 2, 3);
* var sum = 0;
* for (var i = 0; i < list.length; i++)
* sum += list[i];
* </pre>
*/
/*$
* @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 <var>forEach()</var> it will be invoked for each item in the list,
* even if it is <var>undefined</var>.
*
* @example Creates the sum of all list entries.
* <pre>
* var sum = 0;
* _(17, 4, 22).each(function(item, index) {
* sum += item;
* });
* </pre>
*
* @example The previous example with a native array:
* <pre>
* var sum = 0;
* _.each([17, 4, 22], function(item, index) {
* sum += item;
* });
* </pre>
*
* @example This goes through all h2 elements of the class 'section' on a web page and changes their content:
* <pre>
* $('h2.section').each(function(item, index) {
* item.innerHTML = 'Section ' + index + ': ' + item.innerHTML;
* });
* </pre>
*
* @param list a list to iterate. Can be an array, a ##list#Minified list## or any other array-like structure with
* <var>length</var> property.
* @param callback The callback <code>function(item, index)</code> to invoke for each list element.
* <dl><dt>item</dt><dd>The current list element.</dd>
* <dt>index</dt><dd>The second the zero-based index of the current element.</dd>
* <dt class="this">this</dt><dd>The given context if not null. Otherwise the list.</dd>
* 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 <var>each()</var>, but wraps the list elements in a list.
* @see ##find() can be used instead of <var>each()</var> if you need to abort the loop.
* @see ##eachObj() iterates through the properties of an object.
*/
'each': listBind(each),
/*$
* @id equals
* @group LIST
* @requires
* @configurable default
* @name .equals()
* @altname _.equals()
* @syntax list.equals(otherObject)
* @syntax _.equals(thisObject, otherObject)
* @module UTIL
* Checks whether two values, lists or objects are equal in a deep comparison.
*
* First <var>equals()</var> checks whether it got a function as parameter.
* If yes, it will be invoked without arguments and <var>equals()</var> calls itself recursively with the function's result.
*
* Once both values are no functions anymore, the values will be evaluated, If the first value is...
* <ul><li>...<var>null</var> or <var>undefined</var>, they are only equal if the other one is also either <var>null</var> or <var>undefined</var>.</li>
* <li>...a value as defined by ##_.isValue(), but not a Date, they are equal if the other value is the same type and is equal according to the '==' operator.</li>
* <li>...a Date, they are equal if the other value is a Date representing the same time.</li>
* <li>...a list or array, they are equal if the other value is also either a list or an array, has the same number of items and all items equal the items of the other
* list at the same position. The equality of list items is determined recursively using the same rules, so you can also nest lists.</li>
* <li>...a function, it will be invoked without arguments and its return value is evaluated using these rules as if the value has been passed. </li>
* <li>...any other object, they are equal if they contain exactly the same keys (as defined by ##_.eachObj()) and all values are equal as determined using these rules
* recursively.</li>
* </ul>
*
* Please note that, according to the rules, a ##list#Minified list## is equal to an array, as long as their content is equal. <var>equals</var> does not
* differentiate between <var>null</var> and <var>undefined</var>.
*
* <var>equals</var> is commutative. If you swap the parameters, the result is the same as long as no functions are involved.
*
* @example Compare a list and an array:
* <pre>
* _.equals([1, 2, 3], _(1, 2, 3)); // returns true
* </pre>
*
* @example Same result, but with a list method:
* <pre>
* _(1, 2, 3).equals([1, 2, 3]); // returns true
* </pre>
*
* @param thisObject The first reference to evaluate.
* @param otherObject The second reference to evaluate.
* @return true if both references are equal. False otherwise.
*/
'equals': listBind(equals),
/*$
* @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 <var>find()</var>:
* <ol>
* <li>With a value as argument. Then <var>find()</var> 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,
* <var>find()</var> returns <var>undefined</var>.</li>
* <li>With a callback function. <var>find()</var> will then call the given function for each list element until the function
* returns a value that is not <var>null</var> or <var>undefined</var>. This value will be returned.</li>
* </ol>
*
* <var>find()</var> 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:
* <pre>
* var i = _(1, 2, -4, 5, 2, -1).find(function(value, index) { if (value < 0) return index; }); // returns 2
* </pre>
* @example Finds the index of the first 5 in the array:
* <pre>
* var i = _.find([3, 6, 7, 6, 5, 4, 5], 5); // returns 4 (index of first 5)
* </pre>
*
* @example Determines the position of the element with the id '#wanted' among all li elements:
* <pre>
* var elementIndex = $('li').find($$('#wanted'));
* </pre>
*
* @example Goes through the elements to find the first div that has the class 'myClass', and returns this element:
* <pre>
* var myClassElement = $('div').find(function(e) { if ($(e).is('.myClass')) return e; });
* </pre>
*
* @param list A list to use as input. Can be an array, a ##list#Minified list## or any other array-like structure with
* <var>length</var> property.
* @param findFunc The callback <code>function(item, index)</code> that will be invoked for every list item until it returns a non-null value:
* <dl><dt>item</dt><dd>The current list element.</dd><dt>index</dt><dd>The second the zero-based index of the current element.</dd>
* <dt class="this">this</dt><dd>This list.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>If the callback returns something other than <var>null</var> or
* <var>undefined</var>, <var>find()</var> will return it directly. Otherwise it will continue. </dd></dl>
* @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 <var>undefined</var> if not found. If called with a callback function,
* it returns either the value returned by the callback or <var>undefined</var>.
*
* @see ##findLast() is the equivalent to <var>find()</var> for the list's end.
*/
'find': listBind(find),
/*$
* @stop
*/
dummySort:0
,
///#/snippet utilListFuncs
///#snippet webListFuncs
/*$
* @id select
* @group SELECTORS
* @requires dollar
* @configurable default
* @name .select()
* @syntax list.select(selector)
* @syntax list.select(selector, childrenOnly)
* @module WEB
* Executes a selector with the list as context. <code>list.select(selector, childrenOnly)</code> is equivalent
* to <code>$(selector, list, childrenOnly)</code>.
*
* @example Returns a list of all list elements:
* <pre>
* var parents = $('ol.myList').select('li', true);
* </pre>
*
* @example Returns a list of all child elements:
* <pre>
* var children = $('.myElements').select('*', true);
* </pre>
*
* @param selector a selector or any other valid first argument for #dollar#$().
* @param childrenOnly 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 new list containing the selected descendants.
*
* @see ##only() executes a selector on the list elements, instead of their descendants.
*/
'select': function(selector, childOnly) {
return $(selector, this, childOnly);
},
/*$
* @id get
* @group SELECTORS
* @requires dollar
* @configurable default
* @name .get()
* @syntax list.get(name)
* @syntax list.get(name, toNumber)
* @syntax list.get(list)
* @syntax list.get(list, toNumber)
* @syntax list.get(map)
* @syntax list.get(map, toNumber)
* @module WEB
* Retrieves properties, attributes and styles from the list's first element. The syntax to request those values is mostly identical with ##set(). You can either
* get a single value if you specify only one name, or get an object map when you specify several names using an array or an object map.
*
* The <var>name</var> parameter defines what kind of data you are reading. The following name schemes are supported:
* <table>
* <tr><th>Name Schema</th><th>Example</th><th>Sets what?</th><th>Description</th></tr>
* <tr><td>name</td><td>innerHTML</td><td>Property</td><td>A name without prefix of '$' or '@' gets a property of the object.</td></tr>
* <tr><td>@name</td><td>@href</td><td>Attribute</td><td>Gets the HTML attribute using getAttribute().</td></tr>
* <tr><td>%name</td><td>%phone</td><td>Data-Attribute</td><td>Gets a data attribute using getAttribute(). Data attributes are
* attributes whose names start with 'data-'. '%myattr' and '@data-myattr' are equivalent.</td></tr>
* <tr><td>$name</td><td>$fontSize</td><td>CSS Property</td><td>Gets a style using the element's <var>style</var> object.
* The syntax for the CSS styles is camel-case (e.g. "$backgroundColor", not "$background-color"). Shorthand properties like "border" or "margin" are
* not supported. You must use the full name, e.g. "$marginTop". Minified will try to determine the effective style
* and thus will return the value set in style sheets if not overwritten using a regular style.</td></tr>
* <tr><td>$</td><td>$</td><td>CSS Classes</td><td>A simple <var>$</var> returns the CSS classes of the element and is identical with "className".</td></tr>
* <tr><td>$$</td><td>$$</td><td>Style</td><td>Reads the element's style attribute in a browser-independent way. On legacy IEs it uses
* <var>style.cssText</var>, and on everything else just the "style" attribute.</td></tr>
* <tr><td>$$show</td><td>$$show</td><td>Show/Hide</td><td>Returns 1 if the element is visible and 0 if it is not visible. An element counts as
* visible if '$visibility' is not 'hidden' and '$display' is not 'none'. Other properties will be ignored, even if they can also be used to hide the element.</td></tr>
* <tr><td>$$fade</td><td>$$fade</td><td>Fade Effect</td><td>The name '$$fade' returns the opacity of the element as a value between 0 and 1.
* '$$fade' will also automatically evaluate the element's 'visibility' and 'display' styles to find out whether the element is actually visible.</td></tr>
* <tr><td>$$slide</td><td>$$slide</td><td>Slide Effect</td><td>'$$slide' returns the height of the element in pixels with a 'px' suffix and is equivalent to '$height'.
* Please note that you can pass that 'px' value to '$$slide' in ##set(), which will then set the according '$height'.</td></tr>
* <tr><td>$$scrollX, $$scrollY</td><td>$$scrollY</td><td>Scroll Coordinates</td><td>The names '$$scrollX' and
* '$$scrollY' can be used on <code>$(window)</code> to retrieve the scroll coordinates of the document.
* The coordinates are specified in pixels without a 'px' unit postfix.</td></tr>
* </table>
*
* @example Retrieves the id, title attribute and the background color of the element '#myElement':
* <pre>
* var id = $('#myElement).get('id');
* var title = $('#myElement).get('@title');
* var bgColor = $('#myElement).get('$backgroundColor');
* </pre>
*
* @example Retrieves the id, title attribute and the background color of the element '#myElement' as a map:
* <pre>
* var m = $('#myElement).get(['id', '@title', '$backgroundColor']);
* var id = m.id;
* var title = m['@title'];
* var bgColor = m.$backgroundColor;
* </pre>
*
* @example Uses ##get() and ##set() to reposition an element:
* <pre>
* var coords = $('#myElement').get({$top: 0, $left: 0}, true);
* coords.$top = coords.$top + 10 + 'px';
* coords.$left = coords.$left + 20 + 'px';
* $('#myElement').set(coords);
* </pre>
* Please note that the values of $top and $left in the <var>get()</var> invocation do not matter and will be ignored!
*
* @param name the name of a single property or attribute to modify. Unprefixed names set properties, a '$' prefix sets CSS styles and
* '@' sets attributes. Please see the table above for special properties and other options.
* @param list in order to retrieve more than one value, you can specify several names in an array or list. <var>get()</var> will then return an object map
* containing the values.
* @param map if you specify an object that is neither list nor string, <var>get()</var> will use it as a map of property names. Each property name will be requested.
* The values of the properties in the map will be ignored. <var>get()</var> will then return a new object map containing of results.
* @param toNumber if 'true', <var>get()</var> converts all returned values into numbers. If they are strings,
* <var>get()</var> removes any non-numeric characters before the conversion. This is useful when you request
* a CSS property such as '$marginTop' that returns a value with a unit suffix, like "21px". <var>get()</var> will convert it
* into a number and return 21. If the returned value is not parsable as a number, <var>NaN</var> will be returned.
* @return if <var>get()</var> was called with a single name, it returns the corresponding value.
* If a list or map was given, <var>get()</var> returns a new object map with the names as keys and the values as values.
* It returns <var>undefined</var> if the list is empty.
*
* @see ##set() sets values using the same property syntax.
*/
'get': function(spec, toNumber) {
var self = this;
var element = self[0];
if (element) {
if (isString(spec)) {
var match = /^(\W*)(.*)/.exec(replace(spec, /^%/,'@data-'));
var prefix = match[1];
var s;
if (getter[prefix])
s = getter[prefix](this, match[2]);
else if (spec == '$')
s = self['get']('className');
else if (spec == '$$') {
s = self['get']('@style');
}
else if (spec == '$$slide')
s = self['get']('$height');
else if (spec == '$$fade' || spec == '$$show') {
if (self['get']('$visibility') == 'hidden' || self['get']('$display') == 'none')
s = 0;
else if (spec == '$$fade') {
s =
isNaN(self['get']('$opacity', true)) ? 1 : self['get']('$opacity', true);
}
else // $$show
s = 1;
}
else if (prefix == '$') {
s = _window['getComputedStyle'](element, _null)['getPropertyValue'](replace(match[2], /[A-Z]/g, function (match2) { return '-' + match2.toLowerCase(); }));
}
else if (prefix == '@')
s = element.getAttribute(match[2]);
else
s = element[match[2]];
return toNumber ? extractNumber(s) : s;
}
else {
var r = {};
(isList(spec) ? flexiEach : eachObj)(spec, function(name) {
r[name] = self['get'](name, toNumber);
});
return r;
}
}
},
/*$
* @id set
* @group SELECTORS
* @requires dollar get
* @configurable default
* @name .set()
* @syntax list.set(name, value)
* @syntax list.set(properties)
* @syntax list.set(cssClasses)
* @module WEB
*
* Modifies the list's elements by setting their properties, attributes, CSS styles and/or CSS classes. You can either supply a
* single name and value to set only one property, or you can provide an object that contains name/value pairs to describe more than one property.
* More complex operations can be accomplished by supplying functions as values. They will then be called for each element that will
* be set.
*
* The <var>name</var> parameter defines what kind of data you are setting. The following name schemes are supported:
*
* <table>
* <tr><th>Name Schema</th><th>Example</th><th>Sets what?</th><th>Description</th></tr>
* <tr><td>name</td><td>innerHTML</td><td>Property</td><td>A name without prefix of '$' or '@' sets a property of the object.</td></tr>
* <tr><td>@name</td><td>@href</td><td>Attribute</td><td>Sets the HTML attribute using setAttribute(). In order to stay compatible with Internet Explorer 7 and earlier,
* you should not set the attributes '@class' and '@style'. Instead use '$' and '$$' as shown below.</td></tr>
* <tr><td>%name</td><td>%phone</td><td>Data-Attribute</td><td>Sets a data attribute using setAttribute(). Data attributes are
* attributes whose names start with 'data-'. '%myattr' and '@data-myattr' are equivalent.</td></tr>
* <tr><td>$name</td><td>$fontSize</td><td>CSS Property</td><td>Sets a style using the element's <var>style</var> object.
* The syntax for the CSS styles is camel-case (e.g. "$backgroundColor", not "$background-color"). </td></tr>
* <tr><td>$</td><td>$</td><td>CSS Classes</td><td>A simple <var>$</var> modifies the element's CSS classes using the object's <var>className</var> property. The value is a
* space-separated list of class names. If prefixed with '-' the class is removed, a '+' prefix adds the class and a class name without prefix toggles the class.
* The name '$' can also be omitted if <var>set</var> is called with class names as only argument.</td></tr>
* <tr><td>$$</td><td>$$</td><td>Style</td><td>Sets the element's style attribute in a browser-independent way.</td></tr>
* <tr><td>$$show</td><td>$$show</td><td>Show/Hide</td><td>If <var>true</var> or a number not 0, it will make sure the element is visible by
* making sure '$display' is not 'none' and by setting '$visibility' to 'visible'. Please see ##show() for details. If the value is <var>false</var> or 0, it
* will be hidden by setting '$display' to 'none'.</td></tr>
* <tr><td>$$fade</td><td>$$fade</td><td>Fade Effect</td><td>The name '$$fade' sets the opacity of the element in a browser-independent way. The value must be a number
* between 0 and 1. '$$fade' will also automatically control the element's 'visibility' style. If the value is 0,
* the element's visibility will automatically be set to 'hidden'. If the value is larger, the visibility will be set to
* 'visible'. '$$fade' only works with block elements.</td></tr>
* <tr><td>$$slide</td><td>$$slide</td><td>Slide Effect</td><td>The name '$$slide' allows a vertical slide-out or slide-in effect. The value must be a number
* between 0 and 1 and will be used to set the element's '$height'. '$$slide' will also automatically control the element's 'visibility'
* style. If the value is 0, the element's visibility will automatically be set to 'hidden'. If the value is larger,
* the visibility will be set to 'visible'. '$$slide' only works with block elements and will not set the
* element's margin or padding. If you need a margin or padding, you should wrap the elements in a simple <div>.</td></tr>
* <tr><td>$$scrollX, $$scrollY</td><td>$$scrollY</td><td>Scroll Coordinates</td><td>The names '$$scrollX' and
* '$$scrollY' can be used on <code>$(window)</code> to set the scroll coordinates of the document.
* The coordinates are specified in pixels, but must not use a 'px' unit postfix.</td></tr>
* </table>
*
* @example Unchecking checkboxes:
* <pre>
* $('input.checkbox').set('checked', false);
* </pre>
*
* @example Changing the <var>innerHTML</var> property of an element:
* <pre>
* $('#toc').set('innerHTML', 'Content');
* </pre>
*
* @example Changing attributes:
* <pre>
* $('a.someLinks').set('@href', 'http://www.example.com/');
* </pre>
*
* @example Removing attributes:
* <pre>
* $('a.someLinks').set('@title', null);
* </pre>
*
* @example Changing styles:
* <pre>
* $('.bigText').set('$fontSize', 'x-large');
* </pre>
*
* @example Adding and removing CSS classes:
* <pre>
* $('.myElem').set('$', '+myClass -otherClass');
* </pre>
*
* @example Toggling a CSS class:
* <pre>
* $('.myElem').set('$', 'on');
* </pre>
*
* @example Shortcut for CSS manipulation:
* <pre>
* $('.myElem').set('+myClass -otherClass on');
* </pre>
*
* @example Making an element transparent:
* <pre>
* $('.seeThrough').set('$$fade', 0.5);
* </pre>
*
* @example Making an element visible. Note that $$fade will set the element's display style to 'block' and visibility style to 'visible'.
* <pre>
* $('.myElem').set('$$fade', 1);
* </pre>
*
* @example Using a map to change several properties:
* <pre>
* $('input.checkbox').set({checked: false,
* '@title': 'Check this'});
* </pre>
*
* @example Changing CSS with a map:
* <pre>
* $('.importantText').set({$fontSize: 'x-large',
* $color: 'black',
* $backgroundColor: 'red',
* $: '+selected -default'});
* </pre>
*
* @example You can specify a function as value to modify a value instead of just setting it:
* <pre>
* $('h2').set('innerHTML', function(oldValue, index) {
* return 'Chapter ' + index + ': ' + oldValue.toUpperCase();
* });
* </pre>
*
* @param name the name of a single property or attribute to modify. Unprefixed names set properties, a '$' prefix sets CSS styles and
* '@' sets attributes. Please see the table above for special properties and other options.
* @param value the value to set. If value is <var>null</var> and name specified an attribute, the attribute will be removed.
* If dollar ('$') has been passed as name, the value can contain space-separated CSS class names. If prefixed with a '+' the class will be added,
* with a '-' prefix the class will be removed. Without prefix, the class will be toggled.
* If <var>value</var> is a function, the <code>function(oldValue, index, obj)</code> will be invoked for each list element
* to evaluate the new value:
* <dl><dt>oldValue</dt><dd>The old value of the property to be changed, as returned by ##get().
* For the CSS style names, this is the computed style of the property </dd>
* <dt>index</dt><dd>The list index of the object owning the property</dd>
* <dt>obj</dt><dd>The list element owning the property.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>The value to be set.</dd></dl>
* Functions are not supported by '$'.
* @param properties a Object as map containing names as keys and the values to set as map values. See above for the name and value syntax.
* @param cssClasses if <var>set()</var> is invoked with a string as single argument, the name "$" (CSS classes) is assumed and the argument is the
* value. See above for CSS syntax.
* Instead of a string, you can also specify a <code>function(oldValue, index, obj)</code> to modify the existing classes.
* @return the list
*
* @see ##get() retrieves values using the same property syntax.
* @see ##animate() animates values using the same property syntax.
* @see ##toggle() can toggle between two sets of values.
* @see ##dial() allows smooth transitions between two sets of values.
*/
'set': function (name, value) {
var self = this;
if (value !== undef) {
var match = /^(\W*)(.*)/.exec(replace(replace(name, /^\$float$/, 'cssFloat'), /^%/,'@data-'));
var prefix = match[1];
if (setter[prefix])
setter[prefix](this, match[2], value);
else if (name == '$$fade') {
this['set']({'$visibility': value ? 'visible' : 'hidden', '$opacity': value});
}
else if (name == '$$slide') {
self['set']({'$visibility': value ? 'visible' : 'hidden', '$overflow': 'hidden',
'$height': /px/.test(value) ? value : function(oldValue, idx, element) { return getNaturalHeight($(element), value);}
});
}
else if (name == '$$show') {
if (value)
self['set']({'$visibility': value ? 'visible' : 'hidden', '$display': ''}) // that value? part is only for gzip
['set']({'$display': function(oldVal) { // set for 2nd time: now we get the stylesheet's $display
return oldVal == 'none' ? 'block' : oldVal;
}});
else
self['set']({'$display': 'none'});
}
else if (name == '$$') {
self['set']('@style', value);
}
else
flexiEach(this, function(obj, c) {
var newValue = isFunction(value) ? value($(obj)['get'](name), c, obj) : value;
if (prefix == '$') {
if (match[2])
obj['style'][match[2]] = newValue;
else {
flexiEach(newValue && newValue.split(/\s+/), function(clzz) {
var cName = replace(clzz, /^[+-]/);
if (/^\+/.test(clzz))
obj['classList'].add(cName);
else if (/^-/.test(clzz))
obj['classList'].remove(cName);
else
obj['classList'].toggle(cName);
});
}
}
else if (name == '$$scrollX')
obj['scroll'](newValue, $(obj)['get']('$$scrollY'));
else if (name == '$$scrollY')
obj['scroll']($(obj)['get']('$$scrollX'), newValue);
else if (prefix == '@') {
if (newValue == _null)
obj.removeAttribute(match[2]);
else
obj.setAttribute(match[2], newValue);
}
else
obj[match[2]] = newValue;
});
}
else if (isString(name) || isFunction(name))
self['set']('$', name);
else
eachObj(name, function(n,v) { self['set'](n, v); });
return self;
},
/*$
* @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 <var>add()</var> and can help you create new HTML nodes.
*
* @example Using the following HTML:
* <pre>
* <div id="comments">Here is some text.<br/></div>
* </pre>
* The next line appends a text node to the div:
* <pre>
* $('#comments').add('Some additional text.');
* </pre>
* This results in:
* <pre>
* <div id="comments">Here is some text.<br/>Some additional text.</div>
* </pre>
*
* @example Using the following HTML:
* <pre>
* <ul id="myList">
* <li>First list entry</li>
* <li>Second list entry</li>
* </ul>
* </pre>
* The following Javascript adds an element to the list:
* <pre>
* $('#myList').add(EE('li', 'My extra point');
* </pre>
* This results in
* <pre>
* <ul id="myList">
* <li>First list entry</li>
* <li>Second list entry</li>
* <li>My extra point</li>
* </ul>
* </pre>
*
* @example Use a list to add several elements at once:
* <pre>
* $('#comments').add([
* EE('br'),
* 'Some text',
* EE('span', {'className': 'highlight'}, 'Some highlighted text')
* ]);
* </pre>
*
* @example If you need to customize the content, you can write a factory function:
* <pre>
* $('.chapter').add(function(parent, index) { return EE('h2', 'Chapter number ' + index); });
* </pre>
*
* @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 <code>function(listItem, listIndex)</code> that will be invoked for each list element to create the nodes:
* <dl><dt>listItem</dt><dd>The list element that will receive the new children.</dd>
* <dt>listIndex</dt><dd>The index of the list element that will receive the new children.</dd>
* <dt class="returnValue">(callback return value)<dt><dd>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.</dd></dl>
* @return the current list
*
* @see ##fill() works like <var>add()</var>, 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 <var>true</var>
* 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.
* <pre>
* $('div').on('click', function() {
* this.style.backgroundColor = 'red'; // 'this' contains the element that caused the event
* });
* </pre>
*
* @example Registers a handler to call a method setStatus('running') using an inline function:
* <pre>
* $('#myButton').on('click', function() {
* setStatus('running');
* });
* </pre>
* The previous example can bere written like this, using <var>on()</var>'s <var>args</var> parameter:
* <pre>
* $('#myButton').on('click', setStatus, ['running']);
* </pre>
*
* @example Adds two handlers on an input field. The event names are prefixed with '|' and thus keep their original behavior:
* <pre>
* $('#myInput').on('|keypress |keydown', function() {
* // do something
* });
* </pre>
*
* @example Adds a click handler that will abort the operation by returning false, unless the user confirms it:
* <pre>
* $('#myLink').on('?click', function() {
* return window.confirm('Really leave?');
* });
* </pre>
*
* @example Adds a button and registers a click handler for it using a sub-selector.
* <pre>
* $('#myForm').add(HTML("<li><button>click me</button></li>").on('button', 'click', myClickHandler));
* </pre>
*
* @example Adds listeners for all clicks on a table's rows using the bubble selector 'tr'.
* <pre>
* $('#table').on('change', 'tr', function(event, index, selectedIndex) {
* alert("Click on table row number: " + selectedIndex);
* }, 'tr');
* </pre>
* Please note that bubble selectors will even listen to events for
* table rows that have been added <strong>after you registered for the events</strong>.
*
* @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 <var>$()</var> 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 <var>true</var>.
* @param eventHandler the callback <code>function(event, index)</code> to invoke when the event has been triggered:
* <dl>
* <dt>event</dt><dd>The original DOM event object.</dd>
* <dt>index</dt><dd>The index of the target object in the ##list#Minified list## .</dd>
* <dt class="this">this</dt><dd>A ##list#Minified list## containing the target element as only item (same as <var>event.target</var>).</dd>
* <dt class="returnValue">(callback return value)</dt><dd>The return value will only be used if the event name prefix was '?'.
* Then, a return value <var>false</var> will stop all further processing of the event and disable event bubbling.
* <var>true</var> will keep the event alive.</dd>
* </dl>
* @param customFunc a function to be called instead of a regular event handler with the arguments given in <var>args</var>.
* 'this' will be a ##list#Minified list## containing the target element as only item (same element as <var>event.target</var>).
* @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 <var>$()</var> 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 <var>trigger()</var>. 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.
* <pre>
* $('#myButton').trigger('click');
* </pre>
*
* @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
/*$
* @id ht
* @group ELEMENT
* @requires set template
* @configurable default
* @name .ht()
* @syntax list.ht(templateString, object...)
* @syntax list.ht(templateFunction, object...)
* @syntax list.ht(idSelector, object...)
* @module WEB+UTIL
* Replaces the content of the list elements with the HTML generated using the given template. The template uses
* ##template() syntax and HTML-escaped its output using ##escapeHtml().
*
* @example When you have a HTML snippet like this:
* <pre>
* <div id="price"></div>
* </pre>
* Then you can format the price value like this:
* <pre>
* var price = 14.9;
* $('#price').ht('<b>${{::0.00}}</b>', price);
* </pre>
* Results in:
* <pre>
* <div id="price"><b>$14.90</b></div>
* </pre>
*
* @example Render a list of names:
* <pre>
* var names = [ {first: 'James', last: 'Sullivan'},
* {first: 'Michael', last: 'Wazowski'} ];
* $('#list').ht('<h2>{{listName}}</h2>'+
* '<ul>{{each n: names}}<li>{{n.first}} {{n.last}}</li>{{/each}}</ul>',
* {listName: 'Guys', names: names});
* </pre>
* The code creates this:
* <pre>
* <h2>Guys</h2>
* <ul><li>James Sullivan<li><li>Michael Wazowski</li></ul>
* </pre>
*
* @example You can store templates in <script> tags. First you need to create a <script> tag with a type not
* supported by the browser and put your template in there, like this:
* <pre><script id="myTimeTpl" type="minified-template">The time is {{HH:mm:ss}}.</script></pre>
* Then you can specify the tag's id directly to access it:
* <pre>$('#timeDisplay').ht('#myTimeTpl', new Date());</pre>
*
* @param templateString the template using ##template() syntax. Please note, because this is a template, you should
* avoid creating the template itself dynamically, as compiling templates is expensive and
* Minified will cache only a limited number of templates. Exception: If the template string does not use
* any template functionality (no {{}}), it does not need to be compiled and won't be cached.<br/>
* The template will use ##escapeHtml() as escape function, so all template substitutions will be HTML-escaped,
* unless you use triple curly-braces.
* @param templateFunction instead of a HTML template, <var>ht()</var> can also use a template function, e.g. one
* created by ##template(). It will be invoked with the object as only argument.
* @param idSelector if you pass an ID CSS selector in the form "#myScript", Minified will recognize this and use the content
* of the specified <script> element as template. This allows you to put your template into
* a <script> tag with a non-JavaScript type (see example). Any string that starts with '#' and does not
* contain any spaces is used as selector.
* @param object optional one or more objects to pass to the template. If object is not set, the template is called with <var>undefined</var>
* as object. If exactly one object is given, it is passed directly to the template. If you specify more than one
* object, they are ##merge#merged##.
* @return the current list
*
* @see ##HTML() creates only the nodes and can be used with ##add() and other methods to add the nodes to the DOM, giving you more flexibility than <var>ht()</var>.
*/
'ht': function(htmlTemplate, object) {
var o = arguments.length > 2 ? merge(sub(arguments, 1)) : object;
return this['set']('innerHTML', isFunction(htmlTemplate) ? htmlTemplate(o) :
/{{/.test(htmlTemplate) ? formatHtml(htmlTemplate, o) :
/^#\S+$/.test(htmlTemplate) ? formatHtml($$(htmlTemplate)['text'], o) : htmlTemplate);
}
/*$
* @stop
*/
// @cond !ht 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:
* <pre>
* $.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.');
* });
* </pre>
*
* @example Sending a JSON object to a REST web service:
* <pre>
* 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);
* </pre>
*
* @example Using HTTP authentication and a custom XMLHttpRequest property.
* <pre>var handler = $.request('get', 'http://service.example.com/userinfo', null, {xhr: {withCredentials: true}, user: 'me', pass: 'secret'});</pre>
*
*
* @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):
* <dl><dt>headers</dt><dd>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.</dd>
* <dt>xhr</dt><dd>a map of properties to set in the XMLHttpRequest object before the request is sent, for example <code>{withCredentials: true}</code>.</dd>
* <dt>user</dt><dd>username for HTTP authentication, together with the <var>pass</var> parameter</dd>
* <dt>pass</dt><dd>password for HTTP authentication, together with the <var>user</var> parameter</dd>
* </dl>
* @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 <code>function(text, xhr)</code>:
* <dl><dt>text</dt><dd>The response sent by the server as text.</dd>
* <dt>xhr</dt><dd>The XMLHttpRequest used for the request. This allows you to retrieve the response in different
* formats (e.g. <var>responseXml</var> for an XML document</var>), to retrieve headers and more.</dd></dl>
* The failure handler will be called as <code>function(statusCode, statusText, text)</code>:
* <dl><dt>statusCode</dt><dd>The HTTP status (never 200; 0 if no HTTP request took place).</dd>
* <dt>text</dt><dd>The response's body text, if there was any, or the exception as string if the browser threw one.</dd>
* <dt>xhr</dt><dd>The XMLHttpRequest used for the request. This allows you to retrieve the response in different
* formats (e.g. <var>responseXml</var> for an XML document</var>), to retrieve headers and more..</dd></dl>
* The returned promise supports ##stop(). Calling <var>stop()</var> will invoke the XHR's <var>abort()</var> method.
* The underlying XmlHttpRequest can also be obtained from the promise's <var>xhr</var> property.
*
* @see ##values() serializes an HTML form in a format ready to be sent by <var>$.request</var>.
* @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 <var>escape()</var> 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 <var>window.onload</var>.
*
* If you call <var>ready()</var> after the page is completed, the handler is scheduled for invocation in the event loop as soon as possible.
*
* A shortcut for <var>ready()</var> 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:
* <pre>
* $.ready(function() {
* $('#someElement').fill('ready() called');
* });
* </pre>
*
* @param handler the <code>function()</code> to be called when the HTML is ready.
* @see ##dollar#$()## calls <var>ready()</var> when invoked with a function, offering a more convenient syntax.
*/
'ready': ready,
/*$
* @id off
* @group EVENTS
* @requires on
* @configurable default
* @name $.off()
* @syntax $.off(handler)
* @module WEB
* Removes the given event handler. The call will be ignored if the given handler has not been registered using ##on().
* If the handler has been registered for more than one element or event, it will be removed from all instances.
*
* Please note that you can not unregister event handlers registered using ##onOver() or ##onChange().
*
* @example Adds a handler to an element:
* <pre>
* function myEventHandler() {
* this.style.backgroundColor = 'red'; // 'this' contains the element that caused the event
* }
* $('#myElement').on('click', myEventHandler); // add event handler
*
* window.setInterval(function() { // after 5s, remove event handler
* $.off(myEventHandler);
* }, 5000);
* </pre>
*
* @param handler the handler to unregister, as given to ##on(). It must be a handler that has previously been registered using ##on().
* If the handler is not registered as event handler, the function does nothing.
*
* @see ##on() registers an event handler.
*/
'off': off
/*$
* @stop
*/
// @cond !off 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.
* <pre>
* 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);
* });
* });
* </pre>
*
*
* @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 <var>args</var> parameter as given to <var>wait()</var>. 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 each
'each': each,
// @condend
// @condblock each
'toObject': toObject,
// @condend
// @condblock find
'find': find,
// @condend
// @condblock equals
'equals': equals,
// @condend
/*$
* @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:
* <pre>var target = {a:3, c: 3};
* _.copyObj({a: 1, b: 2}, target); // target is now {a: 1, b: 2, c: 3}</pre>
*
* @example Inline property merge:
* <pre>var target = _.copyObj({a: 1, b: 2}, {a:3, c: 3}); // target is now {a: 1, b: 2, c: 3}</pre>
*
* @example Duplicating an object:
* <pre>var target = _.copyObj({a: 1, b: 2}); // target is now {a: 1, b: 2}</pre>
*
* @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 <var>copyObj()</var>, but with a slightly different syntax.
* @see ##_.merge() copies a list of objects into a new object.
*/
'copyObj': copyObj,
/*$
* @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.
*
* <b>Please note:</b> Unlike jQuery, <var>extend</var> 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 <var>$</var> or <var>_</var>, just assign the new function(s) as property.
*
* @example Copying properties:
* <pre>var target = {a:3, c: 3};
* _.extend(target, {a: 1, b: 2}); // target is now {a: 1, b: 2, c: 3}</pre>
*
* @example Using several source values:
* <pre>var extend = _.extend({a: 1, b: 2}, {a:3, c: 3}, {d: 5}); // target is now {a: 1, b: 2, c: 3, d: 5}</pre>
*
* @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 <var>undefined</var>
* parameters will be ignored.
* @return the target
*
* @see ##_.copyObj() is very similar to <var>extend()</var>, 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 eachobj
* @group OBJECT
* @requires
* @configurable default
* @name _.eachObj()
* @syntax _.eachObj(obj, callback)
* @syntax _.eachObj(obj, callback, ctx)
* @module UTIL
* Invokes the given function once for each property of the given object. The callback is not invoked for inherited properties.
*
* @example Dumps all properties of an object.
* <pre>
* var s = '';
* _.eachObj({a: 1, b: 5, c: 2}, function(key, value) {
* s += 'key=' + key + ' value=' + value + '\n';
* });
* </pre>
*
* @param obj the object to use
* @param callback The callback <code>function(key, value)</code> to invoke for each property.
* <dl><dt>key</dt><dd>The name of the current property.</dd>
* <dt>value</dt><dd>The value of the current property.</dd>
* <dt class="this">this</dt><dd>The given context. If not set, the object itself.</dd>
* The callback's return value will be ignored.
* @param ctx optional a context to pass to the callback as 'this'.
* @return the object
*
* @see ##_.each() iterates through a list.
*/
'eachObj': eachObj,
/*$
* @id isobject
* @group TYPE
* @requires
* @configurable default
* @name _.isObject()
* @syntax _.isObject(obj)
* @module UTIL
* Checks whether the given reference is an object as defined by <var>typeof</var>.
*
* @param obj the object to test
* @return <var>true</var> if the object is an object, <var>false</var> otherwise.
*/
'isObject': isObject,
/*$
* @id format
* @group FORMAT
* @requires template
* @configurable default
* @name _.format()
* @syntax _.format()
* @syntax _.format(template, object)
* @syntax _.format(template, object, escapeFunction)
* @module UTIL
* Formats an object using a ##template#template##. The template syntax is shared with ##_.template(). The only difference is that
* <var>format()</var> frees you from the extra step of creating the template. In any case, whether you use
* <var>format()</var> or ##_.template(), the template will be cached. Be careful when you create templates dynamically, as
* every template is cached and consumes memory.<br/>
* If you only want to format a single value, use ##_.formatValue().
*
* @example Format a name:
* <pre>var s = _.formatHtml("{{first}} {{last}}", {first: 'Tim', last: 'Taylor'});</pre>
*
* @example Format a list of dates:
* <pre>var s = _.format("{{each}}{{this :: yyyy-MM-dd}}{{/each}}", dateList);</pre>
*
* @param template The ##template#template## as a string. The template, once created, will be cached.
* @param object the object to format
* @param escapeFunction optional The callback <code>function(inputString)</code> that will be used
* to escape all output:
* <dl><dt>inputString</dt><dd>The string to escape.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>The escaped string.</dd></dl>
* 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 <var>escape()</var> function can escape URL components.
* See ##_.htmlFormat() for a version of <var>format()</var> that already includes HTML escaping.
* @return the string created by the template
*
* @see ##_.template() creates a template function, using the same syntax.
* @see ##_.formatHtml() is a variant of <var>format()</var> with HTML-escpaping built it.
* @see ##_.formatValue() formats a single number or date.
* @see ##_.escapeRegExp() can be used by <var>format()</var> to escape regular expressions.
*/
'format': function(tpl, object, escapeFunction) {
return template(tpl, escapeFunction)(object);
},
/*$
* @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
* <a href="http://handlebarsjs.com/">Handlebars</a>. 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:
* <pre>{{a}} plus {{b}} is {{a+b}}</pre>
*
* To use such a template, create it with <var>template()</var> and then execute the resulting function:
* <pre>var myTemplate = _.template('{{a}} plus {{b}} is {{a+b}}');
* var result = myTemplate({a: 5, b: 7});</pre>
* If you pass an object as input, its properties will be mapped using JavaScript's <code>with</code>
* 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 <var>obj</var>:
* <pre>var myTemplate = _.template('The result is {{obj}}.');
* var result = myTemplate(17);</pre>
* Alternatively, you could also access the input as <var>this</var>, but be aware that JavaScript wraps simples types
* such as Number and Boolean. <var>this</var> is the default, so you can omit it to get the same result:
* <pre>var myTemplate = _.template('The result is {{ }}.');
* var result = myTemplate(17);</pre>
*
* Minified templates can use ##_.formatValue() formats directly. Just separate them from the expression by
* a double-colon:
* <pre>The price is {{obj::#.00}}.</pre>
*
* Conditions can be expressed using <code>if</code> and <code>else</code>:
* <pre>Hello {{if visits==0}}New{{else if visits<10}}Returning{{else}}Regular{{/if}} Customer.</pre>
* You can use any JavaScript expression as condition.
*
* Use <code>each</code> to iterate through a list:
* <pre>var myTemplate = _.template(
* '{{each names}}{{this.firstName}} {{this.lastName}}{{/each}}');
* var result = myTemplate({names: [{firstName: 'Joe', lastName: 'Jones'},
* {firstName: 'Marc', lastName: 'Meyer'}]});</pre>
* <code>each</code> will iterate through the members of the given object. It
* calls its body for each item and put a reference to the item into <var>this</var>.
* Optionally, you can specify up to two variables to store the value in and
* the zero-based index of the current item:
* <pre>var myTemplate = _.template(
* '{{each value, index: names}}{{index}}. {{value.firstName}} {{value.lastName}}{{/each}}');
* </pre>
*
* If you do not pass an expression to <code>each</code>, it will take the list from <var>this</var>:
* <pre>var myTemplate = _.template('{{each value:}}{{value}};{{/each}}');
* var result = myTemplate([1, 2, 3]);</pre>
*
* 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 <var>this</var> and the second parameter:
* <pre>var myTemplate = _.template('{{each key, value: nicknames}}{{key}}: {{value}}{{/each}}');
* var result = myTemplate({nicknames: {Matt: 'Matthew', John: 'Jonathan'} });</pre>
*
* Shorter version of the previous example that uses <var>this</var> for the value:
* <pre>var myTemplate = _.template('{{each key: nicknames}}{{key}}: {{this}}{{/each}}');</pre>
*
* If you do not need the key, you can omit the variable specification:
* <pre>var myTemplate = _.template('{{each nicknames}}{{this}}{{/each}}');</pre>
*
* You can define your own variables, using the regular JavaScript syntax, with 'var':
* <pre>var myTemplate = _.template('{{var s=very.long.name, sum=a+b;}}{{s.desc}}, {{sum}}');</pre>
*
* In some situations, it may be inevitable to embed raw JavaScript in the template.
* To embed JavaScript code, prefix the code with a '#':
* <pre>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']]);</pre>
*
*
* By default, all output will be escaped. You can prevent this by using triple-curly-braces:
* <pre>Here's the original: {{{rawText}}}</pre>.
*
* The template's JavaScript code is executed in a sandbox without access to global variables. Minified defines the
* following variables for you:
* <table>
* <tr><th>Name</th><th>Desciption</th></tr>
* <tr><td>this</td><td>The template object outside of <code>each</code>. Inside <code>each</code>s, the current value.</td></tr>
* <tr><td>obj</td><td>The parameter given to the template function.</td></tr>
* <tr><td>_</td><td>A reference to Minified Util.</td></tr>
* <tr><td>esc</td><td>The escape function given when the template has been defined. If no function has been given,
* a default function that returns the input unmodified.</td></tr>
* <tr><td>print</td><td>A <code>function(text,...)</code> that appends one or more strings to the template result.</td></tr>
* <tr><td>each</td><td>A <code>function(listOrObject, eachCallback)</code> that can iterate over lists or object properties.
* The <var>eachCallback</var> is a <code>function(key, value)</code> for objects or <code>function(value, index)</code>
* for arrays that will be invoked for each item.
* </table>
*
* 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 <code>function(inputString)</code> that will be used
* to escape all output:
* <dl><dt>inputString</dt><dd>The string to escape.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>The escaped string.</dd></dl>
* 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 <var>escape()</var> function can escape URL components.
* @return the value returned by the last invocation of <var>func</var>
*
* @see ##_.format() shares <var>template()</var>'s syntax but returns the result directly.
* @see ##_.formatHtml() is a variant of <var>format()</var> with HTML escaping.
* @see ##_.escapeHtml() can be used by <var>template()</var> to escape HTML.
* @see ##_.escapeRegExp() can be used by <var>template()</var> to escape regular expressions.
* @see ##HTML() creates a HTML element tree from a template.
*/
'template': template,
/*$
* @id formathtml
* @group FORMAT
* @requires template
* @configurable default
* @name _.formatHtml()
* @syntax _.formatHtml()
* @syntax _.formatHtml(template, object)
* @module UTIL
* Formats an object using a ##template#template## with HTML escaping for the output.
* The template syntax is shared with ##_.template(). Output in double curly braces is automatically escaped using ##_.escapeHtml().
* <var>formatHtml()</var> just creates a new template with HTML escaping and invokes it immediately.
* The template will be cached. Be careful when you create templates dynamically, as
* every template is cached and consumes memory.<br/>
* If you only want to format a single value, use ##_.formatValue().
*
* @example Format a name:
* <pre>var s = _.formatHtml("{{first}} {{last}}", {first: 'Tim', last: 'Taylor'});</pre>
*
* @example Format a list of dates:
* <pre>var s = _.formatHtml("{{each}}{{::yyyy-MM-dd}}{{/each}}", dateList);</pre>
*
* @param template The ##template#template## as a string. The template, once created, will be cached.
* @param object the object to format
* @return the string created by the template
*
* @see ##ht() works uses <var>formatHtml</var> to set element's innerHTML.
* @see ##HTML() create HTML nodes using <var>formatHtml</var>.
* @see ##_.template() creates a template function, using the same syntax.
* @see ##_.format() allows you to specify alternative escape mechanisms.
*/
'formatHtml': formatHtml
/*$
* @stop
*/
// @cond !format 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
/*$
* @id html
* @group ELEMENT
* @requires template ht
* @configurable default
* @name HTML()
* @syntax HTML(templateString, object...)
* @syntax HTML(templateFunction, object...)
* @syntax HTML(idSelector, object...)
* @module WEB
* Creates a ##list#list## of HTML nodes from the given HTML template. The list is compatible with ##add(), ##fill() and related methods.
* The template uses the ##template() syntax with ##escapeHtml() escaping for values.
*
* Please note that the function <var>HTML</var> will not be automatically exported by Minified. You should always import it
* using the recommended import statement:
* <pre>
* var MINI = require('minified'), $ = MINI.$, $$ = MINI.$$, EE = MINI.EE, <strong>HTML = MINI.HTML</strong>;
* </pre>
*
* @example Creating a HTML element showing a number:
* <pre>
* <div id="price">-</div>
* </pre>
* Then the price can be set like this:
* <pre>
* var price = 14.9;
* $('#price').fill(HTML('<b>${{::0.99}}</b>', price));
* </pre>
* Results in:
* <pre>
* <div id="price"><b>$14.90</b></div>
* </pre>
*
* @example Adding elements to an existing list:
* <pre>
* var names = [ {first: 'James', last: 'Sullivan'},
* {first: 'Michael', last: 'Wazowski'} ];
* $('#list').add(HTML('{{each}}<li>{{this.first}} {{this.last}}</li>{{/each}}', names);
* </pre>
* The code adds this to #list:
* <pre>
* <li>James Sullivan<li><li>Michael Wazowski</li>
* </pre>
*
* @example You can store templates in <script> tags. First you need to create a <script> tag with a type not
* supported by the browser and put your template in there, like this:
* <pre><script id="myTimeTpl" type="minified-template">The time is {{HH:mm:ss}}.</script></pre>
* Then you can specify the tag's id directly to access it:
* <pre>$('#timeDisplay').fill(HTML('#myTimeTpl', new Date()));</pre>
*
* @param templateString the template using ##template() syntax. Please note, because this is a template, you should
* avoid creating the template itself dynamically, as compiling templates is expensive and
* Minified will cache only a limited number of templates. Exception: If the template string does not use
* any template functionality (no {{}}), it does not need to be compiled and won't be cached.
* The template will use ##escapeHtml() as escape function, so all template substitutions will be HTML-escaped,
* unless you use triple curly-braces.
* @param templateFunction instead of a HTML template <var>HTML()</var> also accepts a template function, e.g. one
* created by ##template(). It will be invoked with the object as only argument.
* @param idSelector if you pass an ID CSS selector in the form "#myScript", Minified will recognize this and use the content
* of the specified <script> element as template. This allows you to put your template into
* a <script> tag with a non-JavaScript type (see example). Any string that starts with '#' and does not
* contain any spaces is used as selector.
* @param object optional one or more objects to pass to the template. If object is not set, the template is called with <var>undefined</var>
* as object. If exactly one object is given, it is passed directly to the template. If you specify more than one
* object, they are ##merge#merged##.
* @return the list containing the new HTML nodes
*
* @see ##ht() is a shortcut for <code>fill(HTML())</code>.
* @see ##EE() is a different way of creating HTML nodes.
*/
'HTML': function () {
var div = EE('div');
return _(call(div['ht'], div, arguments)[0].childNodes);
},
/*$
* @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 <var>_()</var> and <var>$()</var>
* is that <var>$()</var> will automatically remove <var>null</var> values while <var>_()</var> will keep them.
*
* @example Creating an empty list:
* <pre>_()</pre>
*
* @example Creating a list with three items:
* <pre>_(1, 2, 3)</pre>
*
* @example Creating the same list, but by passing an array. One array level will be flattened:
* <pre>_([1, 2, 3])</pre>
*
* @example Creating a list containing the arrays [1, 2] and [3, 4].
* <pre>_([[1, 2], [3, 4]])</pre>
*
* @example Merging two lists:
* <pre>var a = _("a", "b", "c");
* var b = _("x", "y", "z");
* var merged = _(a, b); // contains _("a", "b", "c", "x", "y", "z")
* </pre>
*
* @example Adding two elements to a list:
* <pre>var a = _(1, 2, 3);
* var a4 = _(a, 4); // contains _(1, 2, 3, 4)
* </pre>
*
* @example Mixing different list types and single elements:
* <pre>_(1, [], [2, 3], _(), _(4, 5)); // same content as _(1, 2, 3, 4, 5)</pre>
*
* @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. <var>$()</var> 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 <var>$()</var> 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 <var>$()</var> 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 <var>$()</var>. 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 <var>$()</var>, 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.
* <pre>
* var l0 = $('#myElementId');
* </pre>
*
* @example You can pass an object reference to create a list containing only this element:
* <pre>
* var l1 = $(document.getElementById('myElementId'));
* </pre>
*
* @example Lists and arrays will be copied:
* <pre>
* var l2 = $([elementA, elementB, elementC]);
* </pre>
*
* @example Lists will be automatically flattened and nulls removed. So this list <var>l3</var> has the same content as <var>l2</var>:
* <pre>
* var l3 = $([elementA, [elementB, null, elementC], null]);
* </pre>
*
* @example This is a simple selector to find all elements with the given class.
* <pre>
* var l4 = $('.myClass');
* </pre>
*
* @example A selector to find all elements of the given type.
* <pre>
* var l5 = $('input'); // finds all input elements
* </pre>
*
* @example A selector to find all elements with the given type and class.
* <pre>
* var l6 = $('input.myRadio'); // finds all input elements with class 'myRadio'
* </pre>
*
* @example A selector to find all elements that are descendants of the given element.
* <pre>
* var l7 = $('#myForm input'); // finds all input elements contained in the element myForm
* </pre>
*
* @example A selector to find all elements that have either a CSS class 'a' or class 'b':
* <pre>
* var l8 = $('.a, .b'); // finds all elements that have class a or class b
* </pre>
*
* @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:
* <pre>
* var l9 = $('#myDivision .myForm input');
* </pre>
*
* @example Contexts can make it easier to specify ancestors:
* <pre>
* var l10 = $('.myRadio', '#formA, #formB, #formC');
* </pre>
* The result is identical to:
* <pre>
* var l10 = $('#formA .myRadio, #formB .myRadio, #formC .myRadio');
* </pre>
*
* @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.
* <pre>
* $('#myElementId').set('$color', 'red');
* </pre>
*
* @example Most list methods return the list you invoked them on, allowing you to chain them:
* <pre>
* $('#myForm .myRadio').addClass('uncheckedRadio')
* .set('checked', true)
* .on('click', function() {
* $(this).set({@: 'uncheckedRadio');
* });
* </pre>
*
* @example Using $() as a #ready#$.ready() shortcut:
* <pre>
* $(function() {
* // in here you can safely work with the HTML document
* });
* </pre>
*
* @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 <var>length</var> 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 <var>$()</var>, but returns the resulting list's first element.
*/
'$': $,
/*$
* @id dollardollar
* @group SELECTORS
* @requires
* @configurable default
* @name $$()
* @syntax $(selector)
* @syntax $(selector, context)
* @syntax $(selector, context, childOnly)
* @shortcut $$() - It is recommended that you assign MINI.$$ to a variable $$.
* @module WEB
* Returns a DOM object containing the first match of the given selector, or <var>undefined</var> if no match was found.
* <var>$$</var> allows you to easily access an element directly. It is the equivalent to writing <code>$(selector)[0]</code>.
*
* Please note that the function <var>$$</var> will not be automatically exported by Minified. You should always import it
* using the recommended import statement:
* <pre>
* var MINI = require('minified'), $ = MINI.$, $$ = MINI.$$, EE = MINI.EE;
* </pre>
*
* @example Select the checkbox 'myCheckbox':
* <pre>
* $$('#myCheckbox').checked = true;
* </pre>
*
* @param selector a simple, CSS-like selector for the element. Uses the same syntax as #dollar#$(). The most common
* parameter for this function is the id selector with the syntax "#id".
* @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 a DOM object of the first match, or <var>undefined</var> if the selector did not return at least one match
*
* @see ##dollar#$()## creates a list using the selector, instead of returning only the first result.
*/
'$$': $$,
/*$
* @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 <var>M</var>:
* <pre>
* MINI.M.prototype.printLength = function() { console.log(this.length); };
* </pre>
*/
'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 <var>get()</var>
* 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 <var>getters</var> by a new map, but must always modify the existing map.
*
* The function's signature is <code>function(list, name)</code> where
* <dl><dt>list</dt><dd>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 <var>undefined</var> in
* all other case).</dd>
* <dt>name</dt><dd>The name of the property. That's the part AFTER the prefix.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>The value to return to the user.</dd></dl>
*
* @example Adding a shortcut '||' for accessing border style properties:
* <pre>
* 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'
* </pre>
*
* @example Adding XLink attribute support to get(). This is useful if you work with SVG. The prefix is '>'.
* <pre>
* MINI.getter['>'] = function(list, name) {
* return list[0].getAttributeNS('http://www.w3.org/1999/xlink', name);
* };
*
* var xlinkHref = $('#svgLink').get('>href');
* </pre>
*/
'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 <var>set()</var>
* 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 <var>setters</var> by a new map, but must always modify the existing map.
*
* The function's signature is <code>function(list, name, value)</code> where
* <dl><dt>list</dt><dd>Is the Minified list to use.</dd>
* <dt>name</dt><dd>The name of the property. That's the part AFTER the prefix.</dd>
* <dt>value</dt><dd>Either the value to set, or a callback function to create the value that you must call for each
* value (see ##set() ).</dd>
* </dl>
*
* 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.
* <pre>
* 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)
* </pre>
*
* @example Adding XLink attribute support to set(). This is useful if you work with SVG. The prefix is '>'.
* <pre>
* 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/');
* </pre>
*/
'setter': setter
/*$
* @stop
*/
///#/snippet webExports
};
///#snippet commonAmdEnd
});
///#/snippet commonAmdEnd
///#snippet webDocs
/*$
* @id list
* @name Minified Lists
* @module WEB, UTIL
*
* <i>Minified lists</i> are Array-like objects provided by Minified. Like a regular JavaScript array,
* they provide a <var>length</var> property and you can access their content using the index operator (<code>a[5]</code>).
* 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#$()</a></code> function or with the Util module's
* #underscore#_()</a></code> 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
*
* <i>Promises</i> 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 <a href="http://promises-aplus.github.io/promises-spec/">Promises/A+</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).<br/>
* 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 <var>then()</var>:
* <pre>
* $.request('get', 'http://example.com/weather?zip=90210')
* .then(function success(result) {
* alert('The weather is ' + result);
* }, function error(exception) {
* alert('Something went wrong');
* });
* </pre>
*
* What makes Promises so special is that ##then() itself returns a new Promise, which is based on the Promise <var>then()</var> was called on, but can be
* modified by the outcome of callbacks. Both arguments to <var>then()</var> are optional, and you can also write the code like this:
* <pre>
* $.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');
* });
* </pre>
*
* Because the first ##then() returns a new Promise based on the original Promise, the second <var>then()</var> 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 <var>then()</var>. 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 <var>null</var> as first argument:
* <pre>
* $.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');
* });
* </pre>
*
* 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 <var>then()</var> 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:
* <pre>
* $.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');
* });
* </pre>
*
* 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 <code>fire()</code>
* that needs to be called when the promise result is ready. It requires two arguments.
* The first is a boolean, <var>true</var> for a successful operation and <var>false</var> 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.
*
* <pre>
* function timeout(durationMs) {
* var p = _.promise();
* setTimeout(function() { p.fire(true, [durationMs]); }, durationMs);
* return p;
* }
* </pre>
* Call it like this:
* <pre>
* timeout(1000).then(function(ms) { window.alert(ms+ ' milliseconds have passed.'); });
* </pre>
*
* <h3>Limited Promises Implementation in Web module</h3>
* 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:
* <ol><li>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.</li>
* <li>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.</li></ol>
*/
/*$
* @stop
*/
///#/snippet webDocs