]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Refs #2538: Added vsprintf support to elgg.echo. Added unit tests for normalize_url...
authorewinslow <ewinslow@36083f99-b078-4883-b0ff-0f9b5a30f544>
Sun, 14 Nov 2010 11:33:29 +0000 (11:33 +0000)
committerewinslow <ewinslow@36083f99-b078-4883-b0ff-0f9b5a30f544>
Sun, 14 Nov 2010 11:33:29 +0000 (11:33 +0000)
git-svn-id: http://code.elgg.org/elgg/trunk@7313 36083f99-b078-4883-b0ff-0f9b5a30f544

js/classes/ElggPriorityList.js
js/lib/elgglib.js
js/lib/events.js
js/lib/languages.js
js/lib/prototypes.js [new file with mode: 0644]
js/tests/ElggEventsTest.js
js/tests/ElggLibTest.js
js/tests/jsTestDriver.conf
vendors/sprintf.js [new file with mode: 0644]
views/default/js/initialise_elgg.php

index 324b07cac77351eba7aaf1c4a74f0e9a7c3f999f..7b5d164737097fb8c2df47cc53dc923f048cf13c 100644 (file)
@@ -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++);
+               });
+       });
 };
 
 /**
index a8ab2020c138a25affd2fce10156b9ea860f239a..78a8638036aefda4e23899146af384a68c3353cb 100644 (file)
@@ -5,7 +5,7 @@ var elgg = elgg || {};
 \r
 /**\r
  * Pointer to the global context\r
- * \r
+ *\r
  * @see elgg.require\r
  * @see elgg.provide\r
  */\r
