]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Refs #2538: Added Elggy event system. Javascript boot sequence mimics PHP.
authorewinslow <ewinslow@36083f99-b078-4883-b0ff-0f9b5a30f544>
Tue, 2 Nov 2010 04:23:04 +0000 (04:23 +0000)
committerewinslow <ewinslow@36083f99-b078-4883-b0ff-0f9b5a30f544>
Tue, 2 Nov 2010 04:23:04 +0000 (04:23 +0000)
git-svn-id: http://code.elgg.org/elgg/trunk@7186 36083f99-b078-4883-b0ff-0f9b5a30f544

engine/js/classes/ElggPriorityList.js [new file with mode: 0644]
engine/js/lib/elgglib.js
engine/js/lib/events.js [new file with mode: 0644]
engine/js/lib/languages.js
engine/js/lib/security.js
engine/js/lib/ui.js
engine/js/lib/ui.widgets.js
engine/js/tests/ElggEventsTest.js [new file with mode: 0644]
engine/js/tests/ElggLibTest.js
engine/js/tests/ElggPriorityListTest.js [new file with mode: 0644]
views/default/js/initialise_elgg.php

diff --git a/engine/js/classes/ElggPriorityList.js b/engine/js/classes/ElggPriorityList.js
new file mode 100644 (file)
index 0000000..521fbbb
--- /dev/null
@@ -0,0 +1,60 @@
+elgg.ElggPriorityList = function() {
+       this.length = 0;
+       this.priorities_ = [];
+};
+
+elgg.ElggPriorityList.prototype.insert = function(obj, opt_priority) {
+       if (opt_priority == undefined) {
+               opt_priority = 500;
+       } 
+
+       opt_priority = parseInt(opt_priority);
+       if (opt_priority < 0) {
+               opt_priority = 0;
+       }
+       
+       if (this.priorities_[opt_priority] == undefined) {
+               this.priorities_[opt_priority] = [];
+       }
+       
+       this.priorities_[opt_priority].push(obj);
+       this.length++;
+};
+
+elgg.ElggPriorityList.prototype.forEach = function(callback) {
+       elgg.assertTypeOf('function', callback);
+
+       var index = 0;
+       for (var p in this.priorities_) {
+               var elems = this.priorities_[p];
+               for (var i in elems) {
+                       callback(elems[i], index);
+                       index++;
+               }
+       }
+};
+
+elgg.ElggPriorityList.prototype.every = function(callback) {
+       elgg.assertTypeOf('function', callback);
+       
+       var index = 0;
+       for (var p in this.priorities_) {
+               var elems = this.priorities_[p];
+               for (var i in elems) {
+                       if (!callback(elems[i], index)) {
+                               return false;
+                       };
+               }
+       }
+       
+       return true;
+};
+
+elgg.ElggPriorityList.prototype.remove = function(obj) {
+       this.priorities_.forEach(function(elems, priority) {
+               var index;
+               while ((index = elems.indexOf(obj)) != -1) {
+                       elems.splice(index, 1);
+               }
+       });
+};
\ No newline at end of file
index 5c32deaafec35f22fa7dced674834747b68b77bd..f7c30bdc26e3d57578c11abedfc92a9c99cac72c 100644 (file)
@@ -9,11 +9,10 @@
  */\r
 var elgg = elgg || {};\r
 \r
