From d788c4375034709a36ee6b30cddabe58579464b6 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Sun, 31 May 2015 14:32:05 +0200 Subject: [PATCH] Added some more missing classes and shim around WCF.js's classes --- wcfsetup/install/files/js/WCF.js | 123 ++++-------------- .../install/files/js/WoltLab/WCF/DOM/Util.js | 3 + .../js/WoltLab/WCF/Date/Time/Relative.js | 4 +- .../install/files/js/WoltLab/WCF/Date/Util.js | 53 ++++++++ .../files/js/WoltLab/WCF/UI/CloseOverlay.js | 48 +++++++ .../install/files/js/WoltLab/WCF/UI/Dialog.js | 13 +- .../js/WoltLab/WCF/UI/Dropdown/Simple.js | 12 +- .../files/js/WoltLab/WCF/UI/FlexibleMenu.js | 48 ++++--- .../install/files/js/WoltLab/WCF/UI/Mobile.js | 6 +- wcfsetup/install/files/js/require.config.js | 1 + 10 files changed, 175 insertions(+), 136 deletions(-) create mode 100644 wcfsetup/install/files/js/WoltLab/WCF/Date/Util.js create mode 100644 wcfsetup/install/files/js/WoltLab/WCF/UI/CloseOverlay.js diff --git a/wcfsetup/install/files/js/WCF.js b/wcfsetup/install/files/js/WCF.js index 68687d7b4f..8c354895d5 100755 --- a/wcfsetup/install/files/js/WCF.js +++ b/wcfsetup/install/files/js/WCF.js @@ -410,7 +410,7 @@ $.fn.extend({ * @return string */ wcfIdentify: function() { - return window.domUtilIdentify(this[0]); + return window.bc_wcfDOMUtil.identify(this[0]); }, /** @@ -652,7 +652,7 @@ $.extend(WCF, { * @return string */ getRandomID: function() { - return window.domUtilGetUniqueId(); + return window.bc_wcfDOMUtil.getUniqueId(); }, /** @@ -830,48 +830,15 @@ WCF.Browser = { /** * Dropdown API + * + * @deprecated 2.2 - please use `UI/SimpleDropdown` instead */ WCF.Dropdown = { - /** - * list of callbacks - * @var object - */ - _callbacks: { }, - - /** - * initialization state - * @var boolean - */ - _didInit: false, - - /** - * list of registered dropdowns - * @var object - */ - _dropdowns: { }, - - - - /** - * container for dropdown menus - * @var object - */ - _menuContainer: null, - - /** - * list of registered dropdown menus - * @var object - */ - _menus: { }, - - _api: null, - /** * Initializes dropdowns. */ init: function(api) { - if (api) this._api = api; - else if (this._api !== null) this._api.initAll(); + window.bc_wcfSimpleDropdown.initAll(); }, /** @@ -881,7 +848,7 @@ WCF.Dropdown = { * @param boolean isLazyInitialization */ initDropdown: function(button, isLazyInitialization) { - this._api.init(button[0], isLazyInitialization); + window.bc_wcfSimpleDropdown.init(button[0], isLazyInitialization); }, /** @@ -890,7 +857,7 @@ WCF.Dropdown = { * @param string containerID */ removeDropdown: function(containerID) { - this._api.remove(containerID); + window.bc_wcfSimpleDropdown.remove(containerID); }, /** @@ -901,7 +868,7 @@ WCF.Dropdown = { * @param jQuery dropdownMenu */ initDropdownFragment: function(dropdown, dropdownMenu) { - this._api.initFragment(dropdown[0], dropdownMenu[0]); + window.bc_wcfSimpleDropdown.initFragment(dropdown[0], dropdownMenu[0]); }, /** @@ -911,7 +878,7 @@ WCF.Dropdown = { * @var object callback */ registerCallback: function(identifier, callback) { - this._api.registerCallback(identifier, callback); + window.bc_wcfSimpleDropdown.registerCallback(identifier, callback); }, /** @@ -921,7 +888,7 @@ WCF.Dropdown = { * @param string targetID */ _toggle: function(event, targetID) { - this._api._toggle(event, targetID); + window.bc_wcfSimpleDropdown._toggle(event, targetID); }, /** @@ -930,7 +897,7 @@ WCF.Dropdown = { * @param string containerID */ toggleDropdown: function(containerID) { - this._api._toggle(null, containerID); + window.bc_wcfSimpleDropdown._toggle(null, containerID); }, /** @@ -940,7 +907,7 @@ WCF.Dropdown = { * @return jQuery */ getDropdown: function(containerID) { - var dropdown = this._api.getDropdown(containerID); + var dropdown = window.bc_wcfSimpleDropdown.getDropdown(containerID); return (dropdown) ? $(dropdown) : null; }, @@ -952,7 +919,7 @@ WCF.Dropdown = { * @return jQuery */ getDropdownMenu: function(containerID) { - var menu = this._api.getDropdownMenu(containerID); + var menu = window.bc_wcfSimpleDropdown.getDropdownMenu(containerID); return (menu) ? $(menu) : null; }, @@ -963,7 +930,7 @@ WCF.Dropdown = { * @param string containerID */ setAlignmentByID: function(containerID) { - this._api.setAlignmentById(containerID); + window.bc_wcfSimpleDropdown.setAlignmentById(containerID); }, /** @@ -973,14 +940,14 @@ WCF.Dropdown = { * @param jQuery dropdownMenu */ setAlignment: function(dropdown, dropdownMenu) { - this._api.setAlignment(dropdown[0], dropdownMenu[0]); + window.bc_wcfSimpleDropdown.setAlignment(dropdown[0], dropdownMenu[0]); }, /** * Closes all dropdowns. */ _closeAll: function() { - this._api.closeAll(); + window.bc_wcfSimpleDropdown.closeAll(); }, /** @@ -989,7 +956,7 @@ WCF.Dropdown = { * @param string containerID */ close: function(containerID) { - this._api.close(containerID); + window.bc_wcfSimpleDropdown.close(containerID); }, /** @@ -999,7 +966,7 @@ WCF.Dropdown = { * @return boolean */ destroy: function(containerID) { - this._api.destroy(containerID); + window.bc_wcfSimpleDropdown.destroy(containerID); } }; @@ -4407,20 +4374,10 @@ WCF.Effect.SmoothScroll = WCF.Effect.Scroll.extend({ * preventing errors from blocking the iteration. Furthermore you should * always handle clicks on your overlay's container and return 'false' to * prevent bubbling. + * + * @deprecated 2.2 - please use `UI/CloseOverlay` instead */ WCF.CloseOverlayHandler = { - /** - * list of callbacks - * @var WCF.Dictionary - */ - _callbacks: new WCF.Dictionary(), - - /** - * indicates that overlay handler is listening to click events on body-tag - * @var boolean - */ - _isListening: false, - /** * Adds a new callback. * @@ -4428,14 +4385,9 @@ WCF.CloseOverlayHandler = { * @param object callback */ addCallback: function(identifier, callback) { - this._bindListener(); - - if (this._callbacks.isset(identifier)) { - console.debug("[WCF.CloseOverlayHandler] identifier '" + identifier + "' is already bound to a callback"); - return false; - } - - this._callbacks.add(identifier, callback); + require(['UI/CloseOverlay'], function(UICloseOverlay) { + UICloseOverlay.add(identifier, callback); + }); }, /** @@ -4444,36 +4396,17 @@ WCF.CloseOverlayHandler = { * @param string identifier */ removeCallback: function(identifier) { - if (this._callbacks.isset(identifier)) { - this._callbacks.remove(identifier); - } + require(['UI/CloseOverlay'], function(UICloseOverlay) { + UICloseOverlay.remove(identifier); + }); }, /** * Triggers the callbacks programmatically. */ forceExecution: function() { - this._executeCallbacks(); - }, - - /** - * Binds click event handler. - */ - _bindListener: function() { - if (this._isListening) return; - - $(document.body).click($.proxy(this._executeCallbacks, this)); - - this._isListening = true; - }, - - /** - * Executes callbacks on click. - */ - _executeCallbacks: function(event) { - this._callbacks.each(function(pair) { - // execute callback - pair.value(); + require(['UI/CloseOverlay'], function(UICloseOverlay) { + UICloseOverlay.execute(); }); } }; diff --git a/wcfsetup/install/files/js/WoltLab/WCF/DOM/Util.js b/wcfsetup/install/files/js/WoltLab/WCF/DOM/Util.js index 34298c5516..8efa0e855b 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/DOM/Util.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/DOM/Util.js @@ -201,5 +201,8 @@ define([], function() { } }; + // expose on window object for backward compatibility + window.bc_wcfDOMUtil = DOMUtil; + return DOMUtil; }); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Date/Time/Relative.js b/wcfsetup/install/files/js/WoltLab/WCF/Date/Time/Relative.js index 3fcb5693cd..89d84f2064 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Date/Time/Relative.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Date/Time/Relative.js @@ -6,7 +6,7 @@ * @license GNU Lesser General Public License * @module WoltLab/WCF/Date/Time/Relative */ -define(['DOM/ChangeListener', 'Language', 'WoltLab/WCF/Timer/Repeating'], function(DOMChangeListener, Language, Repeating) { +define(['DOM/ChangeListener', 'Language', 'WoltLab/WCF/Date/Util', 'WoltLab/WCF/Timer/Repeating'], function(DOMChangeListener, Language, DateUtil, Repeating) { "use strict"; var _elements = document.getElementsByTagName('time'); @@ -64,7 +64,7 @@ define(['DOM/ChangeListener', 'Language', 'WoltLab/WCF/Timer/Repeating'], functi var days = Math.ceil((midnight / 1000 - elTimestamp) / 86400); // get day of week - var dateObj = WCF.Date.Util.getTimezoneDate((elTimestamp * 1000), elOffset * 1000); + var dateObj = DateUtil.getTimezoneDate((elTimestamp * 1000), elOffset * 1000); var dow = dateObj.getDay(); var day = Language.get('__days')[dow]; diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Date/Util.js b/wcfsetup/install/files/js/WoltLab/WCF/Date/Util.js new file mode 100644 index 0000000000..bf214d8bcb --- /dev/null +++ b/wcfsetup/install/files/js/WoltLab/WCF/Date/Util.js @@ -0,0 +1,53 @@ +/** + * Provides utility functions for date operations. + * + * @author Alexander Ebert + * @copyright 2001-2015 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLab/WCF/Date/Util + */ +define([], function() { + "use strict"; + + /** + * @exports WoltLab/WCF/Date/Util + */ + var DateUtil = { + /** + * Returns UTC timestamp, if date is not given, current time will be used. + * + * @param Date date target date + * @return integer UTC timestamp in seconds + */ + gmdate: function(data) { + if ((!date instanceof Date)) { + date = new Date(); + } + + return Math.round(Date.UTC( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDay(), + date.getUTCHours(), + date.getUTCMinutes(), + date.getUTCSeconds() + ) / 1000); + }, + + /** + * Returns a Date object with precise offset (including timezone and local timezone). + * + * @param integer timestamp timestamp in miliseconds + * @param integer offset timezone offset in miliseconds + * @return Date localized date + */ + getTimezoneDate: function(timestamp, offset) { + var date = new Date(timestamp); + var localOffset = date.getTimezoneOffset() * 60000; + + return new Date((timestamp + localOffset + offset)); + } + }; + + return DateUtil; +}); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/UI/CloseOverlay.js b/wcfsetup/install/files/js/WoltLab/WCF/UI/CloseOverlay.js new file mode 100644 index 0000000000..fe890929a7 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLab/WCF/UI/CloseOverlay.js @@ -0,0 +1,48 @@ +/** + * Allows to be informed when a click event bubbled up to the document's body. + * + * @author Alexander Ebert + * @copyright 2001-2015 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLab/WCF/UI/CloseOlveray + */ +define(['CallbackList'], function(CallbackList) { + "use strict"; + + var _callbackList = new CallbackList(); + + /** + * @exports WoltLab/WCF/UI/CloseOverlay + */ + var UICloseOverlay = { + /** + * Sets up global event listener for bubbled clicks events. + */ + setup: function() { + document.body.addEventListener('click', this.execute.bind(this)); + }, + + /** + * @see WoltLab/WCF/CallbackList#add + */ + add: _callbackList.add.bind(_callbackList), + + /** + * @see WoltLab/WCF/CallbackList#remove + */ + remove: _callbackList.remove.bind(_callbackList), + + /** + * Invokes all registered callbacks. + */ + execute: function() { + _callbackList.forEach(null, function(callback) { + callback(); + }); + } + }; + + UICloseOverlay.setup(); + + return UICloseOverlay; +}); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/UI/Dialog.js b/wcfsetup/install/files/js/WoltLab/WCF/UI/Dialog.js index 7e84faad59..80b4627b87 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/UI/Dialog.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/UI/Dialog.js @@ -7,8 +7,8 @@ * @module WoltLab/WCF/UI/Dialog */ define( - [ 'enquire', 'Core', 'Dictionary', 'Environment', 'Language', 'DOM/ChangeListener', 'DOM/Util'], - function(enquire, Core, Dictionary, Environment, Language, DOMChangeListener, DOMUtil) + [ 'enquire', 'Core', 'Dictionary', 'Environment', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Confirmation'], + function(enquire, Core, Dictionary, Environment, Language, DOMChangeListener, DOMUtil, UIConfirmation) { "use strict"; @@ -88,11 +88,12 @@ define( if (!options.closable) options.backdropCloseOnClick = false; if (options.closeConfirmMessage) { options.onBeforeClose = (function(id) { - WCF.System.Confirmation.show(options.closeConfirmMessage, (function(action) { - if (action === 'confirm') { + UIConfirmation.show({ + confirm: (function() { this.close(id); - } - }).bind(this)); + }).bind(this), + message: options.closeConfirmMessage + }) }).bind(this); } diff --git a/wcfsetup/install/files/js/WoltLab/WCF/UI/Dropdown/Simple.js b/wcfsetup/install/files/js/WoltLab/WCF/UI/Dropdown/Simple.js index af27780e08..296cc0d5e2 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/UI/Dropdown/Simple.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/UI/Dropdown/Simple.js @@ -7,8 +7,8 @@ * @module WoltLab/WCF/UI/Dropdown/Simple */ define( - [ 'CallbackList', 'Dictionary', 'UI/Alignment', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util'], - function(CallbackList, Dictionary, UIAlignment, DOMChangeListener, DOMTraverse, DOMUtil) + [ 'CallbackList', 'Dictionary', 'UI/Alignment', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', 'UI/CloseOverlay'], + function(CallbackList, Dictionary, UIAlignment, DOMChangeListener, DOMTraverse, DOMUtil, UICloseOverlay) { "use strict"; @@ -34,12 +34,13 @@ define( this.initAll(); - WCF.Dropdown.init(this); - - WCF.CloseOverlayHandler.addCallback('WoltLab/WCF/UI/Dropdown/Simple', this.closeAll.bind(this)); + UICloseOverlay.add('WoltLab/WCF/UI/Dropdown/Simple', this.closeAll.bind(this)); DOMChangeListener.add('WoltLab/WCF/UI/Dropdown/Simple', this.initAll.bind(this)); document.addEventListener('scroll', this._onScroll.bind(this)); + + // expose on window object for backward compatibility + window.bc_wcfSimpleDropdown = this; }, /** @@ -338,6 +339,7 @@ define( } }).bind(this)); + // TODO WCF.Dropdown.Interactive.Handler.closeAll(); if (event !== null) { diff --git a/wcfsetup/install/files/js/WoltLab/WCF/UI/FlexibleMenu.js b/wcfsetup/install/files/js/WoltLab/WCF/UI/FlexibleMenu.js index 3d9471389c..b2012512aa 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/UI/FlexibleMenu.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/UI/FlexibleMenu.js @@ -10,16 +10,15 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', 'UI/SimpleDropdown'], function(Core, Dictionary, DOMChangeListener, DOMTraverse, DOMUtil, SimpleDropdown) { "use strict"; + var _containers = new Dictionary(); + var _dropdowns = new Dictionary(); + var _dropdownMenus = new Dictionary(); + var _itemLists = new Dictionary(); + /** - * @constructor + * @exports WoltLab/WCF/UI/FlexibleMenu */ - function UIFlexibleMenu() { - this._containers = new Dictionary(); - this._dropdowns = new Dictionary(); - this._dropdownMenus = new Dictionary(); - this._itemLists = new Dictionary(); - }; - UIFlexibleMenu.prototype = { + var UIFlexibleMenu = { /** * Register default menus and set up event listeners. */ @@ -28,7 +27,6 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', var navigationHeader = document.querySelector('.navigationHeader'); if (navigationHeader !== null) this.register(DOMUtil.identify(navigationHeader)); - window.addEventListener('resize', this.rebuildAll.bind(this)); DOMChangeListener.add('WoltLab/WCF/UI/FlexibleMenu', this.registerTabMenus.bind(this)); }, @@ -44,17 +42,17 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', throw "Expected a valid element id, '" + containerId + "' does not exist."; } - if (this._containers.has(containerId)) { + if (_containers.has(containerId)) { return; } - var lists = DOMTraverse.childrenByTag(container, 'UL'); - if (!lists.length) { + var list = DOMTraverse.childByTag(container, 'UL'); + if (list === null) { throw "Expected an
    element as child of container '" + containerId + "'."; } - this._containers.set(containerId, container); - this._itemLists.set(containerId, lists[0]); + _containers.set(containerId, container); + _itemLists.set(containerId, list); this.rebuild(containerId); }, @@ -66,10 +64,10 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', var tabMenus = document.querySelectorAll('.tabMenuContainer:not(.jsFlexibleMenuEnabled), .messageTabMenu:not(.jsFlexibleMenuEnabled)'); for (var i = 0, length = tabMenus.length; i < length; i++) { var tabMenu = tabMenus[i]; - var navs = DOMTraverse.childrenByTag(tabMenu, 'NAV'); - if (navs.length !== 0) { + var nav = DOMTraverse.childByTag(tabMenu, 'NAV'); + if (nav !== null) { tabMenu.classList.add('jsFlexibleMenuEnabled'); - this.register(DOMUtil.identify(navs[0])); + this.register(DOMUtil.identify(nav)); } } }, @@ -78,7 +76,7 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', * Rebuilds all menus, e.g. on window resize. */ rebuildAll: function() { - this._containers.forEach((function(container, containerId) { + _containers.forEach((function(container, containerId) { this.rebuild(containerId); }).bind(this)); }, @@ -89,7 +87,7 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', * @param {string} containerId element id */ rebuild: function(containerId) { - var container = this._containers.get(containerId); + var container = _containers.get(containerId); if (container === undefined) { throw "Expected a valid element id, '" + containerId + "' is unknown."; } @@ -100,9 +98,9 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', availableWidth -= DOMUtil.styleAsInt(styles, 'margin-left'); availableWidth -= DOMUtil.styleAsInt(styles, 'margin-right'); - var list = this._itemLists.get(containerId); + var list = _itemLists.get(containerId); var items = DOMTraverse.childrenByTag(list, 'LI'); - var dropdown = this._dropdowns.get(containerId); + var dropdown = _dropdowns.get(containerId); var dropdownWidth = 0; if (dropdown !== undefined) { // show all items for calculation @@ -154,13 +152,13 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', dropdownMenu.classList.add('dropdownMenu'); dropdown.appendChild(dropdownMenu); - this._dropdowns.set(containerId, dropdown); - this._dropdownMenus.set(containerId, dropdownMenu); + _dropdowns.set(containerId, dropdown); + _dropdownMenus.set(containerId, dropdownMenu); SimpleDropdown.init(icon); } else { - dropdownMenu = this._dropdownMenus.get(containerId); + dropdownMenu = _dropdownMenus.get(containerId); } if (dropdown.parentNode === null) { @@ -198,5 +196,5 @@ define(['Core', 'Dictionary', 'DOM/ChangeListener', 'DOM/Traverse', 'DOM/Util', } }; - return new UIFlexibleMenu(); + return UIFlexibleMenu; }); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/UI/Mobile.js b/wcfsetup/install/files/js/WoltLab/WCF/UI/Mobile.js index 329925c08a..5087ff3583 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/UI/Mobile.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/UI/Mobile.js @@ -7,8 +7,8 @@ * @module WoltLab/WCF/UI/Mobile */ define( - [ 'enquire', 'Environment', 'Language', 'DOM/ChangeListener', 'DOM/Traverse'], - function(enquire, Environment, Language, DOMChangeListener, DOMTraverse) + [ 'enquire', 'Environment', 'Language', 'DOM/ChangeListener', 'DOM/Traverse', 'UI/CloseHandler'], + function(enquire, Environment, Language, DOMChangeListener, DOMTraverse, UICloseHandler) { "use strict"; @@ -78,7 +78,7 @@ define( this._initSearchBar(); this._initButtonGroupNavigation(); - WCF.CloseOverlayHandler.addCallback('WoltLab/WCF/UI/Mobile', this._closeAllMenus.bind(this)); + UICloseHandler.add('WoltLab/WCF/UI/Mobile', this._closeAllMenus.bind(this)); DOMChangeListener.add('WoltLab/WCF/UI/Mobile', this._initButtonGroupNavigation.bind(this)); }, diff --git a/wcfsetup/install/files/js/require.config.js b/wcfsetup/install/files/js/require.config.js index 13b6378a86..40d94bb474 100644 --- a/wcfsetup/install/files/js/require.config.js +++ b/wcfsetup/install/files/js/require.config.js @@ -26,6 +26,7 @@ requirejs.config({ 'List': 'WoltLab/WCF/List', 'ObjectMap': 'WoltLab/WCF/ObjectMap', 'UI/Alignment': 'WoltLab/WCF/UI/Alignment', + 'UI/CloseOverlay': 'WoltLab/WCF/UI/CloseOverlay', 'UI/Confirmation': 'WoltLab/WCF/UI/Confirmation', 'UI/Dialog': 'WoltLab/WCF/UI/Dialog', 'UI/SimpleDropdown': 'WoltLab/WCF/UI/Dropdown/Simple', -- 2.20.1