}
var options = callbackObject._ajaxSetup();
- if (typeof data === 'object') {
- options.data = Core.extend(data, options.data);
- }
options.pinData = true;
options.callbackObject = callbackObject;
if (typeof success === 'function') request.setOption('success', success);
if (typeof failure === 'function') request.setOption('failure', failure);
+ if (typeof data === 'object') {
+ request.setData(data);
+ }
+
request.sendRequest();
_requests.set(callbackObject, request);
callbackObject: null
}, options);
+ if (typeof options.callbackObject === 'object') {
+ this._options.callbackObject = options.callbackObject;
+ }
+
this._options.url = Core.convertLegacyUrl(this._options.url);
if (this._options.pinData) {
*/
extend: function(out) {
out = out || {};
+ var newObj = this.clone(out);
for (var i = 1, length = arguments.length; i < length; i++) {
var obj = arguments[i];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (!Array.isArray(obj[key]) && typeof obj[key] === 'object') {
- this.extend(out[key], obj[key]);
+ if (this.isPlainObject(obj[key])) {
+ // object literals have the prototype of Object which in return has no parent prototype
+ newObj[key] = this.extend(out[key], obj[key]);
+ }
+ else {
+ newObj[key] = obj[key];
+ }
}
else {
- out[key] = obj[key];
+ newObj[key] = obj[key];
}
}
}
}
- return out;
+ return newObj;
+ },
+
+ /**
+ * Returns true if `obj` is an object literal.
+ *
+ * @param {*} obj target object
+ * @returns {boolean} true if target is an object literal
+ */
+ isPlainObject: function(obj) {
+ if (obj === window || obj.nodeType) {
+ return false;
+ }
+
+ if (obj.constructor && !obj.constructor.prototype.hasOwnProperty('isPrototypeOf')) {
+ return false;
+ }
+
+ return true;
},
/**
* Recursively serializes an object into an encoded URI parameter string.
*
* @param {object} obj target object
+ * @param {string=} prefix parameter prefix
* @return encoded parameter string
*/
- serialize: function(obj) {
+ serialize: function(obj, prefix) {
var parameters = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
+ var parameterKey = (prefix) ? prefix + '[' + key + ']' : key;
var value = obj[key];
- if (Array.isArray(value)) {
- for (var i = 0, length = value.length; i < length; i++) {
- parameters.push(key + '[]=' + encodeURIComponent(value[i]));
- }
-
- continue;
+ if (typeof value === 'object') {
+ parameters.push(this.serialize(value, parameterKey));
}
- else if (this.getType(value) === 'Object') {
- parameters.push(this.serialize(value));
-
- continue;
+ else {
+ parameters.push(encodeURIComponent(parameterKey) + '=' + encodeURIComponent(value));
}
-
- parameters.push(key + '=' + encodeURIComponent(value));
}
}
--- /dev/null
+/**
+ * Provides the confirmation dialog overlay.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLab/WCF/UI/Confirmation
+ */
+define(['Core', 'Language', 'UI/Dialog'], function(Core, Language, UIDialog) {
+ "use strict";
+
+ var _active = false;
+ var _confirmButton = null;
+ var _content = null;
+ var _options = {};
+ var _text = null;
+
+ /**
+ * Confirmation dialog overlay.
+ *
+ * @exports WoltLab/WCF/UI/Confirmation
+ */
+ var UIConfirmation = {
+ /**
+ * Shows the confirmation dialog.
+ *
+ * Possible options:
+ * - cancel: callback if user cancels the dialog
+ * - confirm: callback if user confirm the dialog
+ * - legacyCallback: WCF 2.0/2.1 compatible callback with string parameter
+ * - message: displayed confirmation message
+ * - parameters: list of parameters passed to the callback on confirm
+ * - template: optional HTML string to be inserted below the `message`
+ *
+ * @param {object<string, *>} options confirmation options
+ */
+ show: function(options) {
+ if (_active) {
+ return;
+ }
+
+ _options = Core.extend({
+ cancel: null,
+ confirm: null,
+ legacyCallback: null,
+ message: '',
+ parameters: {},
+ template: ''
+ }, options);
+
+ _options.message = (typeof _options.message === 'string') ? _options.message.trim() : '';
+ if (!_options.message.length) {
+ throw new Error("Expected a non-empty string for option 'message'.");
+ }
+
+ if (typeof _options.confirm !== 'function' && typeof _options.legacyCallback !== 'function') {
+ throw new TypeError("Expected a valid callback for option 'confirm'.");
+ }
+
+ if (_content === null) {
+ this._createDialog();
+ }
+
+ _content.innerHTML = (typeof options.template === 'string') ? options.template.trim() : '';
+ _text.textContent = _options.message;
+
+ _active = true;
+
+ UIDialog.open('wcfSystemConfirmation', null, {
+ onClose: this._onClose.bind(this),
+ onShow: this._onShow.bind(this),
+ title: Language.get('wcf.global.confirmation.title')
+ });
+ },
+
+ /**
+ * Creates the dialog DOM elements.
+ */
+ _createDialog: function() {
+ var dialog = document.createElement('div');
+ dialog.setAttribute('id', 'wcfSystemConfirmation');
+ dialog.classList.add('systemConfirmation');
+
+ _text = document.createElement('p');
+ dialog.appendChild(_text);
+
+ _content = document.createElement('div');
+ _content.setAttribute('id', 'wcfSystemConfirmationContent');
+ dialog.appendChild(_content);
+
+ var formSubmit = document.createElement('div');
+ formSubmit.classList.add('formSubmit');
+ dialog.appendChild(formSubmit);
+
+ _confirmButton = document.createElement('button');
+ _confirmButton.classList.add('buttonPrimary');
+ _confirmButton.textContent = Language.get('wcf.global.confirmation.confirm');
+ _confirmButton.addEventListener('click', this._confirm.bind(this));
+ formSubmit.appendChild(_confirmButton);
+
+ var cancelButton = document.createElement('button');
+ cancelButton.textContent = Language.get('wcf.global.confirmation.cancel');
+ cancelButton.addEventListener('click', function() { UIDialog.close('wcfSystemConfirmation'); });
+ formSubmit.appendChild(cancelButton);
+
+ document.body.appendChild(dialog);
+ },
+
+ /**
+ * Invoked if the user confirms the dialog.
+ */
+ _confirm: function() {
+ if (typeof _options.legacyCallback === 'function') {
+ _options.legacyCallback('confirm', _options.parameters);
+ }
+ else {
+ _options.confirm(_options.parameters);
+ }
+
+ _active = false;
+ UIDialog.close('wcfSystemConfirmation');
+ },
+
+ /**
+ * Invoked on dialog close or if user cancels the dialog.
+ */
+ _onClose: function() {
+ if (_active) {
+ _confirmButton.blur();
+ _active = false;
+
+ if (typeof _options.legacyCallback === 'function') {
+ _options.legacyCallback('cancel', _options.parameters);
+ }
+ else if (typeof _options.cancel === 'function') {
+ _options.cancel(_options.parameters);
+ }
+ }
+ },
+
+ /**
+ * Sets the focus on the confirm button on dialog open for proper keyboard support.
+ */
+ _onShow: function() {
+ _confirmButton.blur();
+ _confirmButton.focus();
+ }
+ };
+
+ return UIConfirmation;
+});
setTimeout(function() {
if (data.dialog.getAttribute('aria-hidden') === 'true') {
_container.removeChild(data.dialog);
- _dialogs.delete(id);
+ _dialogs['delete'](id);
}
}, 5000);
}
use wcf\util\ClassUtil;
use wcf\util\JSON;
use wcf\util\StringUtil;
+use wcf\util\ArrayUtil;
/**
* Default implementation for DatabaseObject-related actions.
const TYPE_BOOLEAN = 3;
const TYPE_JSON = 4;
+ const STRUCT_FLAT = 1;
+ const STRUCT_ARRAY = 2;
+
/**
* Initialize a new DatabaseObject-related action.
*
* @param string $arrayIndex
*/
protected function readInteger($variableName, $allowEmpty = false, $arrayIndex = '') {
- $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_INTEGER);
+ $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_INTEGER, self::STRUCT_FLAT);
+ }
+
+ /**
+ * Reads an integer array and validates it.
+ *
+ * @param string $variableName
+ * @param boolean $allowEmpty
+ * @param string $arrayIndex
+ */
+ protected function readIntegerArray($variableName, $allowEmpty = false, $arrayIndex = '') {
+ $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_INTEGER, self::STRUCT_ARRAY);
}
/**
* @param string $arrayIndex
*/
protected function readString($variableName, $allowEmpty = false, $arrayIndex = '') {
- $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_STRING);
+ $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_STRING, self::STRUCT_FLAT);
}
/**
* @param string $arrayIndex
*/
protected function readBoolean($variableName, $allowEmpty = false, $arrayIndex = '') {
- $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_BOOLEAN);
+ $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_BOOLEAN, self::STRUCT_FLAT);
}
/**
* @param string $arrayIndex
*/
protected function readJSON($variableName, $allowEmpty = false, $arrayIndex = '') {
- $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_JSON);
+ $this->readValue($variableName, $allowEmpty, $arrayIndex, self::TYPE_JSON, self::STRUCT_FLAT);
}
/**
* @param boolean $allowEmpty
* @param string $arrayIndex
* @param integer $type
+ * @param integer $structure
*/
- protected function readValue($variableName, $allowEmpty, $arrayIndex, $type) {
+ protected function readValue($variableName, $allowEmpty, $arrayIndex, $type, $structure) {
if ($arrayIndex) {
if (!isset($this->parameters[$arrayIndex])) {
throw new SystemException("Corrupt parameters, index '".$arrayIndex."' is missing");
case self::TYPE_INTEGER:
if (!isset($target[$variableName])) {
if ($allowEmpty) {
- $target[$variableName] = 0;
+ $target[$variableName] = ($structure === self::STRUCT_FLAT) ? 0 : array();
}
else {
throw new UserInputException($variableName);
}
}
else {
- $target[$variableName] = intval($target[$variableName]);
- if (!$allowEmpty && !$target[$variableName]) {
- throw new UserInputException($variableName);
+ if ($structure === self::STRUCT_FLAT) {
+ $target[$variableName] = intval($target[$variableName]);
+ if (!$allowEmpty && !$target[$variableName]) {
+ throw new UserInputException($variableName);
+ }
+ }
+ else {
+ $target[$variableName] = ArrayUtil::toIntegerArray($target[$variableName]);
+ if (!is_array($target[$variableName])) {
+ throw new UserInputException($variableName);
+ }
+
+ for ($i = 0, $length = count($target[$variableName]); $i < $length; $i++) {
+ if ($target[$variableName][$i] === 0) {
+ throw new UserInputException($variableName);
+ }
+ }
}
}
break;