-elgg.init = function() {\r
-       //if the user clicks a system message, make it disappear\r
-       $('.elgg_system_message').live('click', function() {\r
-               $(this).stop().fadeOut('fast');\r
-       });\r
+elgg.assertTypeOf = function(type, param) {\r
+       if (typeof param !== type) {\r
+               throw new TypeError("Expecting param to be a " + type + ".  Was a " + typeof param + ".");\r
+       }\r
 };\r
 \r
 /**\r
@@ -176,12 +175,4 @@ elgg.register_error = function(errors, delay) {
  */\r
 elgg.forward = function(url) {\r
        location.href = elgg.extendUrl(url);\r
-};\r
-\r
-/**\r
- * Initialise Elgg\r
- * @todo How should plugins, etc. initialize themselves?\r
- */\r
-$(function() {\r
-       elgg.init();\r
-});\r
+};
\ No newline at end of file
diff --git a/engine/js/lib/events.js b/engine/js/lib/events.js
new file mode 100644 (file)
index 0000000..358dd62
--- /dev/null
@@ -0,0 +1,65 @@
+elgg.provide('elgg.config.events');
+elgg.provide('elgg.config.events.all');
+elgg.provide('elgg.config.events.all.all');
+
+elgg.register_event_handler = function(event, type, callback, priority) {
+       elgg.assertTypeOf('string', event);
+       elgg.assertTypeOf('string', event);
+       elgg.assertTypeOf('function', callback);
+       
+       if (!event || !type) {
+               return false;
+       }
+       
+       elgg.provide('elgg.config.events.' + event + '.' + type);
+
+       var events = elgg.config.events;
+       
+       if (!(events[event][type] instanceof elgg.ElggPriorityList)) {
+               events[event][type] = new elgg.ElggPriorityList();
+       }
+
+       return events[event][type].insert(callback, priority);
+};
+
+elgg.trigger_event = function(event, type, object) {
+       elgg.assertTypeOf('string', event);
+       elgg.assertTypeOf('string', event);
+
+       elgg.provide('elgg.config.events.' + event + '.' + type);
+       elgg.provide('elgg.config.events.all.' + type);
+       elgg.provide('elgg.config.events.' + event + '.all');
+       elgg.provide('elgg.config.events.all.all');
+       
+       var events = elgg.config.events;
+       
+       var callEventHandler = function(handler) { 
+               return handler(event, type, object) !== false; 
+       };
+       
+       if (events[event][type] instanceof elgg.ElggPriorityList) {
+               if (!events[event][type].every(callEventHandler)) {
+                       return false;
+               }
+       }
+       
+       if (events['all'][type] instanceof elgg.ElggPriorityList) {
+               if (!events['all'][type].every(callEventHandler)) {
+                       return false;
+               }
+       }
+       
+       if (events[event]['all'] instanceof elgg.ElggPriorityList) {
+               if (!events[event]['all'].every(callEventHandler)) {
+                       return false;
+               }
+       }
+       
+       if (events['all']['all'] instanceof elgg.ElggPriorityList) {
+               if (!events['all']['all'].every(callEventHandler)) {
+                       return false;
+               }
+       }
+               
+       return true;
+};
\ No newline at end of file
index 6ac83f3506d35da13887293b3ec552afcea66676..3231cf77d92338ad811cbd53b8f9cb2293a4ded6 100644 (file)
@@ -5,10 +5,6 @@ elgg.provide('elgg.config.translations');
 \r
 elgg.config.language = 'en';\r
 \r
-elgg.config.translations.init = function() {\r
-       elgg.reload_all_translations();\r
-};\r
-\r
 elgg.add_translation = function(lang, translations) {\r
        elgg.provide('elgg.config.translations.' + lang);\r
        \r
@@ -36,11 +32,6 @@ elgg.reload_all_translations = function(language) {
        });\r
 };\r
 \r
