From 19b7ea9a394af6e8366c64faa77badb716d743a5 Mon Sep 17 00:00:00 2001 From: brettp Date: Sat, 12 Mar 2011 21:51:07 +0000 Subject: Fixes #3065, #3089. Merged JS events and hooks to a single system. Updated plugins and core to use it. Added elgg.getURLFragment() and using it elgg.ui.popsUp(). git-svn-id: http://code.elgg.org/elgg/trunk@8671 36083f99-b078-4883-b0ff-0f9b5a30f544 --- js/lib/autocomplete.js | 2 +- js/lib/elgglib.js | 16 ++++++++- js/lib/events.js | 52 ---------------------------- js/lib/hooks.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ js/lib/languages.js | 2 +- js/lib/security.js | 2 +- js/lib/ui.js | 84 +++++++++++++++++++++++--------------------- js/lib/ui.widgets.js | 2 +- js/lib/userpicker.js | 2 +- 9 files changed, 158 insertions(+), 98 deletions(-) delete mode 100644 js/lib/events.js create mode 100644 js/lib/hooks.js (limited to 'js/lib') 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 () * - * 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 -- cgit v1.2.3