From c9f5c056862553d5102d1dfb7d964ea449573d59 Mon Sep 17 00:00:00 2001 From: ewinslow Date: Sun, 14 Nov 2010 11:33:29 +0000 Subject: Refs #2538: Added vsprintf support to elgg.echo. Added unit tests for normalize_url, added prototype definitions for Array#forEach for compatibility with IE. git-svn-id: http://code.elgg.org/elgg/trunk@7313 36083f99-b078-4883-b0ff-0f9b5a30f544 --- js/classes/ElggPriorityList.js | 35 +++---- js/lib/elgglib.js | 134 ++++++++++++------------- js/lib/events.js | 22 ++--- js/lib/languages.js | 51 +++++----- js/lib/prototypes.js | 44 +++++++++ js/tests/ElggEventsTest.js | 8 +- js/tests/ElggLibTest.js | 78 +++++++-------- js/tests/jsTestDriver.conf | 1 + vendors/sprintf.js | 183 +++++++++++++++++++++++++++++++++++ views/default/js/initialise_elgg.php | 16 ++- 10 files changed, 401 insertions(+), 171 deletions(-) create mode 100644 js/lib/prototypes.js create mode 100644 vendors/sprintf.js diff --git a/js/classes/ElggPriorityList.js b/js/classes/ElggPriorityList.js index 324b07cac..7b5d16473 100644 --- a/js/classes/ElggPriorityList.js +++ b/js/classes/ElggPriorityList.js @@ -28,14 +28,15 @@ elgg.ElggPriorityList.prototype.insert = function(obj, opt_priority) { elgg.ElggPriorityList.prototype.forEach = function(callback) { elgg.assertTypeOf('function', callback); - var index = 0, p, i, elems; - for (p in this.priorities_) { - elems = this.priorities_[p]; - for (i in elems) { - callback(elems[i], index); - index++; - } - } + var index = 0; + + this.priorities_.forEach(function(elems) { + elems.forEach(function(elem) { + callback(elem, index++); + }); + }); + + return this; }; /** @@ -44,19 +45,13 @@ elgg.ElggPriorityList.prototype.forEach = function(callback) { elgg.ElggPriorityList.prototype.every = function(callback) { elgg.assertTypeOf('function', callback); - var index = 0, p, elems, i; + var index = 0; - for (p in this.priorities_) { - elems = this.priorities_[p]; - for (i in elems) { - if (!callback(elems[i], index)) { - return false; - } - index++; - } - } - - return true; + return this.priorities_.every(function(elems) { + return elems.every(function(elem) { + return callback(elem, index++); + }); + }); }; /** diff --git a/js/lib/elgglib.js b/js/lib/elgglib.js index a8ab2020c..78a863803 100644 --- a/js/lib/elgglib.js +++ b/js/lib/elgglib.js @@ -5,7 +5,7 @@ var elgg = elgg || {}; /** * Pointer to the global context - * + * * @see elgg.require * @see elgg.provide */ @@ -13,55 +13,60 @@ elgg.global = this; /** * Convenience reference to an empty function. - * + * * Save memory by not generating multiple empty functions. */ elgg.nullFunction = function() {}; /** - * + * This forces an inheriting class to implement the method or + * it will throw an error. + * * @example * AbstractClass.prototype.toBeImplemented = elgg.abstractMethod; - * - * Now this forces an inheriting class to implement the method or - * it will throw an error. */ elgg.abstractMethod = function() { throw new Error("Oops... you forgot to implement an abstract method!"); }; /** - * Check if the value is an array. - * + * Check if the value is an array. + * * No sense in reinventing the wheel! - * + * + * @param {*} val + * * @return boolean */ elgg.isArray = jQuery.isArray; /** - * Check if the value is a function. - * + * Check if the value is a function. + * * No sense in reinventing the wheel! - * + * + * @param {*} val + * * @return boolean */ elgg.isFunction = jQuery.isFunction; /** * Check if the value is a "plain" object (i.e., created by {} or new Object()) - * + * * No sense in reinventing the wheel! - * + * + * @param {*} val + * * @return boolean */ elgg.isPlainObject = jQuery.isPlainObject; /** * Check if the value is a string - * + * * @param {*} val - * + * * @return boolean */ elgg.isString = function(val) { @@ -70,9 +75,9 @@ elgg.isString = function(val) { /** * Check if the value is a number - * + * * @param {*} val - * + * * @return boolean */ elgg.isNumber = function(val) { @@ -81,12 +86,12 @@ elgg.isNumber = function(val) { /** * Check if the value is an object - * + * * @note This returns true for functions and arrays! If you want to return true only * for "plain" objects (created using {} or new Object()) use elgg.isPlainObject. - * + * * @param {*} val - * + * * @return boolean */ elgg.isObject = function(val) { @@ -95,9 +100,9 @@ elgg.isObject = function(val) { /** * Check if the value is undefined - * + * * @param {*} val - * + * * @return boolean */ elgg.isUndefined = function(val) { @@ -106,9 +111,9 @@ elgg.isUndefined = function(val) { /** * Check if the value is null - * + * * @param {*} val - * + * * @return boolean */ elgg.isNull = function(val) { @@ -117,9 +122,9 @@ elgg.isNull = function(val) { /** * Check if the value is either null or undefined - * + * * @param {*} val - * + * * @return boolean */ elgg.isNullOrUndefined = function(val) { @@ -128,25 +133,25 @@ elgg.isNullOrUndefined = function(val) { /** * Throw an exception of the type doesn't match - * + * * @todo Might be more appropriate for debug mode only? */ elgg.assertTypeOf = function(type, val) { if (typeof val !== type) { - throw new TypeError("Expecting param of " + - arguments.caller + "to be a(n) " + type + "." + - " Was actually a(n) " + typeof val + "."); + throw new TypeError("Expecting param of " + + arguments.caller + "to be a(n) " + type + "." + + " Was actually a(n) " + typeof val + "."); } }; /** * Throw an error if the required package isn't present - * + * * @param {String} pkg The required package (e.g., 'elgg.package') */ elgg.require = function(pkg) { elgg.assertTypeOf('string', pkg); - + var parts = pkg.split('.'), cur = elgg.global, part, i; @@ -162,31 +167,31 @@ elgg.require = function(pkg) { /** * Generate the skeleton for a package. - * + * *
  * elgg.provide('elgg.package.subpackage');
  * 