-/**\r
- * @deprecated Use elgg.reload_all_translations\r
- */\r
-elgg.config.translations.load = elgg.reload_all_translations;\r
-\r
 /**\r
  * Get the current language\r
  * @return {String}\r
@@ -85,6 +76,8 @@ elgg.echo = function(key, language) {
        return undefined;\r
 };\r
 \r
-$(function() {\r
-       elgg.config.translations.init();\r
-});
\ No newline at end of file
+elgg.config.translations.init = function() {\r
+       elgg.reload_all_translations();\r
+};\r
+\r
+elgg.register_event_handler('boot', 'system', elgg.config.translations.init);
\ No newline at end of file
index f4494111b6b804d5e47cbb11fa07ad31486c87f7..bdd762560b1f0bc4f9588cf548974e11b9916395 100644 (file)
@@ -5,11 +5,6 @@ elgg.provide('elgg.security');
 \r
 elgg.security.token = {};\r
 \r
-elgg.security.init = function() {\r
-       //refresh security token every 5 minutes\r
-       setInterval(elgg.security.refreshToken, elgg.security.interval);\r
-};\r
-\r
 elgg.security.setToken = function(json) {\r
        //update the convenience object\r
        elgg.security.token = json;\r
@@ -67,6 +62,9 @@ elgg.security.addToken = function(data) {
        throw new TypeError("elgg.security.addToken not implemented for " + (typeof data) + "s");\r
 };\r
 \r
-$(function() {\r
-       elgg.security.init();\r
-});
\ No newline at end of file
+elgg.security.init = function() {\r
+       //refresh security token every 5 minutes\r
+       setInterval(elgg.security.refreshToken, elgg.security.interval);\r
+};\r
+\r
+elgg.register_event_handler('boot', 'system', elgg.security.init);
\ No newline at end of file
index b584d66d1df89c589ddbf78a06666d6dc4989cdc..4a9c64e703f370e65c66ae10a288f1b1e7b14cf1 100644 (file)
@@ -1,6 +1,11 @@
 elgg.provide('elgg.ui');\r
 \r
 elgg.ui.init = function () {\r
+       //if the user clicks a system message, make it disappear\r
+       $('.elgg_system_message').live('click', function() {\r
+               $(this).stop().fadeOut('fast');\r
+       });\r
+       \r
        $('a.collapsibleboxlink').click(elgg.ui.toggleCollapsibleBox);\r
 \r
        // set-up hover class for dragged widgets\r
@@ -113,6 +118,4 @@ elgg.ui.toggleCollapsibleBox = function () {
        };\r
 })(jQuery);\r
 \r
-$(function() {\r
-       elgg.ui.init();\r
-});
\ No newline at end of file
+elgg.register_event_handler('init', 'system', elgg.ui.init);
\ No newline at end of file
index 02a6d0e16f7210eb8a2a4b266a70b32863bb18ea..1e3163709ee6116f583a9d487703606cd307d82d 100644 (file)
@@ -128,6 +128,4 @@ var toggleContent =    elgg.ui.widgets.toggleContent,
     widget_state =     elgg.ui.widgets.state,\r
     outputWidgetList = elgg.ui.widgets.outputList;\r
 \r
-$(function() {\r
-       elgg.ui.widgets.init();\r
-});\r
+elgg.register_event_handler('init', 'system', elgg.ui.widgets.init);
\ No newline at end of file
diff --git a/engine/js/tests/ElggEventsTest.js b/engine/js/tests/ElggEventsTest.js
new file mode 100644 (file)
index 0000000..cc30e84
--- /dev/null
@@ -0,0 +1,28 @@
+ElggEventsTest = TestCase("ElggEventsTest");
+
+ElggEventsTest.prototype.setUp = function() {
+       elgg.config.events = {};
+       elgg.provide('elgg.config.events.all.all');
+};
+
+ElggEventsTest.prototype.testEventHandlersMustBeFunctions = function() {
+       assertException(function() { elgg.register_event_handler('str', 'str', 'oops'); });
+};
+
+ElggEventsTest.prototype.testReturnValueDefaultsToTrue = function() {
+       assertTrue(elgg.trigger_event('fee', 'fum'));
+       
+       elgg.register_event_handler('fee', 'fum', function() {});
+       assertTrue(elgg.trigger_event('fee', 'fum'));
+};
+
+ElggEventsTest.prototype.testCanGlomEventsWithAll = function() {
+       elgg.register_event_handler('all', 'bar', function() { throw new Error(); });
+       assertException("all,bar", function() { elgg.trigger_event('foo', 'bar'); });
+       
+       elgg.register_event_handler('foo', 'all', function() { throw new Error(); });
+       assertException("foo,all", function() { elgg.trigger_event('foo', 'baz'); });
+       
+       elgg.register_event_handler('all', 'all', function() { throw new Error(); });   
+       assertException("all,all", function() { elgg.trigger_event('pinky', 'winky'); });
+};
\ No newline at end of file
index 9202964080a98759ce70a9bbb3d2374581a72fa5..ed4db24e13790cd616e71296b9810b62c26dffe2 100644 (file)
@@ -7,6 +7,35 @@ ElggLibTest.prototype.testGlobal = function() {
        assertTrue(window === elgg.global);\r
 };\r
 \r
+ElggLibTest.prototype.testAssertTypeOf = function() {\r
+       var noexceptions = [\r
+           ['string', ''],\r
+        ['object', {}],\r
+        ['boolean', true],          \r
+        ['boolean', false],         \r
+        ['undefined', undefined],   \r
+        ['number', 0],             \r
+        ['function', function() {}],\r
+    ];\r
+       \r
+       for (var i in noexceptions) {\r
+               assertNoException(function() { \r
+                       elgg.assertTypeOf.apply(elgg, noexceptions[i]); \r
+               });\r
+       }\r
+       \r
+       var exceptions = [\r
+        ['function', {}],\r
+        ['object', function() {}],\r
+    ];\r
+       \r
+       for (var i in exceptions) {\r
+               assertException(function() {\r
+                       elgg.assertTypeOf.apply(elgg, exceptions[i]);\r
+               });\r
+       }\r
+};\r
+\r
 ElggLibTest.prototype.testProvide = function() {\r
        elgg.provide('foo.bar.baz');\r
        \r
@@ -39,7 +68,6 @@ ElggLibTest.prototype.testInherit = function() {
        \r
        elgg.inherit(Child, Base);\r
        \r
-       \r
        assertInstanceOf(Base, new Child());\r
        assertEquals(Child, Child.prototype.constructor);\r
 };\r
@@ -53,11 +81,4 @@ ElggLibTest.prototype.testExtendUrl = function() {
        \r
        url = 'pg/test';\r
        assertEquals('http://www.elgg.org/pg/test', elgg.extendUrl(url));\r
-};\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
+};
\ No newline at end of file
diff --git a/engine/js/tests/ElggPriorityListTest.js b/engine/js/tests/ElggPriorityListTest.js
new file mode 100644 (file)
index 0000000..2549e0e
--- /dev/null
@@ -0,0 +1,47 @@
+ElggPriorityListTest = TestCase("ElggPriorityListTest");
+
+ElggPriorityListTest.prototype.setUp = function() {
+       this.list = new elgg.ElggPriorityList();
+};
+
+ElggPriorityListTest.prototype.tearDown = function() {
+       this.list = null;
+};
+
+ElggPriorityListTest.prototype.testInsert = function() {
+       this.list.insert('foo');
+
+       assertEquals('foo', this.list.priorities_[500][0]);
+
+       this.list.insert('bar', 501);
+
+       assertEquals('foo', this.list.priorities_[501][0]);
+};
+
+ElggPriorityListTest.prototype.testInsertRespectsPriority = function() {
+       var values = [5, 4, 3, 2, 1, 0];
+
+       for (var i in values) {
+               this.list.insert(values[i], values[i]);
+       }
+
+       this.list.forEach(function(elem, idx)) {
+               assertEquals(elem, idx);
+       }
+};
+
+ElggPriorityListTest.prototype.testInsertHandlesDuplicatePriorities = function() {
+       values = [0, 1, 2, 3, 4, 5, 6, 7, 8 , 9];
+
+       for (var i in values) {
+               this.list.insert(values[i], values[i]/3);
+       }
+
+       this.list.forEach(function(elem, idx) {
+               assertEquals(elem, idx);
+       });
+};
+
+ElggPriorityListTest.prototype.testEveryDefaultsToTrue = function() {
+       assertTrue(this.list.every(function() {}));
+};
\ No newline at end of file
index b6c3f7ecdf585dd8864a35f46c3d55469e77f3e3..98dfc28a7c0542586f33d04f1e7a7eea4bf6f2a4 100644 (file)
@@ -4,12 +4,23 @@
  */
 global $CONFIG;
 
