Commit 57ff5efceef31375817150fb86815d5985d07f89

Authored by Yarik
1 parent 3735dff7

test

common/models/Project.php
... ... @@ -207,6 +207,7 @@
207 207 'specializationInput' => Yii::t('app', 'specializationInput'),
208 208 'paymentInput' => Yii::t('app', 'paymentInput'),
209 209 'specializationString' => Yii::t('app', 'specializationString'),
  210 + 'hidden' => 'Снять с тендера',
210 211 ];
211 212 }
212 213  
... ...
common/modules/fileloader/resources/jquery.fileupload.js 0 → 100644
  1 +/*
  2 + * jQuery File Upload Plugin
  3 + * https://github.com/blueimp/jQuery-File-Upload
  4 + *
  5 + * Copyright 2010, Sebastian Tschan
  6 + * https://blueimp.net
  7 + *
  8 + * Licensed under the MIT license:
  9 + * http://www.opensource.org/licenses/MIT
  10 + */
  11 +
  12 +/* jshint nomen:false */
  13 +/* global define, require, window, document, location, Blob, FormData */
  14 +
  15 +(function (factory) {
  16 + 'use strict';
  17 + if (typeof define === 'function' && define.amd) {
  18 + // Register as an anonymous AMD module:
  19 + define([
  20 + 'jquery',
  21 + 'jquery.ui.widget'
  22 + ], factory);
  23 + } else if (typeof exports === 'object') {
  24 + // Node/CommonJS:
  25 + factory(
  26 + require('jquery'),
  27 + require('./vendor/jquery.ui.widget')
  28 + );
  29 + } else {
  30 + // Browser globals:
  31 + factory(window.jQuery);
  32 + }
  33 +}(function ($) {
  34 + 'use strict';
  35 +
  36 + // Detect file input support, based on
  37 + // http://viljamis.com/blog/2012/file-upload-support-on-mobile/
  38 + $.support.fileInput = !(new RegExp(
  39 + // Handle devices which give false positives for the feature detection:
  40 + '(Android (1\\.[0156]|2\\.[01]))' +
  41 + '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
  42 + '|(w(eb)?OSBrowser)|(webOS)' +
  43 + '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
  44 + ).test(window.navigator.userAgent) ||
  45 + // Feature detection for all other devices:
  46 + $('<input type="file">').prop('disabled'));
  47 +
  48 + // The FileReader API is not actually used, but works as feature detection,
  49 + // as some Safari versions (5?) support XHR file uploads via the FormData API,
  50 + // but not non-multipart XHR file uploads.
  51 + // window.XMLHttpRequestUpload is not available on IE10, so we check for
  52 + // window.ProgressEvent instead to detect XHR2 file upload capability:
  53 + $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
  54 + $.support.xhrFormDataFileUpload = !!window.FormData;
  55 +
  56 + // Detect support for Blob slicing (required for chunked uploads):
  57 + $.support.blobSlice = window.Blob && (Blob.prototype.slice ||
  58 + Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
  59 +
  60 + // Helper function to create drag handlers for dragover/dragenter/dragleave:
  61 + function getDragHandler(type) {
  62 + var isDragOver = type === 'dragover';
  63 + return function (e) {
  64 + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
  65 + var dataTransfer = e.dataTransfer;
  66 + if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
  67 + this._trigger(
  68 + type,
  69 + $.Event(type, {delegatedEvent: e})
  70 + ) !== false) {
  71 + e.preventDefault();
  72 + if (isDragOver) {
  73 + dataTransfer.dropEffect = 'copy';
  74 + }
  75 + }
  76 + };
  77 + }
  78 +
  79 + // The fileupload widget listens for change events on file input fields defined
  80 + // via fileInput setting and paste or drop events of the given dropZone.
  81 + // In addition to the default jQuery Widget methods, the fileupload widget
  82 + // exposes the "add" and "send" methods, to add or directly send files using
  83 + // the fileupload API.
  84 + // By default, files added via file input selection, paste, drag & drop or
  85 + // "add" method are uploaded immediately, but it is possible to override
  86 + // the "add" callback option to queue file uploads.
  87 + $.widget('blueimp.fileupload', {
  88 +
  89 + options: {
  90 + // The drop target element(s), by the default the complete document.
  91 + // Set to null to disable drag & drop support:
  92 + dropZone: $(document),
  93 + // The paste target element(s), by the default undefined.
  94 + // Set to a DOM node or jQuery object to enable file pasting:
  95 + pasteZone: undefined,
  96 + // The file input field(s), that are listened to for change events.
  97 + // If undefined, it is set to the file input fields inside
  98 + // of the widget element on plugin initialization.
  99 + // Set to null to disable the change listener.
  100 + fileInput: undefined,
  101 + // By default, the file input field is replaced with a clone after
  102 + // each input field change event. This is required for iframe transport
  103 + // queues and allows change events to be fired for the same file
  104 + // selection, but can be disabled by setting the following option to false:
  105 + replaceFileInput: true,
  106 + // The parameter name for the file form data (the request argument name).
  107 + // If undefined or empty, the name property of the file input field is
  108 + // used, or "files[]" if the file input name property is also empty,
  109 + // can be a string or an array of strings:
  110 + paramName: undefined,
  111 + // By default, each file of a selection is uploaded using an individual
  112 + // request for XHR type uploads. Set to false to upload file
  113 + // selections in one request each:
  114 + singleFileUploads: true,
  115 + // To limit the number of files uploaded with one XHR request,
  116 + // set the following option to an integer greater than 0:
  117 + limitMultiFileUploads: undefined,
  118 + // The following option limits the number of files uploaded with one
  119 + // XHR request to keep the request size under or equal to the defined
  120 + // limit in bytes:
  121 + limitMultiFileUploadSize: undefined,
  122 + // Multipart file uploads add a number of bytes to each uploaded file,
  123 + // therefore the following option adds an overhead for each file used
  124 + // in the limitMultiFileUploadSize configuration:
  125 + limitMultiFileUploadSizeOverhead: 512,
  126 + // Set the following option to true to issue all file upload requests
  127 + // in a sequential order:
  128 + sequentialUploads: false,
  129 + // To limit the number of concurrent uploads,
  130 + // set the following option to an integer greater than 0:
  131 + limitConcurrentUploads: undefined,
  132 + // Set the following option to true to force iframe transport uploads:
  133 + forceIframeTransport: false,
  134 + // Set the following option to the location of a redirect url on the
  135 + // origin server, for cross-domain iframe transport uploads:
  136 + redirect: undefined,
  137 + // The parameter name for the redirect url, sent as part of the form
  138 + // data and set to 'redirect' if this option is empty:
  139 + redirectParamName: undefined,
  140 + // Set the following option to the location of a postMessage window,
  141 + // to enable postMessage transport uploads:
  142 + postMessage: undefined,
  143 + // By default, XHR file uploads are sent as multipart/form-data.
  144 + // The iframe transport is always using multipart/form-data.
  145 + // Set to false to enable non-multipart XHR uploads:
  146 + multipart: true,
  147 + // To upload large files in smaller chunks, set the following option
  148 + // to a preferred maximum chunk size. If set to 0, null or undefined,
  149 + // or the browser does not support the required Blob API, files will
  150 + // be uploaded as a whole.
  151 + maxChunkSize: undefined,
  152 + // When a non-multipart upload or a chunked multipart upload has been
  153 + // aborted, this option can be used to resume the upload by setting
  154 + // it to the size of the already uploaded bytes. This option is most
  155 + // useful when modifying the options object inside of the "add" or
  156 + // "send" callbacks, as the options are cloned for each file upload.
  157 + uploadedBytes: undefined,
  158 + // By default, failed (abort or error) file uploads are removed from the
  159 + // global progress calculation. Set the following option to false to
  160 + // prevent recalculating the global progress data:
  161 + recalculateProgress: true,
  162 + // Interval in milliseconds to calculate and trigger progress events:
  163 + progressInterval: 100,
  164 + // Interval in milliseconds to calculate progress bitrate:
  165 + bitrateInterval: 500,
  166 + // By default, uploads are started automatically when adding files:
  167 + autoUpload: true,
  168 +
  169 + // Error and info messages:
  170 + messages: {
  171 + uploadedBytes: 'Uploaded bytes exceed file size'
  172 + },
  173 +
  174 + // Translation function, gets the message key to be translated
  175 + // and an object with context specific data as arguments:
  176 + i18n: function (message, context) {
  177 + message = this.messages[message] || message.toString();
  178 + if (context) {
  179 + $.each(context, function (key, value) {
  180 + message = message.replace('{' + key + '}', value);
  181 + });
  182 + }
  183 + return message;
  184 + },
  185 +
  186 + // Additional form data to be sent along with the file uploads can be set
  187 + // using this option, which accepts an array of objects with name and
  188 + // value properties, a function returning such an array, a FormData
  189 + // object (for XHR file uploads), or a simple object.
  190 + // The form of the first fileInput is given as parameter to the function:
  191 + formData: function (form) {
  192 + return form.serializeArray();
  193 + },
  194 +
  195 + // The add callback is invoked as soon as files are added to the fileupload
  196 + // widget (via file input selection, drag & drop, paste or add API call).
  197 + // If the singleFileUploads option is enabled, this callback will be
  198 + // called once for each file in the selection for XHR file uploads, else
  199 + // once for each file selection.
  200 + //
  201 + // The upload starts when the submit method is invoked on the data parameter.
  202 + // The data object contains a files property holding the added files
  203 + // and allows you to override plugin options as well as define ajax settings.
  204 + //
  205 + // Listeners for this callback can also be bound the following way:
  206 + // .bind('fileuploadadd', func);
  207 + //
  208 + // data.submit() returns a Promise object and allows to attach additional
  209 + // handlers using jQuery's Deferred callbacks:
  210 + // data.submit().done(func).fail(func).always(func);
  211 + add: function (e, data) {
  212 + if (e.isDefaultPrevented()) {
  213 + return false;
  214 + }
  215 + if (data.autoUpload || (data.autoUpload !== false &&
  216 + $(this).fileupload('option', 'autoUpload'))) {
  217 + data.process().done(function () {
  218 + data.submit();
  219 + });
  220 + }
  221 + },
  222 +
  223 + // Other callbacks:
  224 +
  225 + // Callback for the submit event of each file upload:
  226 + // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
  227 +
  228 + // Callback for the start of each file upload request:
  229 + // send: function (e, data) {}, // .bind('fileuploadsend', func);
  230 +
  231 + // Callback for successful uploads:
  232 + // done: function (e, data) {}, // .bind('fileuploaddone', func);
  233 +
  234 + // Callback for failed (abort or error) uploads:
  235 + // fail: function (e, data) {}, // .bind('fileuploadfail', func);
  236 +
  237 + // Callback for completed (success, abort or error) requests:
  238 + // always: function (e, data) {}, // .bind('fileuploadalways', func);
  239 +
  240 + // Callback for upload progress events:
  241 + // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
  242 +
  243 + // Callback for global upload progress events:
  244 + // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
  245 +
  246 + // Callback for uploads start, equivalent to the global ajaxStart event:
  247 + // start: function (e) {}, // .bind('fileuploadstart', func);
  248 +
  249 + // Callback for uploads stop, equivalent to the global ajaxStop event:
  250 + // stop: function (e) {}, // .bind('fileuploadstop', func);
  251 +
  252 + // Callback for change events of the fileInput(s):
  253 + // change: function (e, data) {}, // .bind('fileuploadchange', func);
  254 +
  255 + // Callback for paste events to the pasteZone(s):
  256 + // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
  257 +
  258 + // Callback for drop events of the dropZone(s):
  259 + // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
  260 +
  261 + // Callback for dragover events of the dropZone(s):
  262 + // dragover: function (e) {}, // .bind('fileuploaddragover', func);
  263 +
  264 + // Callback for the start of each chunk upload request:
  265 + // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
  266 +
  267 + // Callback for successful chunk uploads:
  268 + // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
  269 +
  270 + // Callback for failed (abort or error) chunk uploads:
  271 + // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
  272 +
  273 + // Callback for completed (success, abort or error) chunk upload requests:
  274 + // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
  275 +
  276 + // The plugin options are used as settings object for the ajax calls.
  277 + // The following are jQuery ajax settings required for the file uploads:
  278 + processData: false,
  279 + contentType: false,
  280 + cache: false,
  281 + timeout: 0
  282 + },
  283 +
  284 + // A list of options that require reinitializing event listeners and/or
  285 + // special initialization code:
  286 + _specialOptions: [
  287 + 'fileInput',
  288 + 'dropZone',
  289 + 'pasteZone',
  290 + 'multipart',
  291 + 'forceIframeTransport'
  292 + ],
  293 +
  294 + _blobSlice: $.support.blobSlice && function () {
  295 + var slice = this.slice || this.webkitSlice || this.mozSlice;
  296 + return slice.apply(this, arguments);
  297 + },
  298 +
  299 + _BitrateTimer: function () {
  300 + this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
  301 + this.loaded = 0;
  302 + this.bitrate = 0;
  303 + this.getBitrate = function (now, loaded, interval) {
  304 + var timeDiff = now - this.timestamp;
  305 + if (!this.bitrate || !interval || timeDiff > interval) {
  306 + this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
  307 + this.loaded = loaded;
  308 + this.timestamp = now;
  309 + }
  310 + return this.bitrate;
  311 + };
  312 + },
  313 +
  314 + _isXHRUpload: function (options) {
  315 + return !options.forceIframeTransport &&
  316 + ((!options.multipart && $.support.xhrFileUpload) ||
  317 + $.support.xhrFormDataFileUpload);
  318 + },
  319 +
  320 + _getFormData: function (options) {
  321 + var formData;
  322 + if ($.type(options.formData) === 'function') {
  323 + return options.formData(options.form);
  324 + }
  325 + if ($.isArray(options.formData)) {
  326 + return options.formData;
  327 + }
  328 + if ($.type(options.formData) === 'object') {
  329 + formData = [];
  330 + $.each(options.formData, function (name, value) {
  331 + formData.push({name: name, value: value});
  332 + });
  333 + return formData;
  334 + }
  335 + return [];
  336 + },
  337 +
  338 + _getTotal: function (files) {
  339 + var total = 0;
  340 + $.each(files, function (index, file) {
  341 + total += file.size || 1;
  342 + });
  343 + return total;
  344 + },
  345 +
  346 + _initProgressObject: function (obj) {
  347 + var progress = {
  348 + loaded: 0,
  349 + total: 0,
  350 + bitrate: 0
  351 + };
  352 + if (obj._progress) {
  353 + $.extend(obj._progress, progress);
  354 + } else {
  355 + obj._progress = progress;
  356 + }
  357 + },
  358 +
  359 + _initResponseObject: function (obj) {
  360 + var prop;
  361 + if (obj._response) {
  362 + for (prop in obj._response) {
  363 + if (obj._response.hasOwnProperty(prop)) {
  364 + delete obj._response[prop];
  365 + }
  366 + }
  367 + } else {
  368 + obj._response = {};
  369 + }
  370 + },
  371 +
  372 + _onProgress: function (e, data) {
  373 + if (e.lengthComputable) {
  374 + var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
  375 + loaded;
  376 + if (data._time && data.progressInterval &&
  377 + (now - data._time < data.progressInterval) &&
  378 + e.loaded !== e.total) {
  379 + return;
  380 + }
  381 + data._time = now;
  382 + loaded = Math.floor(
  383 + e.loaded / e.total * (data.chunkSize || data._progress.total)
  384 + ) + (data.uploadedBytes || 0);
  385 + // Add the difference from the previously loaded state
  386 + // to the global loaded counter:
  387 + this._progress.loaded += (loaded - data._progress.loaded);
  388 + this._progress.bitrate = this._bitrateTimer.getBitrate(
  389 + now,
  390 + this._progress.loaded,
  391 + data.bitrateInterval
  392 + );
  393 + data._progress.loaded = data.loaded = loaded;
  394 + data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
  395 + now,
  396 + loaded,
  397 + data.bitrateInterval
  398 + );
  399 + // Trigger a custom progress event with a total data property set
  400 + // to the file size(s) of the current upload and a loaded data
  401 + // property calculated accordingly:
  402 + this._trigger(
  403 + 'progress',
  404 + $.Event('progress', {delegatedEvent: e}),
  405 + data
  406 + );
  407 + // Trigger a global progress event for all current file uploads,
  408 + // including ajax calls queued for sequential file uploads:
  409 + this._trigger(
  410 + 'progressall',
  411 + $.Event('progressall', {delegatedEvent: e}),
  412 + this._progress
  413 + );
  414 + }
  415 + },
  416 +
  417 + _initProgressListener: function (options) {
  418 + var that = this,
  419 + xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
  420 + // Accesss to the native XHR object is required to add event listeners
  421 + // for the upload progress event:
  422 + if (xhr.upload) {
  423 + $(xhr.upload).bind('progress', function (e) {
  424 + var oe = e.originalEvent;
  425 + // Make sure the progress event properties get copied over:
  426 + e.lengthComputable = oe.lengthComputable;
  427 + e.loaded = oe.loaded;
  428 + e.total = oe.total;
  429 + that._onProgress(e, options);
  430 + });
  431 + options.xhr = function () {
  432 + return xhr;
  433 + };
  434 + }
  435 + },
  436 +
  437 + _isInstanceOf: function (type, obj) {
  438 + // Cross-frame instanceof check
  439 + return Object.prototype.toString.call(obj) === '[object ' + type + ']';
  440 + },
  441 +
  442 + _initXHRData: function (options) {
  443 + var that = this,
  444 + formData,
  445 + file = options.files[0],
  446 + // Ignore non-multipart setting if not supported:
  447 + multipart = options.multipart || !$.support.xhrFileUpload,
  448 + paramName = $.type(options.paramName) === 'array' ?
  449 + options.paramName[0] : options.paramName;
  450 + options.headers = $.extend({}, options.headers);
  451 + if (options.contentRange) {
  452 + options.headers['Content-Range'] = options.contentRange;
  453 + }
  454 + if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
  455 + options.headers['Content-Disposition'] = 'attachment; filename="' +
  456 + encodeURI(file.name) + '"';
  457 + }
  458 + if (!multipart) {
  459 + options.contentType = file.type || 'application/octet-stream';
  460 + options.data = options.blob || file;
  461 + } else if ($.support.xhrFormDataFileUpload) {
  462 + if (options.postMessage) {
  463 + // window.postMessage does not allow sending FormData
  464 + // objects, so we just add the File/Blob objects to
  465 + // the formData array and let the postMessage window
  466 + // create the FormData object out of this array:
  467 + formData = this._getFormData(options);
  468 + if (options.blob) {
  469 + formData.push({
  470 + name: paramName,
  471 + value: options.blob
  472 + });
  473 + } else {
  474 + $.each(options.files, function (index, file) {
  475 + formData.push({
  476 + name: ($.type(options.paramName) === 'array' &&
  477 + options.paramName[index]) || paramName,
  478 + value: file
  479 + });
  480 + });
  481 + }
  482 + } else {
  483 + if (that._isInstanceOf('FormData', options.formData)) {
  484 + formData = options.formData;
  485 + } else {
  486 + formData = new FormData();
  487 + $.each(this._getFormData(options), function (index, field) {
  488 + formData.append(field.name, field.value);
  489 + });
  490 + }
  491 + if (options.blob) {
  492 + formData.append(paramName, options.blob, file.name);
  493 + } else {
  494 + $.each(options.files, function (index, file) {
  495 + // This check allows the tests to run with
  496 + // dummy objects:
  497 + if (that._isInstanceOf('File', file) ||
  498 + that._isInstanceOf('Blob', file)) {
  499 + formData.append(
  500 + ($.type(options.paramName) === 'array' &&
  501 + options.paramName[index]) || paramName,
  502 + file,
  503 + file.uploadName || file.name
  504 + );
  505 + }
  506 + });
  507 + }
  508 + }
  509 + options.data = formData;
  510 + }
  511 + // Blob reference is not needed anymore, free memory:
  512 + options.blob = null;
  513 + },
  514 +
  515 + _initIframeSettings: function (options) {
  516 + var targetHost = $('<a></a>').prop('href', options.url).prop('host');
  517 + // Setting the dataType to iframe enables the iframe transport:
  518 + options.dataType = 'iframe ' + (options.dataType || '');
  519 + // The iframe transport accepts a serialized array as form data:
  520 + options.formData = this._getFormData(options);
  521 + // Add redirect url to form data on cross-domain uploads:
  522 + if (options.redirect && targetHost && targetHost !== location.host) {
  523 + options.formData.push({
  524 + name: options.redirectParamName || 'redirect',
  525 + value: options.redirect
  526 + });
  527 + }
  528 + },
  529 +
  530 + _initDataSettings: function (options) {
  531 + if (this._isXHRUpload(options)) {
  532 + if (!this._chunkedUpload(options, true)) {
  533 + if (!options.data) {
  534 + this._initXHRData(options);
  535 + }
  536 + this._initProgressListener(options);
  537 + }
  538 + if (options.postMessage) {
  539 + // Setting the dataType to postmessage enables the
  540 + // postMessage transport:
  541 + options.dataType = 'postmessage ' + (options.dataType || '');
  542 + }
  543 + } else {
  544 + this._initIframeSettings(options);
  545 + }
  546 + },
  547 +
  548 + _getParamName: function (options) {
  549 + var fileInput = $(options.fileInput),
  550 + paramName = options.paramName;
  551 + if (!paramName) {
  552 + paramName = [];
  553 + fileInput.each(function () {
  554 + var input = $(this),
  555 + name = input.prop('name') || 'files[]',
  556 + i = (input.prop('files') || [1]).length;
  557 + while (i) {
  558 + paramName.push(name);
  559 + i -= 1;
  560 + }
  561 + });
  562 + if (!paramName.length) {
  563 + paramName = [fileInput.prop('name') || 'files[]'];
  564 + }
  565 + } else if (!$.isArray(paramName)) {
  566 + paramName = [paramName];
  567 + }
  568 + return paramName;
  569 + },
  570 +
  571 + _initFormSettings: function (options) {
  572 + // Retrieve missing options from the input field and the
  573 + // associated form, if available:
  574 + if (!options.form || !options.form.length) {
  575 + options.form = $(options.fileInput.prop('form'));
  576 + // If the given file input doesn't have an associated form,
  577 + // use the default widget file input's form:
  578 + if (!options.form.length) {
  579 + options.form = $(this.options.fileInput.prop('form'));
  580 + }
  581 + }
  582 + options.paramName = this._getParamName(options);
  583 + if (!options.url) {
  584 + options.url = options.form.prop('action') || location.href;
  585 + }
  586 + // The HTTP request method must be "POST" or "PUT":
  587 + options.type = (options.type ||
  588 + ($.type(options.form.prop('method')) === 'string' &&
  589 + options.form.prop('method')) || ''
  590 + ).toUpperCase();
  591 + if (options.type !== 'POST' && options.type !== 'PUT' &&
  592 + options.type !== 'PATCH') {
  593 + options.type = 'POST';
  594 + }
  595 + if (!options.formAcceptCharset) {
  596 + options.formAcceptCharset = options.form.attr('accept-charset');
  597 + }
  598 + },
  599 +
  600 + _getAJAXSettings: function (data) {
  601 + var options = $.extend({}, this.options, data);
  602 + this._initFormSettings(options);
  603 + this._initDataSettings(options);
  604 + return options;
  605 + },
  606 +
  607 + // jQuery 1.6 doesn't provide .state(),
  608 + // while jQuery 1.8+ removed .isRejected() and .isResolved():
  609 + _getDeferredState: function (deferred) {
  610 + if (deferred.state) {
  611 + return deferred.state();
  612 + }
  613 + if (deferred.isResolved()) {
  614 + return 'resolved';
  615 + }
  616 + if (deferred.isRejected()) {
  617 + return 'rejected';
  618 + }
  619 + return 'pending';
  620 + },
  621 +
  622 + // Maps jqXHR callbacks to the equivalent
  623 + // methods of the given Promise object:
  624 + _enhancePromise: function (promise) {
  625 + promise.success = promise.done;
  626 + promise.error = promise.fail;
  627 + promise.complete = promise.always;
  628 + return promise;
  629 + },
  630 +
  631 + // Creates and returns a Promise object enhanced with
  632 + // the jqXHR methods abort, success, error and complete:
  633 + _getXHRPromise: function (resolveOrReject, context, args) {
  634 + var dfd = $.Deferred(),
  635 + promise = dfd.promise();
  636 + context = context || this.options.context || promise;
  637 + if (resolveOrReject === true) {
  638 + dfd.resolveWith(context, args);
  639 + } else if (resolveOrReject === false) {
  640 + dfd.rejectWith(context, args);
  641 + }
  642 + promise.abort = dfd.promise;
  643 + return this._enhancePromise(promise);
  644 + },
  645 +
  646 + // Adds convenience methods to the data callback argument:
  647 + _addConvenienceMethods: function (e, data) {
  648 + var that = this,
  649 + getPromise = function (args) {
  650 + return $.Deferred().resolveWith(that, args).promise();
  651 + };
  652 + data.process = function (resolveFunc, rejectFunc) {
  653 + if (resolveFunc || rejectFunc) {
  654 + data._processQueue = this._processQueue =
  655 + (this._processQueue || getPromise([this])).pipe(
  656 + function () {
  657 + if (data.errorThrown) {
  658 + return $.Deferred()
  659 + .rejectWith(that, [data]).promise();
  660 + }
  661 + return getPromise(arguments);
  662 + }
  663 + ).pipe(resolveFunc, rejectFunc);
  664 + }
  665 + return this._processQueue || getPromise([this]);
  666 + };
  667 + data.submit = function () {
  668 + if (this.state() !== 'pending') {
  669 + data.jqXHR = this.jqXHR =
  670 + (that._trigger(
  671 + 'submit',
  672 + $.Event('submit', {delegatedEvent: e}),
  673 + this
  674 + ) !== false) && that._onSend(e, this);
  675 + }
  676 + return this.jqXHR || that._getXHRPromise();
  677 + };
  678 + data.abort = function () {
  679 + if (this.jqXHR) {
  680 + return this.jqXHR.abort();
  681 + }
  682 + this.errorThrown = 'abort';
  683 + that._trigger('fail', null, this);
  684 + return that._getXHRPromise(false);
  685 + };
  686 + data.state = function () {
  687 + if (this.jqXHR) {
  688 + return that._getDeferredState(this.jqXHR);
  689 + }
  690 + if (this._processQueue) {
  691 + return that._getDeferredState(this._processQueue);
  692 + }
  693 + };
  694 + data.processing = function () {
  695 + return !this.jqXHR && this._processQueue && that
  696 + ._getDeferredState(this._processQueue) === 'pending';
  697 + };
  698 + data.progress = function () {
  699 + return this._progress;
  700 + };
  701 + data.response = function () {
  702 + return this._response;
  703 + };
  704 + },
  705 +
  706 + // Parses the Range header from the server response
  707 + // and returns the uploaded bytes:
  708 + _getUploadedBytes: function (jqXHR) {
  709 + var range = jqXHR.getResponseHeader('Range'),
  710 + parts = range && range.split('-'),
  711 + upperBytesPos = parts && parts.length > 1 &&
  712 + parseInt(parts[1], 10);
  713 + return upperBytesPos && upperBytesPos + 1;
  714 + },
  715 +
  716 + // Uploads a file in multiple, sequential requests
  717 + // by splitting the file up in multiple blob chunks.
  718 + // If the second parameter is true, only tests if the file
  719 + // should be uploaded in chunks, but does not invoke any
  720 + // upload requests:
  721 + _chunkedUpload: function (options, testOnly) {
  722 + options.uploadedBytes = options.uploadedBytes || 0;
  723 + var that = this,
  724 + file = options.files[0],
  725 + fs = file.size,
  726 + ub = options.uploadedBytes,
  727 + mcs = options.maxChunkSize || fs,
  728 + slice = this._blobSlice,
  729 + dfd = $.Deferred(),
  730 + promise = dfd.promise(),
  731 + jqXHR,
  732 + upload;
  733 + if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
  734 + options.data) {
  735 + return false;
  736 + }
  737 + if (testOnly) {
  738 + return true;
  739 + }
  740 + if (ub >= fs) {
  741 + file.error = options.i18n('uploadedBytes');
  742 + return this._getXHRPromise(
  743 + false,
  744 + options.context,
  745 + [null, 'error', file.error]
  746 + );
  747 + }
  748 + // The chunk upload method:
  749 + upload = function () {
  750 + // Clone the options object for each chunk upload:
  751 + var o = $.extend({}, options),
  752 + currentLoaded = o._progress.loaded;
  753 + o.blob = slice.call(
  754 + file,
  755 + ub,
  756 + ub + mcs,
  757 + file.type
  758 + );
  759 + // Store the current chunk size, as the blob itself
  760 + // will be dereferenced after data processing:
  761 + o.chunkSize = o.blob.size;
  762 + // Expose the chunk bytes position range:
  763 + o.contentRange = 'bytes ' + ub + '-' +
  764 + (ub + o.chunkSize - 1) + '/' + fs;
  765 + // Process the upload data (the blob and potential form data):
  766 + that._initXHRData(o);
  767 + // Add progress listeners for this chunk upload:
  768 + that._initProgressListener(o);
  769 + jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
  770 + that._getXHRPromise(false, o.context))
  771 + .done(function (result, textStatus, jqXHR) {
  772 + ub = that._getUploadedBytes(jqXHR) ||
  773 + (ub + o.chunkSize);
  774 + // Create a progress event if no final progress event
  775 + // with loaded equaling total has been triggered
  776 + // for this chunk:
  777 + if (currentLoaded + o.chunkSize - o._progress.loaded) {
  778 + that._onProgress($.Event('progress', {
  779 + lengthComputable: true,
  780 + loaded: ub - o.uploadedBytes,
  781 + total: ub - o.uploadedBytes
  782 + }), o);
  783 + }
  784 + options.uploadedBytes = o.uploadedBytes = ub;
  785 + o.result = result;
  786 + o.textStatus = textStatus;
  787 + o.jqXHR = jqXHR;
  788 + that._trigger('chunkdone', null, o);
  789 + that._trigger('chunkalways', null, o);
  790 + if (ub < fs) {
  791 + // File upload not yet complete,
  792 + // continue with the next chunk:
  793 + upload();
  794 + } else {
  795 + dfd.resolveWith(
  796 + o.context,
  797 + [result, textStatus, jqXHR]
  798 + );
  799 + }
  800 + })
  801 + .fail(function (jqXHR, textStatus, errorThrown) {
  802 + o.jqXHR = jqXHR;
  803 + o.textStatus = textStatus;
  804 + o.errorThrown = errorThrown;
  805 + that._trigger('chunkfail', null, o);
  806 + that._trigger('chunkalways', null, o);
  807 + dfd.rejectWith(
  808 + o.context,
  809 + [jqXHR, textStatus, errorThrown]
  810 + );
  811 + });
  812 + };
  813 + this._enhancePromise(promise);
  814 + promise.abort = function () {
  815 + return jqXHR.abort();
  816 + };
  817 + upload();
  818 + return promise;
  819 + },
  820 +
  821 + _beforeSend: function (e, data) {
  822 + if (this._active === 0) {
  823 + // the start callback is triggered when an upload starts
  824 + // and no other uploads are currently running,
  825 + // equivalent to the global ajaxStart event:
  826 + this._trigger('start');
  827 + // Set timer for global bitrate progress calculation:
  828 + this._bitrateTimer = new this._BitrateTimer();
  829 + // Reset the global progress values:
  830 + this._progress.loaded = this._progress.total = 0;
  831 + this._progress.bitrate = 0;
  832 + }
  833 + // Make sure the container objects for the .response() and
  834 + // .progress() methods on the data object are available
  835 + // and reset to their initial state:
  836 + this._initResponseObject(data);
  837 + this._initProgressObject(data);
  838 + data._progress.loaded = data.loaded = data.uploadedBytes || 0;
  839 + data._progress.total = data.total = this._getTotal(data.files) || 1;
  840 + data._progress.bitrate = data.bitrate = 0;
  841 + this._active += 1;
  842 + // Initialize the global progress values:
  843 + this._progress.loaded += data.loaded;
  844 + this._progress.total += data.total;
  845 + },
  846 +
  847 + _onDone: function (result, textStatus, jqXHR, options) {
  848 + var total = options._progress.total,
  849 + response = options._response;
  850 + if (options._progress.loaded < total) {
  851 + // Create a progress event if no final progress event
  852 + // with loaded equaling total has been triggered:
  853 + this._onProgress($.Event('progress', {
  854 + lengthComputable: true,
  855 + loaded: total,
  856 + total: total
  857 + }), options);
  858 + }
  859 + response.result = options.result = result;
  860 + response.textStatus = options.textStatus = textStatus;
  861 + response.jqXHR = options.jqXHR = jqXHR;
  862 + this._trigger('done', null, options);
  863 + },
  864 +
  865 + _onFail: function (jqXHR, textStatus, errorThrown, options) {
  866 + var response = options._response;
  867 + if (options.recalculateProgress) {
  868 + // Remove the failed (error or abort) file upload from
  869 + // the global progress calculation:
  870 + this._progress.loaded -= options._progress.loaded;
  871 + this._progress.total -= options._progress.total;
  872 + }
  873 + response.jqXHR = options.jqXHR = jqXHR;
  874 + response.textStatus = options.textStatus = textStatus;
  875 + response.errorThrown = options.errorThrown = errorThrown;
  876 + this._trigger('fail', null, options);
  877 + },
  878 +
  879 + _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
  880 + // jqXHRorResult, textStatus and jqXHRorError are added to the
  881 + // options object via done and fail callbacks
  882 + this._trigger('always', null, options);
  883 + },
  884 +
  885 + _onSend: function (e, data) {
  886 + if (!data.submit) {
  887 + this._addConvenienceMethods(e, data);
  888 + }
  889 + var that = this,
  890 + jqXHR,
  891 + aborted,
  892 + slot,
  893 + pipe,
  894 + options = that._getAJAXSettings(data),
  895 + send = function () {
  896 + that._sending += 1;
  897 + // Set timer for bitrate progress calculation:
  898 + options._bitrateTimer = new that._BitrateTimer();
  899 + jqXHR = jqXHR || (
  900 + ((aborted || that._trigger(
  901 + 'send',
  902 + $.Event('send', {delegatedEvent: e}),
  903 + options
  904 + ) === false) &&
  905 + that._getXHRPromise(false, options.context, aborted)) ||
  906 + that._chunkedUpload(options) || $.ajax(options)
  907 + ).done(function (result, textStatus, jqXHR) {
  908 + that._onDone(result, textStatus, jqXHR, options);
  909 + }).fail(function (jqXHR, textStatus, errorThrown) {
  910 + that._onFail(jqXHR, textStatus, errorThrown, options);
  911 + }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
  912 + that._onAlways(
  913 + jqXHRorResult,
  914 + textStatus,
  915 + jqXHRorError,
  916 + options
  917 + );
  918 + that._sending -= 1;
  919 + that._active -= 1;
  920 + if (options.limitConcurrentUploads &&
  921 + options.limitConcurrentUploads > that._sending) {
  922 + // Start the next queued upload,
  923 + // that has not been aborted:
  924 + var nextSlot = that._slots.shift();
  925 + while (nextSlot) {
  926 + if (that._getDeferredState(nextSlot) === 'pending') {
  927 + nextSlot.resolve();
  928 + break;
  929 + }
  930 + nextSlot = that._slots.shift();
  931 + }
  932 + }
  933 + if (that._active === 0) {
  934 + // The stop callback is triggered when all uploads have
  935 + // been completed, equivalent to the global ajaxStop event:
  936 + that._trigger('stop');
  937 + }
  938 + });
  939 + return jqXHR;
  940 + };
  941 + this._beforeSend(e, options);
  942 + if (this.options.sequentialUploads ||
  943 + (this.options.limitConcurrentUploads &&
  944 + this.options.limitConcurrentUploads <= this._sending)) {
  945 + if (this.options.limitConcurrentUploads > 1) {
  946 + slot = $.Deferred();
  947 + this._slots.push(slot);
  948 + pipe = slot.pipe(send);
  949 + } else {
  950 + this._sequence = this._sequence.pipe(send, send);
  951 + pipe = this._sequence;
  952 + }
  953 + // Return the piped Promise object, enhanced with an abort method,
  954 + // which is delegated to the jqXHR object of the current upload,
  955 + // and jqXHR callbacks mapped to the equivalent Promise methods:
  956 + pipe.abort = function () {
  957 + aborted = [undefined, 'abort', 'abort'];
  958 + if (!jqXHR) {
  959 + if (slot) {
  960 + slot.rejectWith(options.context, aborted);
  961 + }
  962 + return send();
  963 + }
  964 + return jqXHR.abort();
  965 + };
  966 + return this._enhancePromise(pipe);
  967 + }
  968 + return send();
  969 + },
  970 +
  971 + _onAdd: function (e, data) {
  972 + var that = this,
  973 + result = true,
  974 + options = $.extend({}, this.options, data),
  975 + files = data.files,
  976 + filesLength = files.length,
  977 + limit = options.limitMultiFileUploads,
  978 + limitSize = options.limitMultiFileUploadSize,
  979 + overhead = options.limitMultiFileUploadSizeOverhead,
  980 + batchSize = 0,
  981 + paramName = this._getParamName(options),
  982 + paramNameSet,
  983 + paramNameSlice,
  984 + fileSet,
  985 + i,
  986 + j = 0;
  987 + if (!filesLength) {
  988 + return false;
  989 + }
  990 + if (limitSize && files[0].size === undefined) {
  991 + limitSize = undefined;
  992 + }
  993 + if (!(options.singleFileUploads || limit || limitSize) ||
  994 + !this._isXHRUpload(options)) {
  995 + fileSet = [files];
  996 + paramNameSet = [paramName];
  997 + } else if (!(options.singleFileUploads || limitSize) && limit) {
  998 + fileSet = [];
  999 + paramNameSet = [];
  1000 + for (i = 0; i < filesLength; i += limit) {
  1001 + fileSet.push(files.slice(i, i + limit));
  1002 + paramNameSlice = paramName.slice(i, i + limit);
  1003 + if (!paramNameSlice.length) {
  1004 + paramNameSlice = paramName;
  1005 + }
  1006 + paramNameSet.push(paramNameSlice);
  1007 + }
  1008 + } else if (!options.singleFileUploads && limitSize) {
  1009 + fileSet = [];
  1010 + paramNameSet = [];
  1011 + for (i = 0; i < filesLength; i = i + 1) {
  1012 + batchSize += files[i].size + overhead;
  1013 + if (i + 1 === filesLength ||
  1014 + ((batchSize + files[i + 1].size + overhead) > limitSize) ||
  1015 + (limit && i + 1 - j >= limit)) {
  1016 + fileSet.push(files.slice(j, i + 1));
  1017 + paramNameSlice = paramName.slice(j, i + 1);
  1018 + if (!paramNameSlice.length) {
  1019 + paramNameSlice = paramName;
  1020 + }
  1021 + paramNameSet.push(paramNameSlice);
  1022 + j = i + 1;
  1023 + batchSize = 0;
  1024 + }
  1025 + }
  1026 + } else {
  1027 + paramNameSet = paramName;
  1028 + }
  1029 + data.originalFiles = files;
  1030 + $.each(fileSet || files, function (index, element) {
  1031 + var newData = $.extend({}, data);
  1032 + newData.files = fileSet ? element : [element];
  1033 + newData.paramName = paramNameSet[index];
  1034 + that._initResponseObject(newData);
  1035 + that._initProgressObject(newData);
  1036 + that._addConvenienceMethods(e, newData);
  1037 + result = that._trigger(
  1038 + 'add',
  1039 + $.Event('add', {delegatedEvent: e}),
  1040 + newData
  1041 + );
  1042 + return result;
  1043 + });
  1044 + return result;
  1045 + },
  1046 +
  1047 + _replaceFileInput: function (data) {
  1048 + var input = data.fileInput,
  1049 + inputClone = input.clone(true),
  1050 + restoreFocus = input.is(document.activeElement);
  1051 + // Add a reference for the new cloned file input to the data argument:
  1052 + data.fileInputClone = inputClone;
  1053 + $('<form></form>').append(inputClone)[0].reset();
  1054 + // Detaching allows to insert the fileInput on another form
  1055 + // without loosing the file input value:
  1056 + input.after(inputClone).detach();
  1057 + // If the fileInput had focus before it was detached,
  1058 + // restore focus to the inputClone.
  1059 + if (restoreFocus) {
  1060 + inputClone.focus();
  1061 + }
  1062 + // Avoid memory leaks with the detached file input:
  1063 + $.cleanData(input.unbind('remove'));
  1064 + // Replace the original file input element in the fileInput
  1065 + // elements set with the clone, which has been copied including
  1066 + // event handlers:
  1067 + this.options.fileInput = this.options.fileInput.map(function (i, el) {
  1068 + if (el === input[0]) {
  1069 + return inputClone[0];
  1070 + }
  1071 + return el;
  1072 + });
  1073 + // If the widget has been initialized on the file input itself,
  1074 + // override this.element with the file input clone:
  1075 + if (input[0] === this.element[0]) {
  1076 + this.element = inputClone;
  1077 + }
  1078 + },
  1079 +
  1080 + _handleFileTreeEntry: function (entry, path) {
  1081 + var that = this,
  1082 + dfd = $.Deferred(),
  1083 + errorHandler = function (e) {
  1084 + if (e && !e.entry) {
  1085 + e.entry = entry;
  1086 + }
  1087 + // Since $.when returns immediately if one
  1088 + // Deferred is rejected, we use resolve instead.
  1089 + // This allows valid files and invalid items
  1090 + // to be returned together in one set:
  1091 + dfd.resolve([e]);
  1092 + },
  1093 + successHandler = function (entries) {
  1094 + that._handleFileTreeEntries(
  1095 + entries,
  1096 + path + entry.name + '/'
  1097 + ).done(function (files) {
  1098 + dfd.resolve(files);
  1099 + }).fail(errorHandler);
  1100 + },
  1101 + readEntries = function () {
  1102 + dirReader.readEntries(function (results) {
  1103 + if (!results.length) {
  1104 + successHandler(entries);
  1105 + } else {
  1106 + entries = entries.concat(results);
  1107 + readEntries();
  1108 + }
  1109 + }, errorHandler);
  1110 + },
  1111 + dirReader, entries = [];
  1112 + path = path || '';
  1113 + if (entry.isFile) {
  1114 + if (entry._file) {
  1115 + // Workaround for Chrome bug #149735
  1116 + entry._file.relativePath = path;
  1117 + dfd.resolve(entry._file);
  1118 + } else {
  1119 + entry.file(function (file) {
  1120 + file.relativePath = path;
  1121 + dfd.resolve(file);
  1122 + }, errorHandler);
  1123 + }
  1124 + } else if (entry.isDirectory) {
  1125 + dirReader = entry.createReader();
  1126 + readEntries();
  1127 + } else {
  1128 + // Return an empy list for file system items
  1129 + // other than files or directories:
  1130 + dfd.resolve([]);
  1131 + }
  1132 + return dfd.promise();
  1133 + },
  1134 +
  1135 + _handleFileTreeEntries: function (entries, path) {
  1136 + var that = this;
  1137 + return $.when.apply(
  1138 + $,
  1139 + $.map(entries, function (entry) {
  1140 + return that._handleFileTreeEntry(entry, path);
  1141 + })
  1142 + ).pipe(function () {
  1143 + return Array.prototype.concat.apply(
  1144 + [],
  1145 + arguments
  1146 + );
  1147 + });
  1148 + },
  1149 +
  1150 + _getDroppedFiles: function (dataTransfer) {
  1151 + dataTransfer = dataTransfer || {};
  1152 + var items = dataTransfer.items;
  1153 + if (items && items.length && (items[0].webkitGetAsEntry ||
  1154 + items[0].getAsEntry)) {
  1155 + return this._handleFileTreeEntries(
  1156 + $.map(items, function (item) {
  1157 + var entry;
  1158 + if (item.webkitGetAsEntry) {
  1159 + entry = item.webkitGetAsEntry();
  1160 + if (entry) {
  1161 + // Workaround for Chrome bug #149735:
  1162 + entry._file = item.getAsFile();
  1163 + }
  1164 + return entry;
  1165 + }
  1166 + return item.getAsEntry();
  1167 + })
  1168 + );
  1169 + }
  1170 + return $.Deferred().resolve(
  1171 + $.makeArray(dataTransfer.files)
  1172 + ).promise();
  1173 + },
  1174 +
  1175 + _getSingleFileInputFiles: function (fileInput) {
  1176 + fileInput = $(fileInput);
  1177 + var entries = fileInput.prop('webkitEntries') ||
  1178 + fileInput.prop('entries'),
  1179 + files,
  1180 + value;
  1181 + if (entries && entries.length) {
  1182 + return this._handleFileTreeEntries(entries);
  1183 + }
  1184 + files = $.makeArray(fileInput.prop('files'));
  1185 + if (!files.length) {
  1186 + value = fileInput.prop('value');
  1187 + if (!value) {
  1188 + return $.Deferred().resolve([]).promise();
  1189 + }
  1190 + // If the files property is not available, the browser does not
  1191 + // support the File API and we add a pseudo File object with
  1192 + // the input value as name with path information removed:
  1193 + files = [{name: value.replace(/^.*\\/, '')}];
  1194 + } else if (files[0].name === undefined && files[0].fileName) {
  1195 + // File normalization for Safari 4 and Firefox 3:
  1196 + $.each(files, function (index, file) {
  1197 + file.name = file.fileName;
  1198 + file.size = file.fileSize;
  1199 + });
  1200 + }
  1201 + return $.Deferred().resolve(files).promise();
  1202 + },
  1203 +
  1204 + _getFileInputFiles: function (fileInput) {
  1205 + if (!(fileInput instanceof $) || fileInput.length === 1) {
  1206 + return this._getSingleFileInputFiles(fileInput);
  1207 + }
  1208 + return $.when.apply(
  1209 + $,
  1210 + $.map(fileInput, this._getSingleFileInputFiles)
  1211 + ).pipe(function () {
  1212 + return Array.prototype.concat.apply(
  1213 + [],
  1214 + arguments
  1215 + );
  1216 + });
  1217 + },
  1218 +
  1219 + _onChange: function (e) {
  1220 + var that = this,
  1221 + data = {
  1222 + fileInput: $(e.target),
  1223 + form: $(e.target.form)
  1224 + };
  1225 + this._getFileInputFiles(data.fileInput).always(function (files) {
  1226 + data.files = files;
  1227 + if (that.options.replaceFileInput) {
  1228 + that._replaceFileInput(data);
  1229 + }
  1230 + if (that._trigger(
  1231 + 'change',
  1232 + $.Event('change', {delegatedEvent: e}),
  1233 + data
  1234 + ) !== false) {
  1235 + that._onAdd(e, data);
  1236 + }
  1237 + });
  1238 + },
  1239 +
  1240 + _onPaste: function (e) {
  1241 + var items = e.originalEvent && e.originalEvent.clipboardData &&
  1242 + e.originalEvent.clipboardData.items,
  1243 + data = {files: []};
  1244 + if (items && items.length) {
  1245 + $.each(items, function (index, item) {
  1246 + var file = item.getAsFile && item.getAsFile();
  1247 + if (file) {
  1248 + data.files.push(file);
  1249 + }
  1250 + });
  1251 + if (this._trigger(
  1252 + 'paste',
  1253 + $.Event('paste', {delegatedEvent: e}),
  1254 + data
  1255 + ) !== false) {
  1256 + this._onAdd(e, data);
  1257 + }
  1258 + }
  1259 + },
  1260 +
  1261 + _onDrop: function (e) {
  1262 + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
  1263 + var that = this,
  1264 + dataTransfer = e.dataTransfer,
  1265 + data = {};
  1266 + if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
  1267 + e.preventDefault();
  1268 + this._getDroppedFiles(dataTransfer).always(function (files) {
  1269 + data.files = files;
  1270 + if (that._trigger(
  1271 + 'drop',
  1272 + $.Event('drop', {delegatedEvent: e}),
  1273 + data
  1274 + ) !== false) {
  1275 + that._onAdd(e, data);
  1276 + }
  1277 + });
  1278 + }
  1279 + },
  1280 +
  1281 + _onDragOver: getDragHandler('dragover'),
  1282 +
  1283 + _onDragEnter: getDragHandler('dragenter'),
  1284 +
  1285 + _onDragLeave: getDragHandler('dragleave'),
  1286 +
  1287 + _initEventHandlers: function () {
  1288 + if (this._isXHRUpload(this.options)) {
  1289 + this._on(this.options.dropZone, {
  1290 + dragover: this._onDragOver,
  1291 + drop: this._onDrop,
  1292 + // event.preventDefault() on dragenter is required for IE10+:
  1293 + dragenter: this._onDragEnter,
  1294 + // dragleave is not required, but added for completeness:
  1295 + dragleave: this._onDragLeave
  1296 + });
  1297 + this._on(this.options.pasteZone, {
  1298 + paste: this._onPaste
  1299 + });
  1300 + }
  1301 + if ($.support.fileInput) {
  1302 + this._on(this.options.fileInput, {
  1303 + change: this._onChange
  1304 + });
  1305 + }
  1306 + },
  1307 +
  1308 + _destroyEventHandlers: function () {
  1309 + this._off(this.options.dropZone, 'dragenter dragleave dragover drop');
  1310 + this._off(this.options.pasteZone, 'paste');
  1311 + this._off(this.options.fileInput, 'change');
  1312 + },
  1313 +
  1314 + _setOption: function (key, value) {
  1315 + var reinit = $.inArray(key, this._specialOptions) !== -1;
  1316 + if (reinit) {
  1317 + this._destroyEventHandlers();
  1318 + }
  1319 + this._super(key, value);
  1320 + if (reinit) {
  1321 + this._initSpecialOptions();
  1322 + this._initEventHandlers();
  1323 + }
  1324 + },
  1325 +
  1326 + _initSpecialOptions: function () {
  1327 + var options = this.options;
  1328 + if (options.fileInput === undefined) {
  1329 + options.fileInput = this.element.is('input[type="file"]') ?
  1330 + this.element : this.element.find('input[type="file"]');
  1331 + } else if (!(options.fileInput instanceof $)) {
  1332 + options.fileInput = $(options.fileInput);
  1333 + }
  1334 + if (!(options.dropZone instanceof $)) {
  1335 + options.dropZone = $(options.dropZone);
  1336 + }
  1337 + if (!(options.pasteZone instanceof $)) {
  1338 + options.pasteZone = $(options.pasteZone);
  1339 + }
  1340 + },
  1341 +
  1342 + _getRegExp: function (str) {
  1343 + var parts = str.split('/'),
  1344 + modifiers = parts.pop();
  1345 + parts.shift();
  1346 + return new RegExp(parts.join('/'), modifiers);
  1347 + },
  1348 +
  1349 + _isRegExpOption: function (key, value) {
  1350 + return key !== 'url' && $.type(value) === 'string' &&
  1351 + /^\/.*\/[igm]{0,3}$/.test(value);
  1352 + },
  1353 +
  1354 + _initDataAttributes: function () {
  1355 + var that = this,
  1356 + options = this.options,
  1357 + data = this.element.data();
  1358 + // Initialize options set via HTML5 data-attributes:
  1359 + $.each(
  1360 + this.element[0].attributes,
  1361 + function (index, attr) {
  1362 + var key = attr.name.toLowerCase(),
  1363 + value;
  1364 + if (/^data-/.test(key)) {
  1365 + // Convert hyphen-ated key to camelCase:
  1366 + key = key.slice(5).replace(/-[a-z]/g, function (str) {
  1367 + return str.charAt(1).toUpperCase();
  1368 + });
  1369 + value = data[key];
  1370 + if (that._isRegExpOption(key, value)) {
  1371 + value = that._getRegExp(value);
  1372 + }
  1373 + options[key] = value;
  1374 + }
  1375 + }
  1376 + );
  1377 + },
  1378 +
  1379 + _create: function () {
  1380 + this._initDataAttributes();
  1381 + this._initSpecialOptions();
  1382 + this._slots = [];
  1383 + this._sequence = this._getXHRPromise(true);
  1384 + this._sending = this._active = 0;
  1385 + this._initProgressObject(this);
  1386 + this._initEventHandlers();
  1387 + },
  1388 +
  1389 + // This method is exposed to the widget API and allows to query
  1390 + // the number of active uploads:
  1391 + active: function () {
  1392 + return this._active;
  1393 + },
  1394 +
  1395 + // This method is exposed to the widget API and allows to query
  1396 + // the widget upload progress.
  1397 + // It returns an object with loaded, total and bitrate properties
  1398 + // for the running uploads:
  1399 + progress: function () {
  1400 + return this._progress;
  1401 + },
  1402 +
  1403 + // This method is exposed to the widget API and allows adding files
  1404 + // using the fileupload API. The data parameter accepts an object which
  1405 + // must have a files property and can contain additional options:
  1406 + // .fileupload('add', {files: filesList});
  1407 + add: function (data) {
  1408 + var that = this;
  1409 + if (!data || this.options.disabled) {
  1410 + return;
  1411 + }
  1412 + if (data.fileInput && !data.files) {
  1413 + this._getFileInputFiles(data.fileInput).always(function (files) {
  1414 + data.files = files;
  1415 + that._onAdd(null, data);
  1416 + });
  1417 + } else {
  1418 + data.files = $.makeArray(data.files);
  1419 + this._onAdd(null, data);
  1420 + }
  1421 + },
  1422 +
  1423 + // This method is exposed to the widget API and allows sending files
  1424 + // using the fileupload API. The data parameter accepts an object which
  1425 + // must have a files or fileInput property and can contain additional options:
  1426 + // .fileupload('send', {files: filesList});
  1427 + // The method returns a Promise object for the file upload call.
  1428 + send: function (data) {
  1429 + if (data && !this.options.disabled) {
  1430 + if (data.fileInput && !data.files) {
  1431 + var that = this,
  1432 + dfd = $.Deferred(),
  1433 + promise = dfd.promise(),
  1434 + jqXHR,
  1435 + aborted;
  1436 + promise.abort = function () {
  1437 + aborted = true;
  1438 + if (jqXHR) {
  1439 + return jqXHR.abort();
  1440 + }
  1441 + dfd.reject(null, 'abort', 'abort');
  1442 + return promise;
  1443 + };
  1444 + this._getFileInputFiles(data.fileInput).always(
  1445 + function (files) {
  1446 + if (aborted) {
  1447 + return;
  1448 + }
  1449 + if (!files.length) {
  1450 + dfd.reject();
  1451 + return;
  1452 + }
  1453 + data.files = files;
  1454 + jqXHR = that._onSend(null, data);
  1455 + jqXHR.then(
  1456 + function (result, textStatus, jqXHR) {
  1457 + dfd.resolve(result, textStatus, jqXHR);
  1458 + },
  1459 + function (jqXHR, textStatus, errorThrown) {
  1460 + dfd.reject(jqXHR, textStatus, errorThrown);
  1461 + }
  1462 + );
  1463 + }
  1464 + );
  1465 + return this._enhancePromise(promise);
  1466 + }
  1467 + data.files = $.makeArray(data.files);
  1468 + if (data.files.length) {
  1469 + return this._onSend(null, data);
  1470 + }
  1471 + }
  1472 + return this._getXHRPromise(false, data && data.context);
  1473 + }
  1474 +
  1475 + });
  1476 +
  1477 +}));
