aboutsummaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/lib/autocomplete.js2
-rw-r--r--js/lib/elgglib.js16
-rw-r--r--js/lib/events.js52
-rw-r--r--js/lib/hooks.js94
-rw-r--r--js/lib/languages.js2
-rw-r--r--js/lib/security.js2
-rw-r--r--js/lib/ui.js84
-rw-r--r--js/lib/ui.widgets.js2
-rw-r--r--js/lib/userpicker.js2
-rw-r--r--js/tests/ElggEventsTest.js28
-rw-r--r--js/tests/ElggHooksTest.js28
11 files changed, 186 insertions, 126 deletions
diff --git a/js/lib/autocomplete.js b/js/lib/autocomplete.js
index eb59f51aa..917326d4f 100644
--- a/js/lib/autocomplete.js
+++ b/js/lib/autocomplete.js
@@ -36,4 +36,4 @@ elgg.autocomplete.init = function() {
};
};
-elgg.register_event_handler('init', 'system', elgg.autocomplete.init); \ No newline at end of file
+elgg.register_hook_handler('init', 'system', elgg.autocomplete.init); \ No newline at end of file
diff --git a/js/lib/elgglib.js b/js/lib/elgglib.js
index 3b409d134..4137c4a7a 100644
--- a/js/lib/elgglib.js
+++ b/js/lib/elgglib.js
@@ -350,4 +350,18 @@ elgg.register_error = function(errors, delay) {
*/
elgg.forward = function(url) {
location.href = elgg.normalize_url(url);
-}; \ No newline at end of file
+};
+
+/**
+ * Returns the fragment part of the URL, including the #. Returns '' if no fragment.
+ *
+ * @param {String} url The URL.
+ */
+elgg.getUrlFragment = function(url) {
+ var fragment = url.split('#')[1];
+
+ if (fragment) {
+ return '#' + fragment;
+ }
+ return '';
+} \ No newline at end of file
diff --git a/js/lib/events.js b/js/lib/events.js
deleted file mode 100644
index c1aa6fd9a..000000000
--- a/js/lib/events.js
+++ /dev/null
@@ -1,52 +0,0 @@
-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();
- }
-
- return events[event_name][event_type].insert(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;
- };
-
- 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],
- events[event_name]['all'],
- events['all']['all']
- ].every(function(handlers) {
- return !(handlers instanceof elgg.ElggPriorityList) || handlers.every(callEventHandler);
- });
-}; \ No newline at end of file
diff --git a/js/lib/hooks.js b/js/lib/hooks.js
new file mode 100644
index 000000000..9c86a1fec
--- /dev/null
+++ b/js/lib/hooks.js
@@ -0,0 +1,94 @@
+/*
+ * Javascript hook interface
+ */
+
+elgg.provide('elgg.config.hooks');
+
+/**
+ * Registers an hook handler with the event system.
+ *
+ * The special keyword "all" can be used for either the name or the type or both
+ * and means to call that handler for all of those hooks.
+ *
+ * @param {String} name Name of the plugin hook to register for
+ * @param {String} type Type of the event to register for
+ * @param {Function} handler Handle to call
+ * @param {Number} priority Priority to call the event handler
+ * @return {Bool}
+ */
+elgg.register_hook_handler = function(name, type, handler, priority) {
+ elgg.assertTypeOf('string', name);
+ elgg.assertTypeOf('string', type);
+ elgg.assertTypeOf('function', handler);
+
+ if (!name || !type) {
+ return false;
+ }
+
+ var priorities = elgg.config.hooks;
+
+ elgg.provide(name + '.' + type, priorities);
+
+ if (!(priorities[name][type] instanceof elgg.ElggPriorityList)) {
+ priorities[name][type] = new elgg.ElggPriorityList();
+ }
+
+ return priorities[name][type].insert(handler, priority);
+};
+
+/**
+ * Emits a hook.
+ *
+ * Loops through all registered hooks and calls the handler functions in order.
+ * Every handler function will always be called, regardless of the return value.
+ *
+ * @warning Handlers take the same 4 arguments in the same order as when calling this function.
+ * This is different to the PHP version!
+ *
+ * Hooks are called in this order:
+ * specifically registered (event_name and event_type match)
+ * all names, specific type
+ * specific name, all types
+ * all names, all types
+ *
+ * @param {String} name Name of the hook to emit
+ * @param {String} type Type of the hook to emit
+ * @param {Object} params Optional parameters to pass to the handlers
+ * @param {Object} value Initial value of the return. Can be mangled by handlers
+ *
+ * @return {Bool}
+ */
+elgg.trigger_hook = function(name, type, params, value) {
+ elgg.assertTypeOf('string', name);
+ elgg.assertTypeOf('string', type);
+
+ // default to true if unpassed
+ value = value || true;
+
+ var hooks = elgg.config.hooks,
+ tempReturnValue = null,
+ returnValue = value,
+ callHookHandler = function(handler) {
+ tempReturnValue = handler(name, type, params, value);
+ // always continue through all the handlers
+ return true;
+ };
+
+ elgg.provide(name + '.' + type, hooks);
+ elgg.provide('all.' + type, hooks);
+ elgg.provide(name + '.all', hooks);
+ elgg.provide('all.all', hooks);
+
+ [ hooks[name][type],
+ hooks['all'][type],
+ hooks[name]['all'],
+ hooks['all']['all']
+ ].every(function(handlers) {
+ if (handlers instanceof elgg.ElggPriorityList) {
+ handlers.every(callHookHandler);
+ }
+ return true;
+ });
+
+ return tempReturnValue || returnValue;
+}; \ No newline at end of file
diff --git a/js/lib/languages.js b/js/lib/languages.js
index 10afa24b0..79768c471 100644
--- a/js/lib/languages.js
+++ b/js/lib/languages.js
@@ -86,4 +86,4 @@ elgg.config.translations.init = function() {
elgg.reload_all_translations();
};
-elgg.register_event_handler('boot', 'system', elgg.config.translations.init); \ No newline at end of file
+elgg.register_hook_handler('boot', 'system', elgg.config.translations.init); \ No newline at end of file
diff --git a/js/lib/security.js b/js/lib/security.js
index def775c05..d449d8887 100644
--- a/js/lib/security.js
+++ b/js/lib/security.js
@@ -73,4 +73,4 @@ elgg.security.init = function() {
setInterval(elgg.security.refreshToken, elgg.security.interval);
};
-elgg.register_event_handler('boot', 'system', elgg.security.init); \ No newline at end of file
+elgg.register_hook_handler('boot', 'system', elgg.security.init); \ No newline at end of file
diff --git a/js/lib/ui.js b/js/lib/ui.js
index c77c85aed..8d519a995 100644
--- a/js/lib/ui.js
+++ b/js/lib/ui.js
@@ -1,7 +1,6 @@
elgg.provide('elgg.ui');
elgg.ui.init = function () {
-
elgg.ui.initHoverMenu();
//if the user clicks a system message, make it disappear
@@ -46,13 +45,14 @@ elgg.ui.toggles = function(event) {
* Set the rel="popup" on the popper and set the href to target the
* item you want to toggle (<a rel="popup" href="#id-of-target">)
*
- * This function emits the popup, ui event that plugins can register for to provide custom
- * positioning for elements. The handler is passed an object with the values:
- * popupSelector: The selector used to find the popup
- * popup: The popup jQuery element as found by the selector
- * popper: The jquery element whose click event initiated a popup.
- *
- * The handler function must return false to tell this function to abort automatic placement.
+ * This function emits the getOptions, ui.popup hook that plugins can register for to provide custom
+ * positioning for elements. The handler is passed the following params:
+ * targetSelector: The selector used to find the popup
+ * target: The popup jQuery element as found by the selector
+ * source: The jquery element whose click event initiated a popup.
+ *
+ * The return value of the function is used as the options object to .position().
+ * Handles can also return false to abort the default behvior and override it with their own.
*
* @param {Object} event
* @return void
@@ -60,17 +60,26 @@ elgg.ui.toggles = function(event) {
elgg.ui.popsUp = function(event) {
event.preventDefault();
- var target = $(this).toggleClass('elgg-state-active').attr('href');
+ var target = elgg.getUrlFragment($(this).toggleClass('elgg-state-active').attr('href'));
var $target = $(target);
// emit a hook to allow plugins to position and control popups
- var obj = {
- popupSelector: target,
- popup: $target,
- popper: $(this)
+ var params = {
+ targetSelector: target,
+ target: $target,
+ source: $(this)
};
-
- if (!elgg.trigger_event('popup', 'ui', obj)) {
+
+ var options = {
+ my: 'center top',
+ at: 'center bottom',
+ of: $(this)
+ }
+
+ options = elgg.trigger_hook('getOptions', 'ui.popup', params, options);
+
+ // allow plugins to cancel event
+ if (!options) {
return;
}
@@ -82,11 +91,7 @@ elgg.ui.popsUp = function(event) {
$target.appendTo('body')
.fadeIn()
- .position({
- 'my': 'left top',
- 'at': 'right bottom',
- 'of': $(this)
- });
+ .position(options);
}
/**
@@ -164,7 +169,7 @@ elgg.ui.initHoverMenu = function(parent) {
/**
* Calls a confirm() and prevents default if denied.
*
- * @param {Object} event
+ * @param {Object} e
* @return void
*/
elgg.ui.requiresConfirmation = function(e) {
@@ -175,25 +180,24 @@ elgg.ui.requiresConfirmation = function(e) {
};
/**
- * Repositions the likes popup.
+ * Repositions the likes popup
+ *
+ * @param {String} hook 'getOptions'
+ * @param {String} type 'ui.popup'
+ * @param {Object} params An array of info about the target and source.
+ * @param {Object} options Options to pass to
+ *
+ * @return {Object}
*/
-elgg.ui.likesPopupHandler = function(event, type, object) {
- if (object.popup.hasClass('elgg-likes-list')) {
- if (object.popup.is(':visible')) {
- object.popup.fadeOut();
- return false;
- }
-
- object.popup.appendTo('body')
- .fadeIn()
- .position({
- 'my': 'right bottom',
- 'at': 'left top',
- 'of': object.popper
- });
+elgg.ui.likesPopupHandler = function(hook, type, params, options) {
+ if (params.target.hasClass('elgg-likes-list')) {
+ options.my = 'right bottom';
+ options.at = 'left top';
+ return options;
}
- return false;
-}
+ return null;
+};
-elgg.register_event_handler('init', 'system', elgg.ui.init);
-elgg.register_event_handler('popup', 'ui', elgg.ui.likesPopupHandler); \ No newline at end of file
+elgg.register_hook_handler('init', 'system', elgg.ui.init);
+//elgg.register_hook_handler('popup', 'ui', elgg.ui.likesPopupHandler);
+elgg.register_hook_handler('getOptions', 'ui.popup', elgg.ui.likesPopupHandler); \ No newline at end of file
diff --git a/js/lib/ui.widgets.js b/js/lib/ui.widgets.js
index 1acc22928..fb256672a 100644
--- a/js/lib/ui.widgets.js
+++ b/js/lib/ui.widgets.js
@@ -199,4 +199,4 @@ elgg.ui.widgets.equalHeight = function(selector) {
$(selector).css('min-height', maxHeight);
}
-elgg.register_event_handler('init', 'system', elgg.ui.widgets.init);
+elgg.register_hook_handler('init', 'system', elgg.ui.widgets.init);
diff --git a/js/lib/userpicker.js b/js/lib/userpicker.js
index 5fc39bce3..b551ea830 100644
--- a/js/lib/userpicker.js
+++ b/js/lib/userpicker.js
@@ -81,4 +81,4 @@ elgg.userpicker.getSearchParams = function(e) {
}
}
-elgg.register_event_handler('init', 'system', elgg.userpicker.init); \ No newline at end of file
+elgg.register_hook_handler('init', 'system', elgg.userpicker.init); \ No newline at end of file
diff --git a/js/tests/ElggEventsTest.js b/js/tests/ElggEventsTest.js
deleted file mode 100644
index 4765878cf..000000000
--- a/js/tests/ElggEventsTest.js
+++ /dev/null
@@ -1,28 +0,0 @@
-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', elgg.nullFunction);
- assertTrue(elgg.trigger_event('fee', 'fum'));
-};
-
-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);
- assertException("all,all", function() { elgg.trigger_event('pinky', 'winky'); });
-}; \ No newline at end of file
diff --git a/js/tests/ElggHooksTest.js b/js/tests/ElggHooksTest.js
new file mode 100644
index 000000000..e7a2440e7
--- /dev/null
+++ b/js/tests/ElggHooksTest.js
@@ -0,0 +1,28 @@
+ElggHooksTest = TestCase("ElggHooksTest");
+
+ElggHooksTest.prototype.setUp = function() {
+ elgg.config.hooks = {};
+ elgg.provide('elgg.config.hooks.all.all');
+};
+
+ElggHooksTest.prototype.testHookHandlersMustBeFunctions = function () {
+ assertException(function() { elgg.register_hook_handler('str', 'str', 'oops'); });
+};
+
+ElggHooksTest.prototype.testReturnValueDefaultsToTrue = function () {
+ assertTrue(elgg.trigger_hook('fee', 'fum'));
+
+ elgg.register_hook_handler('fee', 'fum', elgg.nullFunction);
+ assertTrue(elgg.trigger_hook('fee', 'fum'));
+};
+
+ElggHooksTest.prototype.testCanGlomHooksWithAll = function () {
+ elgg.register_hook_handler('all', 'bar', elgg.abstractMethod);
+ assertException("all,bar", function() { elgg.trigger_hook('foo', 'bar'); });
+
+ elgg.register_hook_handler('foo', 'all', elgg.abstractMethod);
+ assertException("foo,all", function() { elgg.trigger_hook('foo', 'baz'); });
+
+ elgg.register_hook_handler('all', 'all', elgg.abstractMethod);
+ assertException("all,all", function() { elgg.trigger_hook('pinky', 'winky'); });
+}; \ No newline at end of file