sn-jquery-fileupload-rails 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +95 -0
  3. data/Rakefile +15 -0
  4. data/app/assets/images/loading.gif +0 -0
  5. data/app/assets/images/progressbar.gif +0 -0
  6. data/app/assets/javascripts/jquery-fileupload/angularjs.js +12 -0
  7. data/app/assets/javascripts/jquery-fileupload/basic-plus.js +11 -0
  8. data/app/assets/javascripts/jquery-fileupload/basic.js +3 -0
  9. data/app/assets/javascripts/jquery-fileupload/cors/jquery.postmessage-transport.js +126 -0
  10. data/app/assets/javascripts/jquery-fileupload/cors/jquery.xdr-transport.js +89 -0
  11. data/app/assets/javascripts/jquery-fileupload/index.js +13 -0
  12. data/app/assets/javascripts/jquery-fileupload/jquery-ui.js +13 -0
  13. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-angular.js +425 -0
  14. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-audio.js +112 -0
  15. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-image.js +320 -0
  16. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-jquery-ui.js +155 -0
  17. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-process.js +175 -0
  18. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-ui.js +710 -0
  19. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-validate.js +122 -0
  20. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-video.js +112 -0
  21. data/app/assets/javascripts/jquery-fileupload/jquery.fileupload.js +1477 -0
  22. data/app/assets/javascripts/jquery-fileupload/jquery.iframe-transport.js +217 -0
  23. data/app/assets/javascripts/jquery-fileupload/locale.js +29 -0
  24. data/app/assets/javascripts/jquery-fileupload/vendor/canvas-to-blob.js +95 -0
  25. data/app/assets/javascripts/jquery-fileupload/vendor/jquery.ui.widget.js +572 -0
  26. data/app/assets/javascripts/jquery-fileupload/vendor/load-image.all.min.js +1 -0
  27. data/app/assets/javascripts/jquery-fileupload/vendor/tmpl.js +87 -0
  28. data/app/assets/stylesheets/jquery.fileupload-noscript.scss +22 -0
  29. data/app/assets/stylesheets/jquery.fileupload-ui-noscript.scss +17 -0
  30. data/app/assets/stylesheets/jquery.fileupload-ui.scss +57 -0
  31. data/app/assets/stylesheets/jquery.fileupload.scss +37 -0
  32. data/lib/jquery-fileupload-rails.rb +8 -0
  33. data/lib/jquery/fileupload/rails/engine.rb +8 -0
  34. data/lib/jquery/fileupload/rails/middleware.rb +59 -0
  35. data/lib/jquery/fileupload/rails/upload.rb +3 -0
  36. data/lib/jquery/fileupload/rails/version.rb +7 -0
  37. metadata +135 -0
@@ -0,0 +1,217 @@
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
+ }));
@@ -0,0 +1,29 @@
1
+ /*
2
+ * jQuery File Upload Plugin Localization Example 6.5.1
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2012, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*global window */
13
+
14
+ window.locale = {
15
+ "fileupload": {
16
+ "errors": {
17
+ "maxFileSize": "File is too big",
18
+ "minFileSize": "File is too small",
19
+ "acceptFileTypes": "Filetype not allowed",
20
+ "maxNumberOfFiles": "Max number of files exceeded",
21
+ "uploadedBytes": "Uploaded bytes exceed file size",
22
+ "emptyResult": "Empty file upload result"
23
+ },
24
+ "error": "Error",
25
+ "start": "Start",
26
+ "cancel": "Cancel",
27
+ "destroy": "Delete"
28
+ }
29
+ };
@@ -0,0 +1,95 @@
1
+ /*
2
+ * JavaScript Canvas to Blob 2.0.5
3
+ * https://github.com/blueimp/JavaScript-Canvas-to-Blob
4
+ *
5
+ * Copyright 2012, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ *
11
+ * Based on stackoverflow user Stoive's code snippet:
12
+ * http://stackoverflow.com/q/4998908
13
+ */
14
+
15
+ /*jslint nomen: true, regexp: true */
16
+ /*global window, atob, Blob, ArrayBuffer, Uint8Array, define */
17
+
18
+ (function (window) {
19
+ 'use strict';
20
+ var CanvasPrototype = window.HTMLCanvasElement &&
21
+ window.HTMLCanvasElement.prototype,
22
+ hasBlobConstructor = window.Blob && (function () {
23
+ try {
24
+ return Boolean(new Blob());
25
+ } catch (e) {
26
+ return false;
27
+ }
28
+ }()),
29
+ hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array &&
30
+ (function () {
31
+ try {
32
+ return new Blob([new Uint8Array(100)]).size === 100;
33
+ } catch (e) {
34
+ return false;
35
+ }
36
+ }()),
37
+ BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
38
+ window.MozBlobBuilder || window.MSBlobBuilder,
39
+ dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob &&
40
+ window.ArrayBuffer && window.Uint8Array && function (dataURI) {
41
+ var byteString,
42
+ arrayBuffer,
43
+ intArray,
44
+ i,
45
+ mimeString,
46
+ bb;
47
+ if (dataURI.split(',')[0].indexOf('base64') >= 0) {
48
+ // Convert base64 to raw binary data held in a string:
49
+ byteString = atob(dataURI.split(',')[1]);
50
+ } else {
51
+ // Convert base64/URLEncoded data component to raw binary data:
52
+ byteString = decodeURIComponent(dataURI.split(',')[1]);
53
+ }
54
+ // Write the bytes of the string to an ArrayBuffer:
55
+ arrayBuffer = new ArrayBuffer(byteString.length);
56
+ intArray = new Uint8Array(arrayBuffer);
57
+ for (i = 0; i < byteString.length; i += 1) {
58
+ intArray[i] = byteString.charCodeAt(i);
59
+ }
60
+ // Separate out the mime component:
61
+ mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
62
+ // Write the ArrayBuffer (or ArrayBufferView) to a blob:
63
+ if (hasBlobConstructor) {
64
+ return new Blob(
65
+ [hasArrayBufferViewSupport ? intArray : arrayBuffer],
66
+ {type: mimeString}
67
+ );
68
+ }
69
+ bb = new BlobBuilder();
70
+ bb.append(arrayBuffer);
71
+ return bb.getBlob(mimeString);
72
+ };
73
+ if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) {
74
+ if (CanvasPrototype.mozGetAsFile) {
75
+ CanvasPrototype.toBlob = function (callback, type, quality) {
76
+ if (quality && CanvasPrototype.toDataURL && dataURLtoBlob) {
77
+ callback(dataURLtoBlob(this.toDataURL(type, quality)));
78
+ } else {
79
+ callback(this.mozGetAsFile('blob', type));
80
+ }
81
+ };
82
+ } else if (CanvasPrototype.toDataURL && dataURLtoBlob) {
83
+ CanvasPrototype.toBlob = function (callback, type, quality) {
84
+ callback(dataURLtoBlob(this.toDataURL(type, quality)));
85
+ };
86
+ }
87
+ }
88
+ if (typeof define === 'function' && define.amd) {
89
+ define(function () {
90
+ return dataURLtoBlob;
91
+ });
92
+ } else {
93
+ window.dataURLtoBlob = dataURLtoBlob;
94
+ }
95
+ }(window));
@@ -0,0 +1,572 @@
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
+ }));