... ...
common/modules/fileloader/resources/jquery.iframe-transport.js 0 → 100644
  1 +/*
  2 + * jQuery Iframe Transport Plugin
  3 + * https://github.com/blueimp/jQuery-File-Upload
  4 + *
  5 + * Copyright 2011, Sebastian Tschan
  6 + * https://blueimp.net
  7 + *
  8 + * Licensed under the MIT license:
  9 + * http://www.opensource.org/licenses/MIT
  10 + */
  11 +
  12 +/* global define, require, window, document */
  13 +
  14 +(function (factory) {
  15 + 'use strict';
  16 + if (typeof define === 'function' && define.amd) {
  17 + // Register as an anonymous AMD module:
  18 + define(['jquery'], factory);
  19 + } else if (typeof exports === 'object') {
  20 + // Node/CommonJS:
  21 + factory(require('jquery'));
  22 + } else {
  23 + // Browser globals:
  24 + factory(window.jQuery);
  25 + }
  26 +}(function ($) {
  27 + 'use strict';
  28 +
  29 + // Helper variable to create unique names for the transport iframes:
  30 + var counter = 0;
  31 +
  32 + // The iframe transport accepts four additional options:
  33 + // options.fileInput: a jQuery collection of file input fields
  34 + // options.paramName: the parameter name for the file form data,
  35 + // overrides the name property of the file input field(s),
  36 + // can be a string or an array of strings.
  37 + // options.formData: an array of objects with name and value properties,
  38 + // equivalent to the return data of .serializeArray(), e.g.:
  39 + // [{name: 'a', value: 1}, {name: 'b', value: 2}]
  40 + // options.initialIframeSrc: the URL of the initial iframe src,
  41 + // by default set to "javascript:false;"
  42 + $.ajaxTransport('iframe', function (options) {
  43 + if (options.async) {
  44 + // javascript:false as initial iframe src
  45 + // prevents warning popups on HTTPS in IE6:
  46 + /*jshint scripturl: true */
  47 + var initialIframeSrc = options.initialIframeSrc || 'javascript:false;',
  48 + /*jshint scripturl: false */
  49 + form,
  50 + iframe,
  51 + addParamChar;
  52 + return {
  53 + send: function (_, completeCallback) {
  54 + form = $('<form style="display:none;"></form>');
  55 + form.attr('accept-charset', options.formAcceptCharset);
  56 + addParamChar = /\?/.test(options.url) ? '&' : '?';
  57 + // XDomainRequest only supports GET and POST:
  58 + if (options.type === 'DELETE') {
  59 + options.url = options.url + addParamChar + '_method=DELETE';
  60 + options.type = 'POST';
  61 + } else if (options.type === 'PUT') {
  62 + options.url = options.url + addParamChar + '_method=PUT';
  63 + options.type = 'POST';
  64 + } else if (options.type === 'PATCH') {
  65 + options.url = options.url + addParamChar + '_method=PATCH';
  66 + options.type = 'POST';
  67 + }
  68 + // IE versions below IE8 cannot set the name property of
  69 + // elements that have already been added to the DOM,
  70 + // so we set the name along with the iframe HTML markup:
  71 + counter += 1;
  72 + iframe = $(
  73 + '<iframe src="' + initialIframeSrc +
  74 + '" name="iframe-transport-' + counter + '"></iframe>'
  75 + ).bind('load', function () {
  76 + var fileInputClones,
  77 + paramNames = $.isArray(options.paramName) ?
  78 + options.paramName : [options.paramName];
  79 + iframe
  80 + .unbind('load')
  81 + .bind('load', function () {
  82 + var response;
  83 + // Wrap in a try/catch block to catch exceptions thrown
  84 + // when trying to access cross-domain iframe contents:
  85 + try {
  86 + response = iframe.contents();
  87 + // Google Chrome and Firefox do not throw an
  88 + // exception when calling iframe.contents() on
  89 + // cross-domain requests, so we unify the response:
  90 + if (!response.length || !response[0].firstChild) {
  91 + throw new Error();
  92 + }
  93 + } catch (e) {
  94 + response = undefined;
  95 + }
  96 + // The complete callback returns the
  97 + // iframe content document as response object:
  98 + completeCallback(
  99 + 200,
  100 + 'success',
  101 + {'iframe': response}
  102 + );
  103 + // Fix for IE endless progress bar activity bug
  104 + // (happens on form submits to iframe targets):
  105 + $('<iframe src="' + initialIframeSrc + '"></iframe>')
  106 + .appendTo(form);
  107 + window.setTimeout(function () {
  108 + // Removing the form in a setTimeout call
  109 + // allows Chrome's developer tools to display
  110 + // the response result
  111 + form.remove();
  112 + }, 0);
  113 + });
  114 + form
  115 + .prop('target', iframe.prop('name'))
  116 + .prop('action', options.url)
  117 + .prop('method', options.type);
  118 + if (options.formData) {
  119 + $.each(options.formData, function (index, field) {
  120 + $('<input type="hidden"/>')
  121 + .prop('name', field.name)
  122 + .val(field.value)
  123 + .appendTo(form);
  124 + });
  125 + }
  126 + if (options.fileInput && options.fileInput.length &&
  127 + options.type === 'POST') {
  128 + fileInputClones = options.fileInput.clone();
  129 + // Insert a clone for each file input field:
  130 + options.fileInput.after(function (index) {
  131 + return fileInputClones[index];
  132 + });
  133 + if (options.paramName) {
  134 + options.fileInput.each(function (index) {
  135 + $(this).prop(
  136 + 'name',
  137 + paramNames[index] || options.paramName
  138 + );
  139 + });
  140 + }
  141 + // Appending the file input fields to the hidden form
  142 + // removes them from their original location:
  143 + form
  144 + .append(options.fileInput)
  145 + .prop('enctype', 'multipart/form-data')
  146 + // enctype must be set as encoding for IE:
  147 + .prop('encoding', 'multipart/form-data');
  148 + // Remove the HTML5 form attribute from the input(s):
  149 + options.fileInput.removeAttr('form');
  150 + }
  151 + form.submit();
  152 + // Insert the file input fields at their original location
  153 + // by replacing the clones with the originals:
  154 + if (fileInputClones && fileInputClones.length) {
  155 + options.fileInput.each(function (index, input) {
  156 + var clone = $(fileInputClones[index]);
  157 + // Restore the original name and form properties:
  158 + $(input)
  159 + .prop('name', clone.prop('name'))
  160 + .attr('form', clone.attr('form'));
  161 + clone.replaceWith(input);
  162 + });
  163 + }
  164 + });
  165 + form.append(iframe).appendTo(document.body);
  166 + },
  167 + abort: function () {
  168 + if (iframe) {
  169 + // javascript:false as iframe src aborts the request
  170 + // and prevents warning popups on HTTPS in IE6.
  171 + // concat is used to avoid the "Script URL" JSLint error:
  172 + iframe
  173 + .unbind('load')
  174 + .prop('src', initialIframeSrc);
  175 + }
  176 + if (form) {
  177 + form.remove();
  178 + }
  179 + }
  180 + };
  181 + }
  182 + });
  183 +
  184 + // The iframe transport returns the iframe content document as response.
  185 + // The following adds converters from iframe to text, json, html, xml
  186 + // and script.
  187 + // Please note that the Content-Type for JSON responses has to be text/plain
  188 + // or text/html, if the browser doesn't include application/json in the
  189 + // Accept header, else IE will show a download dialog.
  190 + // The Content-Type for XML responses on the other hand has to be always
  191 + // application/xml or text/xml, so IE properly parses the XML response.
  192 + // See also
  193 + // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
  194 + $.ajaxSetup({
  195 + converters: {
  196 + 'iframe text': function (iframe) {
  197 + return iframe && $(iframe[0].body).text();
  198 + },
  199 + 'iframe json': function (iframe) {
  200 + return iframe && $.parseJSON($(iframe[0].body).text());
  201 + },
  202 + 'iframe html': function (iframe) {
  203 + return iframe && $(iframe[0].body).html();
  204 + },
  205 + 'iframe xml': function (iframe) {
  206 + var xmlDoc = iframe && iframe[0];
  207 + return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
  208 + $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
  209 + $(xmlDoc.body).html());
  210 + },
  211 + 'iframe script': function (iframe) {
  212 + return iframe && $.globalEval($(iframe[0].body).text());
  213 + }
  214 + }
  215 + });
  216 +
  217 +}));