@@ -13,55 +13,60 @@ elgg.global = this;
 \r
 /**\r
  * Convenience reference to an empty function.\r
- * \r
+ *\r
  * Save memory by not generating multiple empty functions.\r
  */\r
 elgg.nullFunction = function() {};\r
 \r
 /**\r
- * \r
+ * This forces an inheriting class to implement the method or\r
+ * it will throw an error.\r
+ *\r
  * @example\r
  * AbstractClass.prototype.toBeImplemented = elgg.abstractMethod;\r
- * \r
- * Now this forces an inheriting class to implement the method or\r
- * it will throw an error.\r
  */\r
 elgg.abstractMethod = function() {\r
        throw new Error("Oops... you forgot to implement an abstract method!");\r
 };\r
 \r
 /**\r
- * Check if the value is an array.  \r
- * \r
+ * Check if the value is an array.\r
+ *\r
  * No sense in reinventing the wheel!\r
- * \r
+ *\r
+ * @param {*} val\r
+ *\r
  * @return boolean\r
  */\r
 elgg.isArray = jQuery.isArray;\r
 \r
 /**\r
- * Check if the value is a function.  \r
- * \r
+ * Check if the value is a function.\r
+ *\r
  * No sense in reinventing the wheel!\r
- * \r
+ *\r
+ * @param {*} val\r
+ *\r
  * @return boolean\r
  */\r
 elgg.isFunction = jQuery.isFunction;\r
 \r
 /**\r
  * Check if the value is a "plain" object (i.e., created by {} or new Object())\r
- * \r
+ *\r
  * No sense in reinventing the wheel!\r
- * \r
+ *\r
+ * @param {*} val\r
+ *\r
  * @return boolean\r
  */\r
 elgg.isPlainObject = jQuery.isPlainObject;\r
 \r
 /**\r
  * Check if the value is a string\r
- * \r
+ *\r
  * @param {*} val\r
- * \r
+ *\r
  * @return boolean\r
  */\r
 elgg.isString = function(val) {\r
@@ -70,9 +75,9 @@ elgg.isString = function(val) {
 \r
 /**\r
  * Check if the value is a number\r
- * \r
+ *\r
  * @param {*} val\r
- * \r
+ *\r
  * @return boolean\r
  */\r
 elgg.isNumber = function(val) {\r
@@ -81,12 +86,12 @@ elgg.isNumber = function(val) {
 \r
 /**\r
  * Check if the value is an object\r
- * \r
+ *\r
  * @note This returns true for functions and arrays!  If you want to return true only\r
  * for "plain" objects (created using {} or new Object()) use elgg.isPlainObject.\r
- * \r
+ *\r
  * @param {*} val\r
- * \r
+ *\r
  * @return boolean\r
  */\r
 elgg.isObject = function(val) {\r
@@ -95,9 +100,9 @@ elgg.isObject = function(val) {
 \r
 /**\r
  * Check if the value is undefined\r
- * \r
+ *\r
  * @param {*} val\r
- * \r
+ *\r
  * @return boolean\r
  */\r
 elgg.isUndefined = function(val) {\r
@@ -106,9 +111,9 @@ elgg.isUndefined = function(val) {
 \r
 /**\r
  * Check if the value is null\r
- * \r
+ *\r
  * @param {*} val\r
- * \r
+ *\r
  * @return boolean\r
  */\r
 elgg.isNull = function(val) {\r
@@ -117,9 +122,9 @@ elgg.isNull = function(val) {
 \r
 /**\r
  * Check if the value is either null or undefined\r
- * \r
+ *\r
  * @param {*} val\r
- * \r
+ *\r
  * @return boolean\r
  */\r
 elgg.isNullOrUndefined = function(val) {\r
@@ -128,25 +133,25 @@ elgg.isNullOrUndefined = function(val) {
 \r
 /**\r
  * Throw an exception of the type doesn't match\r
- * \r
+ *\r
  * @todo Might be more appropriate for debug mode only?\r
  */\r
 elgg.assertTypeOf = function(type, val) {\r
        if (typeof val !== type) {\r
-               throw new TypeError("Expecting param of " + \r
-                       arguments.caller + "to be a(n) " + type + "." + \r
-                       "  Was actually a(n) " + typeof val + ".");\r
+               throw new TypeError("Expecting param of " +\r
+                                   arguments.caller + "to be a(n) " + type + "." +\r
+                                   "  Was actually a(n) " + typeof val + ".");\r
        }\r
 };\r
 \r
 /**\r
  * Throw an error if the required package isn't present\r
- * \r
+ *\r
  * @param {String} pkg The required package (e.g., 'elgg.package')\r
  */\r
 elgg.require = function(pkg) {\r
        elgg.assertTypeOf('string', pkg);\r
-       \r
+\r
        var parts = pkg.split('.'),\r
                cur = elgg.global,\r
                part, i;\r
@@ -162,31 +167,31 @@ elgg.require = function(pkg) {
 \r
 /**\r
  * Generate the skeleton for a package.\r
- * \r
+ *\r
  * <pre>\r
  * elgg.provide('elgg.package.subpackage');\r
  * </pre>\r
- * \r
+ *\r
  * is equivalent to\r
- * \r
+ *\r
  * <pre>\r
  * elgg = elgg || {};\r
  * elgg.package = elgg.package || {};\r
  * elgg.package.subpackage = elgg.package.subpackage || {};\r
  * </pre>\r
- * \r
+ *\r
  * @example elgg.provide('elgg.config.translations')\r
- * \r
+ *\r
  * @param {string} pkg The package name.\r
  */\r
 elgg.provide = function(pkg, opt_context) {\r
        elgg.assertTypeOf('string', pkg);\r
-       \r
+\r
        var parts = pkg.split('.'),\r
-               context = opt_context || elgg.global,\r
-               part, i;\r
-       \r
-       \r
+       context = opt_context || elgg.global,\r
+       part, i;\r
+\r
+\r
        for (i = 0; i < parts.length; i += 1) {\r
                part = parts[i];\r
                context[part] = context[part] || {};\r
@@ -196,11 +201,11 @@ elgg.provide = function(pkg, opt_context) {
 \r
 /**\r
  * Inherit the prototype methods from one constructor into another.\r
- * \r
+ *\r
  * @example\r
  * <pre>\r
  * function ParentClass(a, b) { }\r
- * \r
+ *\r
  * ParentClass.prototype.foo = function(a) { alert(a); }\r
  *\r
  * function ChildClass(a, b, c) {\r
@@ -224,7 +229,7 @@ elgg.inherit = function(Child, Parent) {
 \r
 /**\r
  * Prepend elgg.config.wwwroot to a url if the url doesn't already have it.\r
- * \r
+ *\r
  * @param {String} url The url to extend\r
  * @return {String} The extended url\r
  * @private\r
@@ -232,18 +237,18 @@ elgg.inherit = function(Child, Parent) {
 elgg.normalize_url = function(url) {\r
        url = url || '';\r
        elgg.assertTypeOf('string', url);\r
-       \r
+\r
        // jslint complains if you use /regexp/ shorthand here... ?!?!\r
        if ((new RegExp("^(https?:)?//")).test(url)) {\r
                return url;\r
        }\r
-       \r
-       return elgg.config.wwwroot + url;\r
+\r
+       return elgg.config.wwwroot + url.ltrim('/');\r
 };\r
 \r
 /**\r
  * Displays system messages via javascript rather than php.\r
- * \r
+ *\r
  * @param {String} msgs The message we want to display\r
  * @param {Number} delay The amount of time to display the message in milliseconds. Defaults to 6 seconds.\r
  * @param {String} type The type of message (typically 'error' or 'message')\r
@@ -253,18 +258,19 @@ elgg.system_messages = function(msgs, delay, type) {
        if (elgg.isUndefined(msgs)) {\r
                return;\r
        }\r
-       \r
-       var classes = [],\r
+\r
+       var classes = ['elgg_system_message', 'radius8'],\r
                messages_html = [],\r
-               i;\r
-       \r
-       //validate delay.  Must be a positive integer. \r
-       delay = parseInt(delay, 10);\r
+               appendMessage = function(msg) {\r
+                       messages_html.push('<div class="' + classes.join(' ') + '"><p>' + msg + '</p></div>');\r
+               }, i;\r
+\r
+       //validate delay.  Must be a positive integer.\r
+       delay = parseInt(delay || 6000, 10);\r
        if (isNaN(delay) || delay <= 0) {\r
                delay = 6000;\r
        }\r
-       \r
-       classes = ['elgg_system_message', 'radius8'];\r
+\r
        if (type === 'error') {\r
                classes.push('messages_error');\r
        }\r
@@ -273,13 +279,11 @@ elgg.system_messages = function(msgs, delay, type) {
        if (!elgg.isArray(msgs)) {\r
                msgs = [msgs];\r
        }\r
-       \r
-       for (i in msgs) {\r
-               messages_html.push('<div class="' + classes.join(' ') + '"><p>' + msgs[i] + '</p></div>');\r
-       }\r
-       \r
+\r
+       msgs.forEach(appendMessage);\r
+\r
        $(messages_html.join('')).appendTo('#elgg_system_messages')\r
-           .animate({opacity: '1.0'}, delay).fadeOut('slow');\r
+               .animate({opacity: '1.0'}, delay).fadeOut('slow');\r
 };\r
 \r
 /**\r
@@ -303,7 +307,7 @@ elgg.register_error = function(errors, delay) {
 /**\r
  * Meant to mimic the php forward() function by simply redirecting the\r
  * user to another page.\r
- * \r
+ *\r
  * @param {String} url The url to forward to\r
  */\r
 elgg.forward = function(url) {\r
index ad05a988828d6501c6eacd723f46bd030ee05b4d..c1aa6fd9a402123aa7bb1c348efc352603008734 100644 (file)
@@ -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],
index 640764282638a3a21739493658d7a38b280232fb..82cfa7a01320b85ba869a79fa524d8bd29f03187 100644 (file)
@@ -1,3 +1,4 @@
+/*globals vsprintf*/\r
 /**\r
  * Provides language-related functionality\r
  */\r
@@ -7,13 +8,13 @@ elgg.config.language = 'en';
 \r
 elgg.add_translation = function(lang, translations) {\r
        elgg.provide('elgg.config.translations.' + lang);\r
-       \r
+\r
        $.extend(elgg.config.translations[lang], translations);\r
 };\r
 \r
 /**\r
  * Load the translations for the given language.\r
- * \r
+ *\r
  * If no language is specified, the default language is used.\r
  * @param {string} language\r
  * @return {XMLHttpRequest}\r
@@ -38,41 +39,43 @@ elgg.reload_all_translations = function(language) {
  */\r
 elgg.get_language = function() {\r
        var user = elgg.get_loggedin_user();\r
-       \r
+\r
        if (user && user.language) {\r
                return user.language;\r
        }\r
-       \r
+\r
        return elgg.config.language;\r
 };\r
 \r
 /**\r
  * Translates a string\r
- * \r
- * @param {String} key The string to translate\r
+ *\r
+ * @param {String} key      The string to translate\r
+ * @param {Array}  argv     vsprintf support\r
  * @param {String} language The language to display it in\r
+ *\r
  * @return {String} The translation\r
  */\r
-elgg.echo = function(key, language) {\r
-       var translations,\r
-               dlang = elgg.get_language();\r
-       \r
-       language = language || dlang;\r
-       \r
-       translations = elgg.config.translations[language];\r
-       if (translations && translations[key]) {\r
-               return translations[key];\r
-       }\r
-       \r
-       if (language === dlang) {\r
-               return undefined;\r
+elgg.echo = function(key, argv, language) {\r
+       //elgg.echo('str', 'en')\r
+       if (elgg.isString(argv)) {\r
+               language = argv;\r
+               argv = [];\r
        }\r
-       \r
-       translations = elgg.config.translations[dlang];\r
-       if (translations && translations[key]) {\r
-               return translations[key];\r
+\r
+       //elgg.echo('str', [...], 'en')\r
+       var translations = elgg.config.translations,\r
+               dlang = elgg.get_language(),\r
+               map;\r
+\r
+       language = language || dlang;\r
+       argv = argv || [];\r
+\r
+       map = translations[language] || translations[dlang];\r
+       if (map && map[key]) {\r
+               return vsprintf(map[key], argv);\r
        }\r
-       \r
+\r
        return undefined;\r
 };\r
 \r
diff --git a/js/lib/prototypes.js b/js/lib/prototypes.js
new file mode 100644 (file)
index 0000000..0f00148
--- /dev/null
@@ -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
index 1fc9c8e868461239e90173d40d0f63f1401b01a2..4765878cfe6fa59d0d0292a294520cba2196abbf 100644 (file)
@@ -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
index e810a47fb782870c4c525fd160a31220e5d694df..132ad986a51c42483cbaf262cce913d0a39aa3a3 100644 (file)
@@ -8,50 +8,42 @@ ElggLibTest.prototype.testGlobal = function() {
 };\r
 \r
 ElggLibTest.prototype.testAssertTypeOf = function() {\r
-       var noexceptions = [\r
+       [//Valid inputs\r
            ['string', ''],\r
         ['object', {}],\r
-        ['boolean', true],          \r
-        ['boolean', false],         \r
-        ['undefined', undefined],   \r
-        ['number', 0],             \r
-        ['function', elgg.nullFunction],\r
-    ];\r
-       \r
-       for (var i in noexceptions) {\r
-               assertNoException(function() { \r
-                       elgg.assertTypeOf.apply(elgg, noexceptions[i]); \r
+        ['boolean', true],\r
+        ['boolean', false],\r
+        ['undefined', undefined],\r
+        ['number', 0],\r
+        ['function', elgg.nullFunction]\r
+    ].forEach(function(args) {\r
+               assertNoException(function() {\r
+                       elgg.assertTypeOf.apply(undefined, args);\r
                });\r
-       }\r
-       \r
-       var exceptions = [\r
+       });\r
+\r
+       [//Invalid inputs\r
         ['function', {}],\r
-        ['object', elgg.nullFunction],\r
-    ];\r
-       \r
-       for (var i in exceptions) {\r
-               assertException(function() {\r
-                       elgg.assertTypeOf.apply(elgg, exceptions[i]);\r
+        ['object', elgg.nullFunction]\r
+    ].forEach(function() {\r
+               assertException(function(args) {\r
+                       elgg.assertTypeOf.apply(undefined, args);\r
                });\r
-       }\r
+       });\r
 };\r
 \r
-ElggLibTest.prototype.testProvide = function() {\r
+ElggLibTest.prototype.testProvideDoesntClobber = function() {\r
        elgg.provide('foo.bar.baz');\r
-       \r
-       assertNotUndefined(foo);\r
-       assertNotUndefined(foo.bar);\r
-       assertNotUndefined(foo.bar.baz);\r
-       \r
-       var str = foo.bar.baz.oof = "don't overwrite me";\r
-       \r
+\r
+       foo.bar.baz.oof = "test";\r
+\r
        elgg.provide('foo.bar.baz');\r
-       \r
-       assertEquals(str, foo.bar.baz.oof);\r
+\r
+       assertEquals("test", foo.bar.baz.oof);\r
 };\r
 \r
 /**\r
- * Try requiring bogus input \r
+ * Try requiring bogus input\r
  */\r
 ElggLibTest.prototype.testRequire = function () {\r
        assertException(function(){ elgg.require(''); });\r
@@ -69,24 +61,24 @@ ElggLibTest.prototype.testRequire = function () {
 ElggLibTest.prototype.testInherit = function () {\r
        function Base() {}\r
        function Child() {}\r
-       \r
+\r
        elgg.inherit(Child, Base);\r
-       \r
+\r
        assertInstanceOf(Base, new Child());\r
        assertEquals(Child, Child.prototype.constructor);\r
 };\r
 \r
 ElggLibTest.prototype.testNormalizeUrl = function() {\r
        elgg.config.wwwroot = "http://elgg.org/";\r
-       \r
-       var inputs = [\r
-           [elgg.config.wwwroot, ''],\r
-           [elgg.config.wwwroot + 'pg/test', 'pg/test'],\r
+\r
+       [\r
+           ['', elgg.config.wwwroot],\r
+           ['pg/test', elgg.config.wwwroot + 'pg/test'],\r
            ['http://google.com', 'http://google.com'],\r
            ['//example.com', '//example.com'],\r
-       ];\r
-\r
-       for (var i in inputs) {\r
-               assertEquals(inputs[i][0], elgg.normalize_url(inputs[i][1]));\r
-       }\r
+           ['/pg/page', elgg.config.wwwroot + 'pg/page'],\r
+           ['mod/plugin/index.php', elgg.config.wwwroot + 'mod/plugin/index.php'],\r
+       ].forEach(function(args) {\r
+               assertEquals(args[1], elgg.normalize_url(args[0]));\r
+       });\r
 };
\ No newline at end of file
index 2f732da7b8850100ad5d16568e686873f9b82346..606487c039854f7c1dab415955fb195bcb69fb46 100644 (file)
@@ -2,6 +2,7 @@ server: http://localhost:42442
 \r
 load:\r
  - vendors/jquery/jquery-1.4.2.min.js\r
+ - vendors/sprintf.js\r
  - js/lib/elgglib.js\r
  - js/classes/*.js\r
  - js/lib/*.js\r
diff --git a/vendors/sprintf.js b/vendors/sprintf.js
new file mode 100644 (file)
index 0000000..0e8d02c
--- /dev/null
@@ -0,0 +1,183 @@
+/**\r
+sprintf() for JavaScript 0.7-beta1\r
+http://www.diveintojavascript.com/projects/javascript-sprintf\r
+\r
+Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>\r
+All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions are met:\r
+    * Redistributions of source code must retain the above copyright\r
+      notice, this list of conditions and the following disclaimer.\r
+    * Redistributions in binary form must reproduce the above copyright\r
+      notice, this list of conditions and the following disclaimer in the\r
+      documentation and/or other materials provided with the distribution.\r
+    * Neither the name of sprintf() for JavaScript nor the\r
+      names of its contributors may be used to endorse or promote products\r
+      derived from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY\r
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+\r
+\r
+Changelog:\r
+2010.09.06 - 0.7-beta1\r
+  - features: vsprintf, support for named placeholders\r
+  - enhancements: format cache, reduced global namespace pollution\r
+\r
+2010.05.22 - 0.6:\r
+ - reverted to 0.4 and fixed the bug regarding the sign of the number 0\r
+ Note:\r
+ Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/)\r
+ who warned me about a bug in 0.5, I discovered that the last update was\r
+ a regress. I appologize for that.\r
+\r
+2010.05.09 - 0.5:\r
+ - bug fix: 0 is now preceeded with a + sign\r
+ - bug fix: the sign was not at the right position on padded results (Kamal Abdali)\r
+ - switched from GPL to BSD license\r
+\r
+2007.10.21 - 0.4:\r
+ - unit test and patch (David Baird)\r
+\r
+2007.09.17 - 0.3:\r
+ - bug fix: no longer throws exception on empty paramenters (Hans Pufal)\r
+\r
+2007.09.11 - 0.2:\r
+ - feature: added argument swapping\r
+\r
+2007.04.03 - 0.1:\r
+ - initial release\r
+**/\r
+\r
+var sprintf = (function() {\r
+       function get_type(variable) {\r
+               return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();\r
+       }\r
+       function str_repeat(input, multiplier) {\r
+               for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}\r
+               return output.join('');\r
+       }\r
+\r
+       var str_format = function() {\r
+               if (!str_format.cache.hasOwnProperty(arguments[0])) {\r
+                       str_format.cache[arguments[0]] = str_format.parse(arguments[0]);\r
+               }\r
+               return str_format.format.call(null, str_format.cache[arguments[0]], arguments);\r
+       };\r
+\r
+       str_format.format = function(parse_tree, argv) {\r
+               var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;\r
+               for (i = 0; i < tree_length; i++) {\r
+                       node_type = get_type(parse_tree[i]);\r
+                       if (node_type === 'string') {\r
+                               output.push(parse_tree[i]);\r
+                       }\r
+                       else if (node_type === 'array') {\r
+                               match = parse_tree[i]; // convenience purposes only\r
+                               if (match[2]) { // keyword argument\r
+                                       arg = argv[cursor];\r
+                                       for (k = 0; k < match[2].length; k++) {\r
+                                               if (!arg.hasOwnProperty(match[2][k])) {\r
+                                                       throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));\r
+                                               }\r
+                                               arg = arg[match[2][k]];\r
+                                       }\r
+                               }\r
+                               else if (match[1]) { // positional argument (explicit)\r
+                                       arg = argv[match[1]];\r
+                               }\r
+                               else { // positional argument (implicit)\r
+                                       arg = argv[cursor++];\r
+                               }\r
+\r
+                               if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {\r
+                                       throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));\r
+                               }\r
+                               switch (match[8]) {\r
+                                       case 'b': arg = arg.toString(2); break;\r
+                                       case 'c': arg = String.fromCharCode(arg); break;\r
+                                       case 'd': arg = parseInt(arg, 10); break;\r
+                                       case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;\r
+                                       case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;\r
+                                       case 'o': arg = arg.toString(8); break;\r
+                                       case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;\r
+                                       case 'u': arg = Math.abs(arg); break;\r
+                                       case 'x': arg = arg.toString(16); break;\r
+                                       case 'X': arg = arg.toString(16).toUpperCase(); break;\r
+                               }\r
+                               arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);\r
+                               pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';\r
+                               pad_length = match[6] - String(arg).length;\r
+                               pad = match[6] ? str_repeat(pad_character, pad_length) : '';\r
+                               output.push(match[5] ? arg + pad : pad + arg);\r
+                       }\r
+               }\r
+               return output.join('');\r
+       };\r
+\r
+       str_format.cache = {};\r
+\r
+       str_format.parse = function(fmt) {\r
+               var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;\r
+               while (_fmt) {\r
+                       if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {\r
+                               parse_tree.push(match[0]);\r
+                       }\r
+                       else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {\r
+                               parse_tree.push('%');\r
+                       }\r
+                       else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {\r
+                               if (match[2]) {\r
+                                       arg_names |= 1;\r
+                                       var field_list = [], replacement_field = match[2], field_match = [];\r
+                                       if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {\r
+                                               field_list.push(field_match[1]);\r
+                                               while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {\r
+                                                       if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {\r
+                                                               field_list.push(field_match[1]);\r
+                                                       }\r
+                                                       else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {\r
+                                                               field_list.push(field_match[1]);\r
+                                                       }\r
+                                                       else {\r
+                                                               throw('[sprintf] huh?');\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else {\r
+                                               throw('[sprintf] huh?');\r
+                                       }\r
+                                       match[2] = field_list;\r
+                               }\r
+                               else {\r
+                                       arg_names |= 2;\r
+                               }\r
+                               if (arg_names === 3) {\r
+                                       throw('[sprintf] mixing positional and named placeholders is not (yet) supported');\r
+                               }\r
+                               parse_tree.push(match);\r
+                       }\r
+                       else {\r
+                               throw('[sprintf] huh?');\r
+                       }\r
+                       _fmt = _fmt.substring(match[0].length);\r
+               }\r
+               return parse_tree;\r
+       };\r
+\r
+       return str_format;\r
+})();\r
+\r
+var vsprintf = function(fmt, argv) {\r
+       argv.unshift(fmt);\r
+       return sprintf.apply(null, argv);\r
+};\r
index 3de1c020b681f8482339330f3e936cdf8568250b..49c12e30c57f934d52133dbb123015cf808c2333 100644 (file)
@@ -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 = '<?php echo get_version(); ?>';
 elgg.release = '<?php echo get_version(true); ?>';
 elgg.config.wwwroot = '<?php echo elgg_get_site_url(); ?>';
-elgg.security.interval = 5 * 60 * 1000; <?php //TODO make this configurable ?>
+elgg.security.interval = 5 * 60 * 1000; <?php //@todo make this configurable ?>
 
 //Mimic PHP engine boot process