UNPKG

pebble-clay

Version:

Pebble Config Framework

1,382 lines (1,272 loc) 160 kB
// 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 ##th