... ...
common/modules/fileloader/resources/jquery.ui.widget.js 0 → 100644
  1 +/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28
  2 +* http://jqueryui.com
  3 +* Includes: widget.js
  4 +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
  5 +
  6 +(function( factory ) {
  7 + if ( typeof define === "function" && define.amd ) {
  8 +
  9 + // AMD. Register as an anonymous module.
  10 + define([ "jquery" ], factory );
  11 +
  12 + } else if ( typeof exports === "object" ) {
  13 +
  14 + // Node/CommonJS
  15 + factory( require( "jquery" ) );
  16 +
  17 + } else {
  18 +
  19 + // Browser globals
  20 + factory( jQuery );
  21 + }
  22 +}(function( $ ) {
  23 +/*!
  24 + * jQuery UI Widget 1.11.4
  25 + * http://jqueryui.com
  26 + *
  27 + * Copyright jQuery Foundation and other contributors
  28 + * Released under the MIT license.
  29 + * http://jquery.org/license
  30 + *
  31 + * http://api.jqueryui.com/jQuery.widget/
  32 + */
  33 +
  34 +
  35 +var widget_uuid = 0,
  36 + widget_slice = Array.prototype.slice;
  37 +
  38 +$.cleanData = (function( orig ) {
  39 + return function( elems ) {
  40 + var events, elem, i;
  41 + for ( i = 0; (elem = elems[i]) != null; i++ ) {
  42 + try {
  43 +
  44 + // Only trigger remove when necessary to save time
  45 + events = $._data( elem, "events" );
  46 + if ( events && events.remove ) {
  47 + $( elem ).triggerHandler( "remove" );
  48 + }
  49 +
  50 + // http://bugs.jquery.com/ticket/8235
  51 + } catch ( e ) {}
  52 + }
  53 + orig( elems );
  54 + };
  55 +})( $.cleanData );
  56 +
  57 +$.widget = function( name, base, prototype ) {
  58 + var fullName, existingConstructor, constructor, basePrototype,
  59 + // proxiedPrototype allows the provided prototype to remain unmodified
  60 + // so that it can be used as a mixin for multiple widgets (#8876)
  61 + proxiedPrototype = {},
  62 + namespace = name.split( "." )[ 0 ];
  63 +
  64 + name = name.split( "." )[ 1 ];
  65 + fullName = namespace + "-" + name;
  66 +
  67 + if ( !prototype ) {
  68 + prototype = base;
  69 + base = $.Widget;
  70 + }
  71 +
  72 + // create selector for plugin
  73 + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
  74 + return !!$.data( elem, fullName );
  75 + };
  76 +
  77 + $[ namespace ] = $[ namespace ] || {};
  78 + existingConstructor = $[ namespace ][ name ];
  79 + constructor = $[ namespace ][ name ] = function( options, element ) {
  80 + // allow instantiation without "new" keyword
  81 + if ( !this._createWidget ) {
  82 + return new constructor( options, element );
  83 + }
  84 +
  85 + // allow instantiation without initializing for simple inheritance
  86 + // must use "new" keyword (the code above always passes args)
  87 + if ( arguments.length ) {
  88 + this._createWidget( options, element );
  89 + }
  90 + };
  91 + // extend with the existing constructor to carry over any static properties
  92 + $.extend( constructor, existingConstructor, {
  93 + version: prototype.version,
  94 + // copy the object used to create the prototype in case we need to
  95 + // redefine the widget later
  96 + _proto: $.extend( {}, prototype ),
  97 + // track widgets that inherit from this widget in case this widget is
  98 + // redefined after a widget inherits from it
  99 + _childConstructors: []
  100 + });
  101 +
  102 + basePrototype = new base();
  103 + // we need to make the options hash a property directly on the new instance
  104 + // otherwise we'll modify the options hash on the prototype that we're
  105 + // inheriting from
  106 + basePrototype.options = $.widget.extend( {}, basePrototype.options );
  107 + $.each( prototype, function( prop, value ) {
  108 + if ( !$.isFunction( value ) ) {
  109 + proxiedPrototype[ prop ] = value;
  110 + return;
  111 + }
  112 + proxiedPrototype[ prop ] = (function() {
  113 + var _super = function() {
  114 + return base.prototype[ prop ].apply( this, arguments );
  115 + },
  116 + _superApply = function( args ) {
  117 + return base.prototype[ prop ].apply( this, args );
  118 + };
  119 + return function() {
  120 + var __super = this._super,
  121 + __superApply = this._superApply,
  122 + returnValue;
  123 +
  124 + this._super = _super;
  125 + this._superApply = _superApply;
  126 +
  127 + returnValue = value.apply( this, arguments );
  128 +
  129 + this._super = __super;
  130 + this._superApply = __superApply;
  131 +
  132 + return returnValue;
  133 + };
  134 + })();
  135 + });
  136 + constructor.prototype = $.widget.extend( basePrototype, {
  137 + // TODO: remove support for widgetEventPrefix
  138 + // always use the name + a colon as the prefix, e.g., draggable:start
  139 + // don't prefix for widgets that aren't DOM-based
  140 + widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
  141 + }, proxiedPrototype, {
  142 + constructor: constructor,
  143 + namespace: namespace,
  144 + widgetName: name,
  145 + widgetFullName: fullName
  146 + });
  147 +
  148 + // If this widget is being redefined then we need to find all widgets that
  149 + // are inheriting from it and redefine all of them so that they inherit from
  150 + // the new version of this widget. We're essentially trying to replace one
  151 + // level in the prototype chain.
  152 + if ( existingConstructor ) {
  153 + $.each( existingConstructor._childConstructors, function( i, child ) {
  154 + var childPrototype = child.prototype;
  155 +
  156 + // redefine the child widget using the same prototype that was
  157 + // originally used, but inherit from the new version of the base
  158 + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
  159 + });
  160 + // remove the list of existing child constructors from the old constructor
  161 + // so the old child constructors can be garbage collected
  162 + delete existingConstructor._childConstructors;
  163 + } else {
  164 + base._childConstructors.push( constructor );
  165 + }
  166 +
  167 + $.widget.bridge( name, constructor );
  168 +
  169 + return constructor;
  170 +};
  171 +
  172 +$.widget.extend = function( target ) {
  173 + var input = widget_slice.call( arguments, 1 ),
  174 + inputIndex = 0,
  175 + inputLength = input.length,
  176 + key,
  177 + value;
  178 + for ( ; inputIndex < inputLength; inputIndex++ ) {
  179 + for ( key in input[ inputIndex ] ) {
  180 + value = input[ inputIndex ][ key ];
  181 + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
  182 + // Clone objects
  183 + if ( $.isPlainObject( value ) ) {
  184 + target[ key ] = $.isPlainObject( target[ key ] ) ?
  185 + $.widget.extend( {}, target[ key ], value ) :
  186 + // Don't extend strings, arrays, etc. with objects
  187 + $.widget.extend( {}, value );
  188 + // Copy everything else by reference
  189 + } else {
  190 + target[ key ] = value;
  191 + }
  192 + }
  193 + }
  194 + }
  195 + return target;
  196 +};
  197 +
  198 +$.widget.bridge = function( name, object ) {
  199 + var fullName = object.prototype.widgetFullName || name;
  200 + $.fn[ name ] = function( options ) {
  201 + var isMethodCall = typeof options === "string",
  202 + args = widget_slice.call( arguments, 1 ),
  203 + returnValue = this;
  204 +
  205 + if ( isMethodCall ) {
  206 + this.each(function() {
  207 + var methodValue,
  208 + instance = $.data( this, fullName );
  209 + if ( options === "instance" ) {
  210 + returnValue = instance;
  211 + return false;
  212 + }
  213 + if ( !instance ) {
  214 + return $.error( "cannot call methods on " + name + " prior to initialization; " +
  215 + "attempted to call method '" + options + "'" );
  216 + }
  217 + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
  218 + return $.error( "no such method '" + options + "' for " + name + " widget instance" );
  219 + }
  220 + methodValue = instance[ options ].apply( instance, args );
  221 + if ( methodValue !== instance && methodValue !== undefined ) {
  222 + returnValue = methodValue && methodValue.jquery ?
  223 + returnValue.pushStack( methodValue.get() ) :
  224 + methodValue;
  225 + return false;
  226 + }
  227 + });
  228 + } else {
  229 +
  230 + // Allow multiple hashes to be passed on init
  231 + if ( args.length ) {
  232 + options = $.widget.extend.apply( null, [ options ].concat(args) );
  233 + }
  234 +
  235 + this.each(function() {
  236 + var instance = $.data( this, fullName );
  237 + if ( instance ) {
  238 + instance.option( options || {} );
  239 + if ( instance._init ) {
  240 + instance._init();
  241 + }
  242 + } else {
  243 + $.data( this, fullName, new object( options, this ) );
  244 + }
  245 + });
  246 + }
  247 +
  248 + return returnValue;
  249 + };
  250 +};
  251 +
  252 +$.Widget = function( /* options, element */ ) {};
  253 +$.Widget._childConstructors = [];
  254 +
  255 +$.Widget.prototype = {
  256 + widgetName: "widget",
  257 + widgetEventPrefix: "",
  258 + defaultElement: "<div>",
  259 + options: {
  260 + disabled: false,
  261 +
  262 + // callbacks
  263 + create: null
  264 + },
  265 + _createWidget: function( options, element ) {
  266 + element = $( element || this.defaultElement || this )[ 0 ];
  267 + this.element = $( element );
  268 + this.uuid = widget_uuid++;
  269 + this.eventNamespace = "." + this.widgetName + this.uuid;
  270 +
  271 + this.bindings = $();
  272 + this.hoverable = $();
  273 + this.focusable = $();
  274 +
  275 + if ( element !== this ) {
  276 + $.data( element, this.widgetFullName, this );
  277 + this._on( true, this.element, {
  278 + remove: function( event ) {
  279 + if ( event.target === element ) {
  280 + this.destroy();
  281 + }
  282 + }
  283 + });
  284 + this.document = $( element.style ?
  285 + // element within the document
  286 + element.ownerDocument :
  287 + // element is window or document
  288 + element.document || element );
  289 + this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
  290 + }
  291 +
  292 + this.options = $.widget.extend( {},
  293 + this.options,
  294 + this._getCreateOptions(),
  295 + options );
  296 +
  297 + this._create();
  298 + this._trigger( "create", null, this._getCreateEventData() );
  299 + this._init();
  300 + },
  301 + _getCreateOptions: $.noop,
  302 + _getCreateEventData: $.noop,
  303 + _create: $.noop,
  304 + _init: $.noop,
  305 +
  306 + destroy: function() {
  307 + this._destroy();
  308 + // we can probably remove the unbind calls in 2.0
  309 + // all event bindings should go through this._on()
  310 + this.element
  311 + .unbind( this.eventNamespace )
  312 + .removeData( this.widgetFullName )
  313 + // support: jquery <1.6.3
  314 + // http://bugs.jquery.com/ticket/9413
  315 + .removeData( $.camelCase( this.widgetFullName ) );
  316 + this.widget()
  317 + .unbind( this.eventNamespace )
  318 + .removeAttr( "aria-disabled" )
  319 + .removeClass(
  320 + this.widgetFullName + "-disabled " +
  321 + "ui-state-disabled" );
  322 +
  323 + // clean up events and states
  324 + this.bindings.unbind( this.eventNamespace );
  325 + this.hoverable.removeClass( "ui-state-hover" );
  326 + this.focusable.removeClass( "ui-state-focus" );
  327 + },
  328 + _destroy: $.noop,
  329 +
  330 + widget: function() {
  331 + return this.element;
  332 + },
  333 +
  334 + option: function( key, value ) {
  335 + var options = key,
  336 + parts,
  337 + curOption,
  338 + i;
  339 +
  340 + if ( arguments.length === 0 ) {
  341 + // don't return a reference to the internal hash
  342 + return $.widget.extend( {}, this.options );
  343 + }
  344 +
  345 + if ( typeof key === "string" ) {
  346 + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
  347 + options = {};
  348 + parts = key.split( "." );
  349 + key = parts.shift();
  350 + if ( parts.length ) {
  351 + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
  352 + for ( i = 0; i < parts.length - 1; i++ ) {
  353 + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
  354 + curOption = curOption[ parts[ i ] ];
  355 + }
  356 + key = parts.pop();
  357 + if ( arguments.length === 1 ) {
  358 + return curOption[ key ] === undefined ? null : curOption[ key ];
  359 + }
  360 + curOption[ key ] = value;
  361 + } else {
  362 + if ( arguments.length === 1 ) {
  363 + return this.options[ key ] === undefined ? null : this.options[ key ];
  364 + }
  365 + options[ key ] = value;
  366 + }
  367 + }
  368 +
  369 + this._setOptions( options );
  370 +
  371 + return this;
  372 + },
  373 + _setOptions: function( options ) {
  374 + var key;
  375 +
  376 + for ( key in options ) {
  377 + this._setOption( key, options[ key ] );
  378 + }
  379 +
  380 + return this;
  381 + },
  382 + _setOption: function( key, value ) {
  383 + this.options[ key ] = value;
  384 +
  385 + if ( key === "disabled" ) {
  386 + this.widget()
  387 + .toggleClass( this.widgetFullName + "-disabled", !!value );
  388 +
  389 + // If the widget is becoming disabled, then nothing is interactive
  390 + if ( value ) {
  391 + this.hoverable.removeClass( "ui-state-hover" );
  392 + this.focusable.removeClass( "ui-state-focus" );
  393 + }
  394 + }
  395 +
  396 + return this;
  397 + },
  398 +
  399 + enable: function() {
  400 + return this._setOptions({ disabled: false });
  401 + },
  402 + disable: function() {
  403 + return this._setOptions({ disabled: true });
  404 + },
  405 +
  406 + _on: function( suppressDisabledCheck, element, handlers ) {
  407 + var delegateElement,
  408 + instance = this;
  409 +
  410 + // no suppressDisabledCheck flag, shuffle arguments
  411 + if ( typeof suppressDisabledCheck !== "boolean" ) {
  412 + handlers = element;
  413 + element = suppressDisabledCheck;
  414 + suppressDisabledCheck = false;
  415 + }
  416 +
  417 + // no element argument, shuffle and use this.element
  418 + if ( !handlers ) {
  419 + handlers = element;
  420 + element = this.element;
  421 + delegateElement = this.widget();
  422 + } else {
  423 + element = delegateElement = $( element );
  424 + this.bindings = this.bindings.add( element );
  425 + }
  426 +
  427 + $.each( handlers, function( event, handler ) {
  428 + function handlerProxy() {
  429 + // allow widgets to customize the disabled handling
  430 + // - disabled as an array instead of boolean
  431 + // - disabled class as method for disabling individual parts
  432 + if ( !suppressDisabledCheck &&
  433 + ( instance.options.disabled === true ||
  434 + $( this ).hasClass( "ui-state-disabled" ) ) ) {
  435 + return;
  436 + }
  437 + return ( typeof handler === "string" ? instance[ handler ] : handler )
  438 + .apply( instance, arguments );
  439 + }
  440 +
  441 + // copy the guid so direct unbinding works
  442 + if ( typeof handler !== "string" ) {
  443 + handlerProxy.guid = handler.guid =
  444 + handler.guid || handlerProxy.guid || $.guid++;
  445 + }
  446 +
  447 + var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
  448 + eventName = match[1] + instance.eventNamespace,
  449 + selector = match[2];
  450 + if ( selector ) {
  451 + delegateElement.delegate( selector, eventName, handlerProxy );
  452 + } else {
  453 + element.bind( eventName, handlerProxy );
  454 + }
  455 + });
  456 + },
  457 +
  458 + _off: function( element, eventName ) {
  459 + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
  460 + this.eventNamespace;
  461 + element.unbind( eventName ).undelegate( eventName );
  462 +
  463 + // Clear the stack to avoid memory leaks (#10056)
  464 + this.bindings = $( this.bindings.not( element ).get() );
  465 + this.focusable = $( this.focusable.not( element ).get() );
  466 + this.hoverable = $( this.hoverable.not( element ).get() );
  467 + },
  468 +
  469 + _delay: function( handler, delay ) {
  470 + function handlerProxy() {
  471 + return ( typeof handler === "string" ? instance[ handler ] : handler )
  472 + .apply( instance, arguments );
  473 + }
  474 + var instance = this;
  475 + return setTimeout( handlerProxy, delay || 0 );
  476 + },
  477 +
  478 + _hoverable: function( element ) {
  479 + this.hoverable = this.hoverable.add( element );
  480 + this._on( element, {
  481 + mouseenter: function( event ) {
  482 + $( event.currentTarget ).addClass( "ui-state-hover" );
  483 + },
  484 + mouseleave: function( event ) {
  485 + $( event.currentTarget ).removeClass( "ui-state-hover" );
  486 + }
  487 + });
  488 + },
  489 +
  490 + _focusable: function( element ) {
  491 + this.focusable = this.focusable.add( element );
  492 + this._on( element, {
  493 + focusin: function( event ) {
  494 + $( event.currentTarget ).addClass( "ui-state-focus" );
  495 + },
  496 + focusout: function( event ) {
  497 + $( event.currentTarget ).removeClass( "ui-state-focus" );
  498 + }
  499 + });
  500 + },
  501 +
  502 + _trigger: function( type, event, data ) {
  503 + var prop, orig,
  504 + callback = this.options[ type ];
  505 +
  506 + data = data || {};
  507 + event = $.Event( event );
  508 + event.type = ( type === this.widgetEventPrefix ?
  509 + type :
  510 + this.widgetEventPrefix + type ).toLowerCase();
  511 + // the original event may come from any element
  512 + // so we need to reset the target on the new event
  513 + event.target = this.element[ 0 ];
  514 +
  515 + // copy original event properties over to the new event
  516 + orig = event.originalEvent;
  517 + if ( orig ) {
  518 + for ( prop in orig ) {
  519 + if ( !( prop in event ) ) {
  520 + event[ prop ] = orig[ prop ];
  521 + }
  522 + }
  523 + }
  524 +
  525 + this.element.trigger( event, data );
  526 + return !( $.isFunction( callback ) &&
  527 + callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
  528 + event.isDefaultPrevented() );
  529 + }
  530 +};
  531 +
  532 +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
  533 + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
  534 + if ( typeof options === "string" ) {
  535 + options = { effect: options };
  536 + }
  537 + var hasOptions,
  538 + effectName = !options ?
  539 + method :
  540 + options === true || typeof options === "number" ?
  541 + defaultEffect :
  542 + options.effect || defaultEffect;
  543 + options = options || {};
  544 + if ( typeof options === "number" ) {
  545 + options = { duration: options };
  546 + }
  547 + hasOptions = !$.isEmptyObject( options );
  548 + options.complete = callback;
  549 + if ( options.delay ) {
  550 + element.delay( options.delay );
  551 + }
  552 + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
  553 + element[ method ]( options );
  554 + } else if ( effectName !== method && element[ effectName ] ) {
  555 + element[ effectName ]( options.duration, options.easing, callback );
  556 + } else {
  557 + element.queue(function( next ) {
  558 + $( this )[ method ]();
  559 + if ( callback ) {
  560 + callback.call( element[ 0 ] );
  561 + }
  562 + next();
  563 + });
  564 + }
  565 + };
  566 +});
  567 +
  568 +var widget = $.widget;
  569 +
  570 +
  571 +
  572 +}));
... ...