- * + * * is equivalent to - * + * *
  * elgg = elgg || {};
  * elgg.package = elgg.package || {};
  * elgg.package.subpackage = elgg.package.subpackage || {};
  * 
- * + * * @example elgg.provide('elgg.config.translations') - * + * * @param {string} pkg The package name. */ elgg.provide = function(pkg, opt_context) { elgg.assertTypeOf('string', pkg); - + var parts = pkg.split('.'), - context = opt_context || elgg.global, - part, i; - - + context = opt_context || elgg.global, + part, i; + + for (i = 0; i < parts.length; i += 1) { part = parts[i]; context[part] = context[part] || {}; @@ -196,11 +201,11 @@ elgg.provide = function(pkg, opt_context) { /** * Inherit the prototype methods from one constructor into another. - * + * * @example *
  * function ParentClass(a, b) { }
- * 
+ *
  * ParentClass.prototype.foo = function(a) { alert(a); }
  *
  * function ChildClass(a, b, c) {
@@ -224,7 +229,7 @@ elgg.inherit = function(Child, Parent) {
 
 /**
  * Prepend elgg.config.wwwroot to a url if the url doesn't already have it.
- * 
+ *
  * @param {String} url The url to extend
  * @return {String} The extended url
  * @private
@@ -232,18 +237,18 @@ elgg.inherit = function(Child, Parent) {
 elgg.normalize_url = function(url) {
 	url = url || '';
 	elgg.assertTypeOf('string', url);
-	
+
 	// jslint complains if you use /regexp/ shorthand here... ?!?!
 	if ((new RegExp("^(https?:)?//")).test(url)) {
 		return url;
 	}
-	
-	return elgg.config.wwwroot + url;
+
+	return elgg.config.wwwroot + url.ltrim('/');
 };
 
 /**
  * Displays system messages via javascript rather than php.
- * 
+ *
  * @param {String} msgs The message we want to display
  * @param {Number} delay The amount of time to display the message in milliseconds. Defaults to 6 seconds.
  * @param {String} type The type of message (typically 'error' or 'message')
@@ -253,18 +258,19 @@ elgg.system_messages = function(msgs, delay, type) {
 	if (elgg.isUndefined(msgs)) {
 		return;
 	}
-	
-	var classes = [],
+
+	var classes = ['elgg_system_message', 'radius8'],
 		messages_html = [],
-		i;
-	
-	//validate delay.  Must be a positive integer. 
-	delay = parseInt(delay, 10);
+		appendMessage = function(msg) {
+			messages_html.push('

' + msg + '

'); + }, i; + + //validate delay. Must be a positive integer. + delay = parseInt(delay || 6000, 10); if (isNaN(delay) || delay <= 0) { delay = 6000; } - - classes = ['elgg_system_message', 'radius8']; + if (type === 'error') { classes.push('messages_error'); } @@ -273,13 +279,11 @@ elgg.system_messages = function(msgs, delay, type) { if (!elgg.isArray(msgs)) { msgs = [msgs]; } - - for (i in msgs) { - messages_html.push('

' + msgs[i] + '

'); - } - + + msgs.forEach(appendMessage); + $(messages_html.join('')).appendTo('#elgg_system_messages') - .animate({opacity: '1.0'}, delay).fadeOut('slow'); + .animate({opacity: '1.0'}, delay).fadeOut('slow'); }; /** @@ -303,7 +307,7 @@ elgg.register_error = function(errors, delay) { /** * Meant to mimic the php forward() function by simply redirecting the * user to another page. - * + * * @param {String} url The url to forward to */ elgg.forward = function(url) { diff --git a/js/lib/events.js b/js/lib/events.js index ad05a9888..c1aa6fd9a 100644 --- a/js/lib/events.js +++ b/js/lib/events.js @@ -1,22 +1,22 @@ elgg.provide('elgg.config.events'); /** - * + * */ elgg.register_event_handler = function(event_name, event_type, handler, priority) { elgg.assertTypeOf('string', event_name); elgg.assertTypeOf('string', event_type); elgg.assertTypeOf('function', handler); - + if (!event_name || !event_type) { return false; } - + var events = elgg.config.events; - + elgg.provide(event_name + '.' + event_type, events); - + if (!(events[event_name][event_type] instanceof elgg.ElggPriorityList)) { events[event_name][event_type] = new elgg.ElggPriorityList(); } @@ -25,22 +25,22 @@ elgg.register_event_handler = function(event_name, event_type, handler, priority }; /** - * + * */ elgg.trigger_event = function(event_name, event_type, opt_object) { elgg.assertTypeOf('string', event_name); elgg.assertTypeOf('string', event_type); var events = elgg.config.events, - callEventHandler = function(handler) { - return handler(event_name, event_type, opt_object) !== false; - } - + callEventHandler = function(handler) { + return handler(event_name, event_type, opt_object) !== false; + }; + elgg.provide(event_name + '.' + event_type, events); elgg.provide('all.' + event_type, events); elgg.provide(event_name + '.all', events); elgg.provide('all.all', events); - + return [ events[event_name][event_type], events['all'][event_type], diff --git a/js/lib/languages.js b/js/lib/languages.js index 640764282..82cfa7a01 100644 --- a/js/lib/languages.js +++ b/js/lib/languages.js @@ -1,3 +1,4 @@ +/*globals vsprintf*/ /** * Provides language-related functionality */ @@ -7,13 +8,13 @@ elgg.config.language = 'en'; elgg.add_translation = function(lang, translations) { elgg.provide('elgg.config.translations.' + lang); - + $.extend(elgg.config.translations[lang], translations); }; /** * Load the translations for the given language. - * + * * If no language is specified, the default language is used. * @param {string} language * @return {XMLHttpRequest} @@ -38,41 +39,43 @@ elgg.reload_all_translations = function(language) { */ elgg.get_language = function() { var user = elgg.get_loggedin_user(); - + if (user && user.language) { return user.language; } - + return elgg.config.language; }; /** * Translates a string - * - * @param {String} key The string to translate + * + * @param {String} key The string to translate + * @param {Array} argv vsprintf support * @param {String} language The language to display it in + * * @return {String} The translation */ -elgg.echo = function(key, language) { - var translations, - dlang = elgg.get_language(); - - language = language || dlang; - - translations = elgg.config.translations[language]; - if (translations && translations[key]) { - return translations[key]; - } - - if (language === dlang) { - return undefined; +elgg.echo = function(key, argv, language) { + //elgg.echo('str', 'en') + if (elgg.isString(argv)) { + language = argv; + argv = []; } - - translations = elgg.config.translations[dlang]; - if (translations && translations[key]) { - return translations[key]; + + //elgg.echo('str', [...], 'en') + var translations = elgg.config.translations, + dlang = elgg.get_language(), + map; + + language = language || dlang; + argv = argv || []; + + map = translations[language] || translations[dlang]; + if (map && map[key]) { + return vsprintf(map[key], argv); } - + return undefined; }; diff --git a/js/lib/prototypes.js b/js/lib/prototypes.js new file mode 100644 index 000000000..0f0014818 --- /dev/null +++ b/js/lib/prototypes.js @@ -0,0 +1,44 @@ +/** + * + */ +if (!Array.prototype.every) { + Array.prototype.every = function(callback) { + var len = this.length, i; + + for (i = 0; i < len; i++) { + if (i in this && !callback.call(null, this[i], i)) { + return false; + } + } + + return true; + }; +} + +/** + * + */ +if (!Array.prototype.forEach) { + Array.prototype.forEach = function(callback) { + var len = this.length, i; + + for (i = 0; i < len; i++) { + if (i in this) { + callback.call(null, this[i], i); + } + } + }; +} + +/** + * + */ +if (!String.prototype.ltrim) { + String.prototype.ltrim = function(str) { + if (this.indexOf(str) === 0) { + return this.substring(str.length); + } else { + return this; + } + }; +} \ No newline at end of file diff --git a/js/tests/ElggEventsTest.js b/js/tests/ElggEventsTest.js index 1fc9c8e86..4765878cf 100644 --- a/js/tests/ElggEventsTest.js +++ b/js/tests/ElggEventsTest.js @@ -11,7 +11,7 @@ ElggEventsTest.prototype.testEventHandlersMustBeFunctions = function () { ElggEventsTest.prototype.testReturnValueDefaultsToTrue = function () { assertTrue(elgg.trigger_event('fee', 'fum')); - + elgg.register_event_handler('fee', 'fum', elgg.nullFunction); assertTrue(elgg.trigger_event('fee', 'fum')); }; @@ -19,10 +19,10 @@ ElggEventsTest.prototype.testReturnValueDefaultsToTrue = function () { ElggEventsTest.prototype.testCanGlomEventsWithAll = function () { elgg.register_event_handler('all', 'bar', elgg.abstractMethod); assertException("all,bar", function() { elgg.trigger_event('foo', 'bar'); }); - + elgg.register_event_handler('foo', 'all', elgg.abstractMethod); assertException("foo,all", function() { elgg.trigger_event('foo', 'baz'); }); - - elgg.register_event_handler('all', 'all', elgg.abstractMethod); + + elgg.register_event_handler('all', 'all', elgg.abstractMethod); assertException("all,all", function() { elgg.trigger_event('pinky', 'winky'); }); }; \ No newline at end of file diff --git a/js/tests/ElggLibTest.js b/js/tests/ElggLibTest.js index e810a47fb..132ad986a 100644 --- a/js/tests/ElggLibTest.js +++ b/js/tests/ElggLibTest.js @@ -8,50 +8,42 @@ ElggLibTest.prototype.testGlobal = function() { }; ElggLibTest.prototype.testAssertTypeOf = function() { - var noexceptions = [ + [//Valid inputs ['string', ''], ['object', {}], - ['boolean', true], - ['boolean', false], - ['undefined', undefined], - ['number', 0], - ['function', elgg.nullFunction], - ]; - - for (var i in noexceptions) { - assertNoException(function() { - elgg.assertTypeOf.apply(elgg, noexceptions[i]); + ['boolean', true], + ['boolean', false], + ['undefined', undefined], + ['number', 0], + ['function', elgg.nullFunction] + ].forEach(function(args) { + assertNoException(function() { + elgg.assertTypeOf.apply(undefined, args); }); - } - - var exceptions = [ + }); + + [//Invalid inputs ['function', {}], - ['object', elgg.nullFunction], - ]; - - for (var i in exceptions) { - assertException(function() { - elgg.assertTypeOf.apply(elgg, exceptions[i]); + ['object', elgg.nullFunction] + ].forEach(function() { + assertException(function(args) { + elgg.assertTypeOf.apply(undefined, args); }); - } + }); }; -ElggLibTest.prototype.testProvide = function() { +ElggLibTest.prototype.testProvideDoesntClobber = function() { elgg.provide('foo.bar.baz'); - - assertNotUndefined(foo); - assertNotUndefined(foo.bar); - assertNotUndefined(foo.bar.baz); - - var str = foo.bar.baz.oof = "don't overwrite me"; - + + foo.bar.baz.oof = "test"; + elgg.provide('foo.bar.baz'); - - assertEquals(str, foo.bar.baz.oof); + + assertEquals("test", foo.bar.baz.oof); }; /** - * Try requiring bogus input + * Try requiring bogus input */ ElggLibTest.prototype.testRequire = function () { assertException(function(){ elgg.require(''); }); @@ -69,24 +61,24 @@ ElggLibTest.prototype.testRequire = function () { ElggLibTest.prototype.testInherit = function () { function Base() {} function Child() {} - + elgg.inherit(Child, Base); - + assertInstanceOf(Base, new Child()); assertEquals(Child, Child.prototype.constructor); }; ElggLibTest.prototype.testNormalizeUrl = function() { elgg.config.wwwroot = "http://elgg.org/"; - - var inputs = [ - [elgg.config.wwwroot, ''], - [elgg.config.wwwroot + 'pg/test', 'pg/test'], + + [ + ['', elgg.config.wwwroot], + ['pg/test', elgg.config.wwwroot + 'pg/test'], ['http://google.com', 'http://google.com'], ['//example.com', '//example.com'], - ]; - - for (var i in inputs) { - assertEquals(inputs[i][0], elgg.normalize_url(inputs[i][1])); - } + ['/pg/page', elgg.config.wwwroot + 'pg/page'], + ['mod/plugin/index.php', elgg.config.wwwroot + 'mod/plugin/index.php'], + ].forEach(function(args) { + assertEquals(args[1], elgg.normalize_url(args[0])); + }); }; \ No newline at end of file diff --git a/js/tests/jsTestDriver.conf b/js/tests/jsTestDriver.conf index 2f732da7b..606487c03 100644 --- a/js/tests/jsTestDriver.conf +++ b/js/tests/jsTestDriver.conf @@ -2,6 +2,7 @@ server: http://localhost:42442 load: - vendors/jquery/jquery-1.4.2.min.js + - vendors/sprintf.js - js/lib/elgglib.js - js/classes/*.js - js/lib/*.js diff --git a/vendors/sprintf.js b/vendors/sprintf.js new file mode 100644 index 000000000..0e8d02c98 --- /dev/null +++ b/vendors/sprintf.js @@ -0,0 +1,183 @@ +/** +sprintf() for JavaScript 0.7-beta1 +http://www.diveintojavascript.com/projects/javascript-sprintf + +Copyright (c) Alexandru Marasteanu +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of sprintf() for JavaScript nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Changelog: +2010.09.06 - 0.7-beta1 + - features: vsprintf, support for named placeholders + - enhancements: format cache, reduced global namespace pollution + +2010.05.22 - 0.6: + - reverted to 0.4 and fixed the bug regarding the sign of the number 0 + Note: + Thanks to Raphael Pigulla (http://www.n3rd.org/) + who warned me about a bug in 0.5, I discovered that the last update was + a regress. I appologize for that. + +2010.05.09 - 0.5: + - bug fix: 0 is now preceeded with a + sign + - bug fix: the sign was not at the right position on padded results (Kamal Abdali) + - switched from GPL to BSD license + +2007.10.21 - 0.4: + - unit test and patch (David Baird) + +2007.09.17 - 0.3: + - bug fix: no longer throws exception on empty paramenters (Hans Pufal) + +2007.09.11 - 0.2: + - feature: added argument swapping + +2007.04.03 - 0.1: + - initial release +**/ + +var sprintf = (function() { + function get_type(variable) { + return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); + } + function str_repeat(input, multiplier) { + for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} + return output.join(''); + } + + var str_format = function() { + if (!str_format.cache.hasOwnProperty(arguments[0])) { + str_format.cache[arguments[0]] = str_format.parse(arguments[0]); + } + return str_format.format.call(null, str_format.cache[arguments[0]], arguments); + }; + + str_format.format = function(parse_tree, argv) { + var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; + for (i = 0; i < tree_length; i++) { + node_type = get_type(parse_tree[i]); + if (node_type === 'string') { + output.push(parse_tree[i]); + } + else if (node_type === 'array') { + match = parse_tree[i]; // convenience purposes only + if (match[2]) { // keyword argument + arg = argv[cursor]; + for (k = 0; k < match[2].length; k++) { + if (!arg.hasOwnProperty(match[2][k])) { + throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); + } + arg = arg[match[2][k]]; + } + } + else if (match[1]) { // positional argument (explicit) + arg = argv[match[1]]; + } + else { // positional argument (implicit) + arg = argv[cursor++]; + } + + if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { + throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); + } + switch (match[8]) { + case 'b': arg = arg.toString(2); break; + case 'c': arg = String.fromCharCode(arg); break; + case 'd': arg = parseInt(arg, 10); break; + case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; + case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; + case 'o': arg = arg.toString(8); break; + case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; + case 'u': arg = Math.abs(arg); break; + case 'x': arg = arg.toString(16); break; + case 'X': arg = arg.toString(16).toUpperCase(); break; + } + arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); + pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; + pad_length = match[6] - String(arg).length; + pad = match[6] ? str_repeat(pad_character, pad_length) : ''; + output.push(match[5] ? arg + pad : pad + arg); + } + } + return output.join(''); + }; + + str_format.cache = {}; + + str_format.parse = function(fmt) { + var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; + while (_fmt) { + if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { + parse_tree.push(match[0]); + } + else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { + parse_tree.push('%'); + } + else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { + if (match[2]) { + arg_names |= 1; + var field_list = [], replacement_field = match[2], field_match = []; + if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { + if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { + field_list.push(field_match[1]); + } + else { + throw('[sprintf] huh?'); + } + } + } + else { + throw('[sprintf] huh?'); + } + match[2] = field_list; + } + else { + arg_names |= 2; + } + if (arg_names === 3) { + throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); + } + parse_tree.push(match); + } + else { + throw('[sprintf] huh?'); + } + _fmt = _fmt.substring(match[0].length); + } + return parse_tree; + }; + + return str_format; +})(); + +var vsprintf = function(fmt, argv) { + argv.unshift(fmt); + return sprintf.apply(null, argv); +}; diff --git a/views/default/js/initialise_elgg.php b/views/default/js/initialise_elgg.php index 3de1c020b..49c12e30c 100644 --- a/views/default/js/initialise_elgg.php +++ b/views/default/js/initialise_elgg.php @@ -4,7 +4,14 @@ */ global $CONFIG; -include("{$CONFIG->path}js/lib/elgglib.js"); +$prereq_files = array( + "vendors/sprintf.js", + "js/lib/elgglib.js", +); + +foreach ($prereq_files as $file) { + include("{$CONFIG->path}$file"); +} //No such thing as autoloading classes in javascript $model_files = array( @@ -13,13 +20,14 @@ $model_files = array( 'ElggPriorityList', ); -foreach($model_files as $file) { +foreach ($model_files as $file) { include("{$CONFIG->path}js/classes/$file.js"); } //Include library files $libs = array( //libraries + 'prototypes', 'events', 'security', 'languages', @@ -31,7 +39,7 @@ $libs = array( 'ui.widgets', ); -foreach($libs as $file) { +foreach ($libs as $file) { include("{$CONFIG->path}js/lib/$file.js"); } @@ -43,7 +51,7 @@ foreach($libs as $file) { elgg.version = ''; elgg.release = ''; elgg.config.wwwroot = ''; -elgg.security.interval = 5 * 60 * 1000; +elgg.security.interval = 5 * 60 * 1000; //Mimic PHP engine boot process -- cgit v1.2.3