-//Include library files
-$lib_files = array(
-       //core
-       'elgglib',
+include("{$CONFIG->path}engine/js/lib/elgglib.js");
 
+//No such thing as autoloading classes in javascript
+$model_files = array(
+       'ElggEntity',
+       'ElggUser',
+       'ElggPriorityList',
+);
+
+foreach($model_files as $file) {
+       include("{$CONFIG->path}engine/js/classes/$file.js");
+}
+
+//Include library files
+$libs = array(
        //libraries
+       'events',
        'security',
        'languages',
        'ajax',
@@ -20,23 +31,12 @@ $lib_files = array(
        'ui.widgets',
 );
 
-foreach($lib_files as $file) {
+foreach($libs as $file) {
        include("{$CONFIG->path}engine/js/lib/$file.js");
 }
 
-//Include classes
-$model_files = array(
-       'ElggEntity',
-
-       'ElggUser',
-);
-
-foreach($model_files as $file) {
-       include("{$CONFIG->path}engine/js/classes/$file.js");
-}
-
 /**
- * Finally, set some values that are cacheable
+ * Set some values that are cacheable
  */
 ?>
 
@@ -45,6 +45,16 @@ 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 ?>
 
+//Mimic PHP engine boot process
+
+//Before the DOM is ready -- note that plugins aren't loaded yet
+elgg.trigger_event('boot', 'system');
+
+//After the DOM is ready
+$(function() {
+       elgg.trigger_event('init', 'system');
+});
+
 $(document).ready(function () {
 
        // COLLAPSABLE WIDGETS (on Dashboard? & Profile pages)