From b5a32d797d19372cefa5211c8867d48f64b52b45 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Sun, 24 May 2015 12:55:50 +0200 Subject: [PATCH] Updated WoltLab/WCF/Ajax implementation --- wcfsetup/install/files/js/WoltLab/WCF/Ajax.js | 21 ++++++++ .../files/js/WoltLab/WCF/Ajax/Request.js | 50 +++++++++++-------- .../files/js/WoltLab/WCF/Ajax/Status.js | 4 ++ .../files/js/WoltLab/WCF/BootstrapFrontend.js | 22 ++++---- .../WoltLab/WCF/Controller/Notice/Dismiss.js | 2 +- .../js/WoltLab/WCF/Controller/Popover.js | 22 +++++++- .../WoltLab/WCF/Controller/Style/Changer.js | 4 +- wcfsetup/install/files/js/WoltLab/WCF/Core.js | 48 ++++++++++++++++++ wcfsetup/install/files/style/dialog.less | 11 ++++ 9 files changed, 145 insertions(+), 39 deletions(-) diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ajax.js b/wcfsetup/install/files/js/WoltLab/WCF/Ajax.js index 9b1a14c29b..d7337037db 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ajax.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ajax.js @@ -24,10 +24,27 @@ define(['AjaxRequest', 'Core', 'ObjectMap'], function(AjaxRequest, Core, ObjectM * @return {AjaxRequest} */ api: function(callbackObject, data) { + return this.apiProxy(callbackObject, data); + }, + + /** + * Shorthand function to perform a request against the WCF-API with overrides + * for success and failure callbacks. + * + * @param {object} callbackObject callback object + * @param {object=} data request data + * @param {function=} success success callback + * @param {function=} failure failure callback + * @return {AjaxRequest} + */ + apiProxy: function(callbackObject, data, success, failure) { var request = _requests.get(callbackObject); if (request !== undefined) { data = data || {}; + if (typeof success === 'function') request.setOption('success', success); + if (typeof failure === 'function') request.setOption('failure', failure); + request.setData(data || {}); request.sendRequest(); @@ -49,6 +66,10 @@ define(['AjaxRequest', 'Core', 'ObjectMap'], function(AjaxRequest, Core, ObjectM if (!options.url) options.url = 'index.php/AJAXProxy/?t=' + SECURITY_TOKEN; request = new AjaxRequest(options); + + if (typeof success === 'function') request.setOption('success', success); + if (typeof failure === 'function') request.setOption('failure', failure); + request.sendRequest(); _requests.set(callbackObject, request); diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Request.js b/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Request.js index d90c66088f..aa5c0b37a0 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Request.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Request.js @@ -46,9 +46,9 @@ define(['Core', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Dialog', 'Wolt } if (this._options.callbackObject !== null) { - this._options.failure = (typeof this._options.callbackObject._ajaxFailure === 'function') ? this._options.callbackObject._ajaxFailure.bind(this._options.callbackObject) : null; - this._options.finalize = (typeof this._options.callbackObject._ajaxFinalize === 'function') ? this._options.callbackObject._ajaxFinalize.bind(this._options.callbackObject) : null; - this._options.success = (typeof this._options.callbackObject._ajaxSuccess === 'function') ? this._options.callbackObject._ajaxSuccess.bind(this._options.callbackObject) : null; + if (typeof this._options.callbackObject._ajaxFailure === 'function') this._options.failure = this._options.callbackObject._ajaxFailure.bind(this._options.callbackObject); + if (typeof this._options.callbackObject._ajaxFinalize === 'function') this._options.finalize = this._options.callbackObject._ajaxFinalize.bind(this._options.callbackObject); + if (typeof this._options.callbackObject._ajaxSuccess === 'function') this._options.success = this._options.callbackObject._ajaxSuccess.bind(this._options.callbackObject); } if (_didInit === false) { @@ -82,18 +82,20 @@ define(['Core', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Dialog', 'Wolt this._xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); var self = this; + + var options = Core.clone(this._options); this._xhr.onload = function() { if (this.readyState === XMLHttpRequest.DONE) { if (this.status >= 200 && this.status < 300 || this.status === 304) { - self._success(this); + self._success(this, options); } else { - self._failure(this); + self._failure(this, options); } } }; this._xhr.onerror = function() { - self._failure(this); + self._failure(this, options); }; if (this._options.type === 'POST') { @@ -156,14 +158,15 @@ define(['Core', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Dialog', 'Wolt /** * Handles a successful request. * - * @param {XMLHttpRequest} xhr request object + * @param {XMLHttpRequest} xhr request object + * @param {object} options request options */ - _success: function(xhr) { - if (!this._options.silent) { + _success: function(xhr, options) { + if (!options.silent) { AjaxStatus.hide(); } - if (typeof this._options.success === 'function') { + if (typeof options.success === 'function') { var data = null; if (xhr.getResponseHeader('Content-Type') === 'application/json') { try { @@ -182,24 +185,25 @@ define(['Core', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Dialog', 'Wolt } } - this._options.success(data, xhr.responseText, xhr); + options.success(data, xhr.responseText, xhr); } - this._finalize(); + this._finalize(options); }, /** * Handles failed requests, this can be both a successful request with * a non-success status code or an entirely failed request. * - * @param {XMLHttpRequest} xhr request object + * @param {XMLHttpRequest} xhr request object + * @param {object} options request options */ - _failure: function (xhr) { + _failure: function (xhr, options) { if (_ignoreAllErrors) { return; } - if (!this._options.silent) { + if (!options.silent) { AjaxStatus.hide(); } @@ -210,11 +214,11 @@ define(['Core', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Dialog', 'Wolt catch (e) {} var showError = true; - if (typeof this._options.failure === 'function') { - showError = this._options.failure(data, xhr); + if (typeof options.failure === 'function') { + showError = options.failure(data, xhr); } - if (this._options.ignoreError !== true && showError !== false) { + if (options.ignoreError !== true && showError !== false) { var details = ''; var message = ''; @@ -239,15 +243,17 @@ define(['Core', 'Language', 'DOM/ChangeListener', 'DOM/Util', 'UI/Dialog', 'Wolt }); } - this._finalize(); + this._finalize(options); }, /** * Finalizes a request. + * + * @param {object} options request options */ - _finalize: function() { - if (typeof this._options.finalize === 'function') { - this._options.finalize(this._xhr); + _finalize: function(options) { + if (typeof options.finalize === 'function') { + options.finalize(this._xhr); } this._previousXhr = null; diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Status.js b/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Status.js index 7eedcc80ac..2827404d73 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Status.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Ajax/Status.js @@ -68,8 +68,12 @@ define(['Language'], function(Language) { window.clearTimeout(_timeoutShow); } + console.debug("Removing 'active'!"); + window.dt = _overlay; _overlay.classList.remove('active'); } + + console.debug(_activeRequests); } }; diff --git a/wcfsetup/install/files/js/WoltLab/WCF/BootstrapFrontend.js b/wcfsetup/install/files/js/WoltLab/WCF/BootstrapFrontend.js index ad046fd663..20dfb36287 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/BootstrapFrontend.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/BootstrapFrontend.js @@ -40,19 +40,15 @@ define(['Ajax', 'WoltLab/WCF/Bootstrap', 'WoltLab/WCF/Controller/Sitemap', 'Wolt className: 'userLink', identifier: 'com.woltlab.wcf.user', loadCallback: function(objectId, popover) { - Ajax.api({ - data: { - actionName: 'getUserProfile', - className: 'wcf\\data\\user\\UserProfileAction', - objectIDs: [ objectId ] - }, - success: (function(data) { - popover.setContent('com.woltlab.wcf.user', objectId, data.returnValues.template); - }).bind(this), - failure: (function(data) { - popover.setContent('com.woltlab.wcf.user', objectId, data.returnValues.template); - }).bind(this) - }); + var callback = function(data) { + popover.setContent('com.woltlab.wcf.user', objectId, data.returnValues.template); + }; + + popover.ajaxApi({ + actionName: 'getUserProfile', + className: 'wcf\\data\\user\\UserProfileAction', + objectIDs: [ objectId ] + }, callback, callback); } }); } diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Controller/Notice/Dismiss.js b/wcfsetup/install/files/js/WoltLab/WCF/Controller/Notice/Dismiss.js index 757db6e246..2a0d58645a 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Controller/Notice/Dismiss.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Controller/Notice/Dismiss.js @@ -34,7 +34,7 @@ define(['Ajax'], function(Ajax) { _click: function(event) { var button = event.currentTarget; - Ajax.api({ + Ajax.apiOnce({ data: { actionName: 'dismiss', className: 'wcf\\data\\notice\\NoticeAction', diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Controller/Popover.js b/wcfsetup/install/files/js/WoltLab/WCF/Controller/Popover.js index a54801875f..fec8f529e9 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Controller/Popover.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Controller/Popover.js @@ -6,7 +6,7 @@ * @license GNU Lesser General Public License * @module WoltLab/WCF/Controller/Popover */ -define(['Dictionary', 'Environment', 'DOM/ChangeListener', 'DOM/Util', 'UI/Alignment'], function(Dictionary, Environment, DOMChangeListener, DOMUtil, UIAlignment) { +define(['Ajax', 'Dictionary', 'Environment', 'DOM/ChangeListener', 'DOM/Util', 'UI/Alignment'], function(Ajax, Dictionary, Environment, DOMChangeListener, DOMUtil, UIAlignment) { "use strict"; var _activeId = null; @@ -399,6 +399,26 @@ define(['Dictionary', 'Environment', 'DOM/ChangeListener', 'DOM/Util', 'UI/Align vertical: 'top', verticalOffset: 3 }); + }, + + _ajaxSetup: function() { + // does nothing + return {}; + }, + + /** + * Sends an AJAX requests to the server, simple wrapper to reuse the request object. + * + * @param {object} data request data + * @param {function} success success callback + * @param {function=} failure error callback + */ + ajaxApi: function(data, success, failure) { + if (typeof success !== 'function') { + throw new TypeError("Expected a valid callback for parameter 'success'."); + } + + Ajax.apiProxy(this, data, success, failure); } }; diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Controller/Style/Changer.js b/wcfsetup/install/files/js/WoltLab/WCF/Controller/Style/Changer.js index d966ea3ef3..9ea7a3ce82 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Controller/Style/Changer.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Controller/Style/Changer.js @@ -44,7 +44,7 @@ define(['Ajax', 'Language', 'UI/Dialog'], function(Ajax, Language, UIDialog) { event.preventDefault(); if (UIDialog.getDialog('styleChanger') === undefined) { - Ajax.api({ + Ajax.apiOnce({ data: { actionName: 'getStyleChooser', className: 'wcf\\data\\style\\StyleAction' @@ -78,7 +78,7 @@ define(['Ajax', 'Language', 'UI/Dialog'], function(Ajax, Language, UIDialog) { _click: function(event) { event.preventDefault(); - Ajax.api({ + Ajax.apiOnce({ data: { actionName: 'changeStyle', className: 'wcf\\data\\style\\StyleAction', diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Core.js b/wcfsetup/install/files/js/WoltLab/WCF/Core.js index 249c7e9764..811a7189e8 100644 --- a/wcfsetup/install/files/js/WoltLab/WCF/Core.js +++ b/wcfsetup/install/files/js/WoltLab/WCF/Core.js @@ -9,11 +9,59 @@ define([], function() { "use strict"; + var _clone = function(variable) { + if (typeof variable === 'object' && variable !== null) { + return _cloneObject(variable); + } + + return variable; + }; + + var _cloneArray = function(oldArray) { + var i = oldArray.length; + var newArray = new Array(i); + + while (i--) { + newArray[i] = oldArray[i]; + } + + return newArray; + }; + + var _cloneObject = function(obj) { + if (!obj) { + return null; + } + + if (Array.isArray(obj)) { + return _cloneArray(obj); + } + + var newObj = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key) && typeof obj[key] !== 'undefined') { + newObj[key] = _clone(obj[key]); + } + } + + return newObj; + }; + /** * @constructor */ function Core() {}; Core.prototype = { + /** + * Deep clones an object. + * + * @param {object} obj source object + * @return {object} cloned object + */ + clone: function(obj) { + return _clone(obj); + }, + /** * Converts WCF 2.0-style URLs into the default URL layout. * diff --git a/wcfsetup/install/files/style/dialog.less b/wcfsetup/install/files/style/dialog.less index d3ef290337..2d7b98d94b 100644 --- a/wcfsetup/install/files/style/dialog.less +++ b/wcfsetup/install/files/style/dialog.less @@ -171,10 +171,12 @@ box-sizing: border-box; color: #fff; left: 50%; + opacity: 0; padding: 7px; position: fixed; text-align: center; top: 200px; + visibility: hidden; z-index: 401; transform: translateX(-50%); @@ -182,6 +184,15 @@ .boxShadow(0, 1px, rgba(0, 0, 0, .5), 7px); .linearGradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, 0), rgba(0, 0, 0, .7)); + transition: visibility 0s linear .1s, opacity .1s linear; + + &.active { + opacity: 1; + visibility: visible; + + transition-delay: 0s; + } + > .icon { color: #fff; } -- 2.20.1