sufia 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -1
- data/app/assets/javascripts/sufia.js +6 -5
- data/app/assets/javascripts/terms_of_service.js +28 -0
- data/app/controllers/batch_edits_controller.rb +2 -2
- data/app/controllers/generic_files_controller.rb +2 -2
- data/app/models/datastreams/fits_datastream.rb +1 -1
- data/app/views/batch/edit.html.erb +6 -6
- data/app/views/batch_edits/edit.html.erb +10 -6
- data/app/views/catalog/_search_form.html.erb +2 -2
- data/app/views/dashboard/index.html.erb +7 -7
- data/app/views/generic_files/_asset_updated_flash.html.erb +1 -1
- data/app/views/generic_files/_descriptions.html.erb +1 -1
- data/app/views/generic_files/_versioning.html.erb +1 -1
- data/app/views/generic_files/edit.html.erb +10 -10
- data/app/views/generic_files/new.html.erb +3 -3
- data/app/views/generic_files/show.html.erb +1 -1
- data/app/views/users/edit.html.erb +3 -3
- data/config/locales/sufia.en.yml +10 -3
- data/features/step_definitions/scholarsphere.rb +3 -1
- data/features/support/paths.rb +1 -1
- data/lib/sufia/generic_file.rb +2 -3
- data/lib/sufia/generic_file/characterization.rb +1 -1
- data/lib/sufia/jobs/batch_update_job.rb +2 -2
- data/lib/sufia/version.rb +1 -1
- data/lib/tasks/resque.rake +27 -1
- data/spec/models/file_content_datastream_spec.rb +2 -2
- data/spec/models/generic_file_spec.rb +7 -4
- data/sufia.gemspec +3 -5
- data/vendor/assets/javascripts/fileupload.js +1 -3
- data/vendor/assets/javascripts/fileupload/application.js +0 -25
- data/vendor/assets/javascripts/fileupload/tmpl.js +86 -0
- data/vendor/assets/javascripts/jquery-ui-1.9.2/jquery.ui.autocomplete.js +602 -0
- data/vendor/assets/javascripts/jquery-ui-1.9.2/jquery.ui.core.js +356 -0
- data/vendor/assets/javascripts/jquery-ui-1.9.2/jquery.ui.menu.js +610 -0
- data/vendor/assets/javascripts/jquery-ui-1.9.2/jquery.ui.widget.js +528 -0
- data/vendor/assets/javascripts/swfobject.js +4 -0
- metadata +15 -37
- data/app/assets/javascripts/generic_files.js +0 -17
- data/tasks/resque.rake +0 -27
- data/vendor/assets/javascripts/blacklight.js +0 -513
- data/vendor/assets/javascripts/bootstrap-collapse.js +0 -157
- data/vendor/assets/javascripts/bootstrap-popover.js +0 -98
- data/vendor/assets/javascripts/bootstrap-tooltip.js +0 -275
- data/vendor/assets/javascripts/fileupload/tmpl.min.js +0 -1
- data/vendor/assets/javascripts/jquery-1.7.2.min.js +0 -4
- data/vendor/assets/javascripts/jquery-1.8.2.js +0 -9440
- data/vendor/assets/javascripts/jquery-1.8.2.min.js +0 -2
- data/vendor/assets/javascripts/jquery-ui-1.8.16.custom.min.js +0 -791
- data/vendor/assets/javascripts/jquery-ui-1.8.23.custom.min.js +0 -125
- data/vendor/assets/javascripts/jquery_ujs.js +0 -377
@@ -0,0 +1,356 @@
|
|
1
|
+
/*!
|
2
|
+
* jQuery UI Core @VERSION
|
3
|
+
* http://jqueryui.com
|
4
|
+
*
|
5
|
+
* Copyright 2012 jQuery Foundation and other contributors
|
6
|
+
* Released under the MIT license.
|
7
|
+
* http://jquery.org/license
|
8
|
+
*
|
9
|
+
* http://api.jqueryui.com/category/ui-core/
|
10
|
+
*/
|
11
|
+
(function( $, undefined ) {
|
12
|
+
|
13
|
+
var uuid = 0,
|
14
|
+
runiqueId = /^ui-id-\d+$/;
|
15
|
+
|
16
|
+
// prevent duplicate loading
|
17
|
+
// this is only a problem because we proxy existing functions
|
18
|
+
// and we don't want to double proxy them
|
19
|
+
$.ui = $.ui || {};
|
20
|
+
if ( $.ui.version ) {
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
|
24
|
+
$.extend( $.ui, {
|
25
|
+
version: "@VERSION",
|
26
|
+
|
27
|
+
keyCode: {
|
28
|
+
BACKSPACE: 8,
|
29
|
+
COMMA: 188,
|
30
|
+
DELETE: 46,
|
31
|
+
DOWN: 40,
|
32
|
+
END: 35,
|
33
|
+
ENTER: 13,
|
34
|
+
ESCAPE: 27,
|
35
|
+
HOME: 36,
|
36
|
+
LEFT: 37,
|
37
|
+
NUMPAD_ADD: 107,
|
38
|
+
NUMPAD_DECIMAL: 110,
|
39
|
+
NUMPAD_DIVIDE: 111,
|
40
|
+
NUMPAD_ENTER: 108,
|
41
|
+
NUMPAD_MULTIPLY: 106,
|
42
|
+
NUMPAD_SUBTRACT: 109,
|
43
|
+
PAGE_DOWN: 34,
|
44
|
+
PAGE_UP: 33,
|
45
|
+
PERIOD: 190,
|
46
|
+
RIGHT: 39,
|
47
|
+
SPACE: 32,
|
48
|
+
TAB: 9,
|
49
|
+
UP: 38
|
50
|
+
}
|
51
|
+
});
|
52
|
+
|
53
|
+
// plugins
|
54
|
+
$.fn.extend({
|
55
|
+
_focus: $.fn.focus,
|
56
|
+
focus: function( delay, fn ) {
|
57
|
+
return typeof delay === "number" ?
|
58
|
+
this.each(function() {
|
59
|
+
var elem = this;
|
60
|
+
setTimeout(function() {
|
61
|
+
$( elem ).focus();
|
62
|
+
if ( fn ) {
|
63
|
+
fn.call( elem );
|
64
|
+
}
|
65
|
+
}, delay );
|
66
|
+
}) :
|
67
|
+
this._focus.apply( this, arguments );
|
68
|
+
},
|
69
|
+
|
70
|
+
scrollParent: function() {
|
71
|
+
var scrollParent;
|
72
|
+
if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
|
73
|
+
scrollParent = this.parents().filter(function() {
|
74
|
+
return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
|
75
|
+
}).eq(0);
|
76
|
+
} else {
|
77
|
+
scrollParent = this.parents().filter(function() {
|
78
|
+
return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x'));
|
79
|
+
}).eq(0);
|
80
|
+
}
|
81
|
+
|
82
|
+
return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
|
83
|
+
},
|
84
|
+
|
85
|
+
zIndex: function( zIndex ) {
|
86
|
+
if ( zIndex !== undefined ) {
|
87
|
+
return this.css( "zIndex", zIndex );
|
88
|
+
}
|
89
|
+
|
90
|
+
if ( this.length ) {
|
91
|
+
var elem = $( this[ 0 ] ), position, value;
|
92
|
+
while ( elem.length && elem[ 0 ] !== document ) {
|
93
|
+
// Ignore z-index if position is set to a value where z-index is ignored by the browser
|
94
|
+
// This makes behavior of this function consistent across browsers
|
95
|
+
// WebKit always returns auto if the element is positioned
|
96
|
+
position = elem.css( "position" );
|
97
|
+
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
|
98
|
+
// IE returns 0 when zIndex is not specified
|
99
|
+
// other browsers return a string
|
100
|
+
// we ignore the case of nested elements with an explicit value of 0
|
101
|
+
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
|
102
|
+
value = parseInt( elem.css( "zIndex" ), 10 );
|
103
|
+
if ( !isNaN( value ) && value !== 0 ) {
|
104
|
+
return value;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
elem = elem.parent();
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
return 0;
|
112
|
+
},
|
113
|
+
|
114
|
+
uniqueId: function() {
|
115
|
+
return this.each(function() {
|
116
|
+
if ( !this.id ) {
|
117
|
+
this.id = "ui-id-" + (++uuid);
|
118
|
+
}
|
119
|
+
});
|
120
|
+
},
|
121
|
+
|
122
|
+
removeUniqueId: function() {
|
123
|
+
return this.each(function() {
|
124
|
+
if ( runiqueId.test( this.id ) ) {
|
125
|
+
$( this ).removeAttr( "id" );
|
126
|
+
}
|
127
|
+
});
|
128
|
+
}
|
129
|
+
});
|
130
|
+
|
131
|
+
// selectors
|
132
|
+
function focusable( element, isTabIndexNotNaN ) {
|
133
|
+
var map, mapName, img,
|
134
|
+
nodeName = element.nodeName.toLowerCase();
|
135
|
+
if ( "area" === nodeName ) {
|
136
|
+
map = element.parentNode;
|
137
|
+
mapName = map.name;
|
138
|
+
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
|
139
|
+
return false;
|
140
|
+
}
|
141
|
+
img = $( "img[usemap=#" + mapName + "]" )[0];
|
142
|
+
return !!img && visible( img );
|
143
|
+
}
|
144
|
+
return ( /input|select|textarea|button|object/.test( nodeName ) ?
|
145
|
+
!element.disabled :
|
146
|
+
"a" === nodeName ?
|
147
|
+
element.href || isTabIndexNotNaN :
|
148
|
+
isTabIndexNotNaN) &&
|
149
|
+
// the element and all of its ancestors must be visible
|
150
|
+
visible( element );
|
151
|
+
}
|
152
|
+
|
153
|
+
function visible( element ) {
|
154
|
+
return $.expr.filters.visible( element ) &&
|
155
|
+
!$( element ).parents().andSelf().filter(function() {
|
156
|
+
return $.css( this, "visibility" ) === "hidden";
|
157
|
+
}).length;
|
158
|
+
}
|
159
|
+
|
160
|
+
$.extend( $.expr[ ":" ], {
|
161
|
+
data: $.expr.createPseudo ?
|
162
|
+
$.expr.createPseudo(function( dataName ) {
|
163
|
+
return function( elem ) {
|
164
|
+
return !!$.data( elem, dataName );
|
165
|
+
};
|
166
|
+
}) :
|
167
|
+
// support: jQuery <1.8
|
168
|
+
function( elem, i, match ) {
|
169
|
+
return !!$.data( elem, match[ 3 ] );
|
170
|
+
},
|
171
|
+
|
172
|
+
focusable: function( element ) {
|
173
|
+
return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
|
174
|
+
},
|
175
|
+
|
176
|
+
tabbable: function( element ) {
|
177
|
+
var tabIndex = $.attr( element, "tabindex" ),
|
178
|
+
isTabIndexNaN = isNaN( tabIndex );
|
179
|
+
return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
|
180
|
+
}
|
181
|
+
});
|
182
|
+
|
183
|
+
// support
|
184
|
+
$(function() {
|
185
|
+
var body = document.body,
|
186
|
+
div = body.appendChild( div = document.createElement( "div" ) );
|
187
|
+
|
188
|
+
// access offsetHeight before setting the style to prevent a layout bug
|
189
|
+
// in IE 9 which causes the element to continue to take up space even
|
190
|
+
// after it is removed from the DOM (#8026)
|
191
|
+
div.offsetHeight;
|
192
|
+
|
193
|
+
$.extend( div.style, {
|
194
|
+
minHeight: "100px",
|
195
|
+
height: "auto",
|
196
|
+
padding: 0,
|
197
|
+
borderWidth: 0
|
198
|
+
});
|
199
|
+
|
200
|
+
$.support.minHeight = div.offsetHeight === 100;
|
201
|
+
$.support.selectstart = "onselectstart" in div;
|
202
|
+
|
203
|
+
// set display to none to avoid a layout bug in IE
|
204
|
+
// http://dev.jquery.com/ticket/4014
|
205
|
+
body.removeChild( div ).style.display = "none";
|
206
|
+
});
|
207
|
+
|
208
|
+
// support: jQuery <1.8
|
209
|
+
if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
|
210
|
+
$.each( [ "Width", "Height" ], function( i, name ) {
|
211
|
+
var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
|
212
|
+
type = name.toLowerCase(),
|
213
|
+
orig = {
|
214
|
+
innerWidth: $.fn.innerWidth,
|
215
|
+
innerHeight: $.fn.innerHeight,
|
216
|
+
outerWidth: $.fn.outerWidth,
|
217
|
+
outerHeight: $.fn.outerHeight
|
218
|
+
};
|
219
|
+
|
220
|
+
function reduce( elem, size, border, margin ) {
|
221
|
+
$.each( side, function() {
|
222
|
+
size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
|
223
|
+
if ( border ) {
|
224
|
+
size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
|
225
|
+
}
|
226
|
+
if ( margin ) {
|
227
|
+
size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
|
228
|
+
}
|
229
|
+
});
|
230
|
+
return size;
|
231
|
+
}
|
232
|
+
|
233
|
+
$.fn[ "inner" + name ] = function( size ) {
|
234
|
+
if ( size === undefined ) {
|
235
|
+
return orig[ "inner" + name ].call( this );
|
236
|
+
}
|
237
|
+
|
238
|
+
return this.each(function() {
|
239
|
+
$( this ).css( type, reduce( this, size ) + "px" );
|
240
|
+
});
|
241
|
+
};
|
242
|
+
|
243
|
+
$.fn[ "outer" + name] = function( size, margin ) {
|
244
|
+
if ( typeof size !== "number" ) {
|
245
|
+
return orig[ "outer" + name ].call( this, size );
|
246
|
+
}
|
247
|
+
|
248
|
+
return this.each(function() {
|
249
|
+
$( this).css( type, reduce( this, size, true, margin ) + "px" );
|
250
|
+
});
|
251
|
+
};
|
252
|
+
});
|
253
|
+
}
|
254
|
+
|
255
|
+
// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
|
256
|
+
if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
|
257
|
+
$.fn.removeData = (function( removeData ) {
|
258
|
+
return function( key ) {
|
259
|
+
if ( arguments.length ) {
|
260
|
+
return removeData.call( this, $.camelCase( key ) );
|
261
|
+
} else {
|
262
|
+
return removeData.call( this );
|
263
|
+
}
|
264
|
+
};
|
265
|
+
})( $.fn.removeData );
|
266
|
+
}
|
267
|
+
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
|
272
|
+
// deprecated
|
273
|
+
|
274
|
+
(function() {
|
275
|
+
var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || [];
|
276
|
+
$.ui.ie = uaMatch.length ? true : false;
|
277
|
+
$.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6;
|
278
|
+
})();
|
279
|
+
|
280
|
+
$.fn.extend({
|
281
|
+
disableSelection: function() {
|
282
|
+
return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
|
283
|
+
".ui-disableSelection", function( event ) {
|
284
|
+
event.preventDefault();
|
285
|
+
});
|
286
|
+
},
|
287
|
+
|
288
|
+
enableSelection: function() {
|
289
|
+
return this.unbind( ".ui-disableSelection" );
|
290
|
+
}
|
291
|
+
});
|
292
|
+
|
293
|
+
$.extend( $.ui, {
|
294
|
+
// $.ui.plugin is deprecated. Use the proxy pattern instead.
|
295
|
+
plugin: {
|
296
|
+
add: function( module, option, set ) {
|
297
|
+
var i,
|
298
|
+
proto = $.ui[ module ].prototype;
|
299
|
+
for ( i in set ) {
|
300
|
+
proto.plugins[ i ] = proto.plugins[ i ] || [];
|
301
|
+
proto.plugins[ i ].push( [ option, set[ i ] ] );
|
302
|
+
}
|
303
|
+
},
|
304
|
+
call: function( instance, name, args ) {
|
305
|
+
var i,
|
306
|
+
set = instance.plugins[ name ];
|
307
|
+
if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
|
311
|
+
for ( i = 0; i < set.length; i++ ) {
|
312
|
+
if ( instance.options[ set[ i ][ 0 ] ] ) {
|
313
|
+
set[ i ][ 1 ].apply( instance.element, args );
|
314
|
+
}
|
315
|
+
}
|
316
|
+
}
|
317
|
+
},
|
318
|
+
|
319
|
+
contains: $.contains,
|
320
|
+
|
321
|
+
// only used by resizable
|
322
|
+
hasScroll: function( el, a ) {
|
323
|
+
|
324
|
+
//If overflow is hidden, the element might have extra content, but the user wants to hide it
|
325
|
+
if ( $( el ).css( "overflow" ) === "hidden") {
|
326
|
+
return false;
|
327
|
+
}
|
328
|
+
|
329
|
+
var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
|
330
|
+
has = false;
|
331
|
+
|
332
|
+
if ( el[ scroll ] > 0 ) {
|
333
|
+
return true;
|
334
|
+
}
|
335
|
+
|
336
|
+
// TODO: determine which cases actually cause this to happen
|
337
|
+
// if the element doesn't have the scroll set, see if it's possible to
|
338
|
+
// set the scroll
|
339
|
+
el[ scroll ] = 1;
|
340
|
+
has = ( el[ scroll ] > 0 );
|
341
|
+
el[ scroll ] = 0;
|
342
|
+
return has;
|
343
|
+
},
|
344
|
+
|
345
|
+
// these are odd functions, fix the API or move into individual plugins
|
346
|
+
isOverAxis: function( x, reference, size ) {
|
347
|
+
//Determines when x coordinate is over "b" element axis
|
348
|
+
return ( x > reference ) && ( x < ( reference + size ) );
|
349
|
+
},
|
350
|
+
isOver: function( y, x, top, left, height, width ) {
|
351
|
+
//Determines when x, y coordinates is over "b" element
|
352
|
+
return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
|
353
|
+
}
|
354
|
+
});
|
355
|
+
|
356
|
+
})( jQuery );
|
@@ -0,0 +1,610 @@
|
|
1
|
+
/*!
|
2
|
+
* jQuery UI Menu @VERSION
|
3
|
+
* http://jqueryui.com
|
4
|
+
*
|
5
|
+
* Copyright 2012 jQuery Foundation and other contributors
|
6
|
+
* Released under the MIT license.
|
7
|
+
* http://jquery.org/license
|
8
|
+
*
|
9
|
+
* http://api.jqueryui.com/menu/
|
10
|
+
*
|
11
|
+
* Depends:
|
12
|
+
* jquery.ui.core.js
|
13
|
+
* jquery.ui.widget.js
|
14
|
+
* jquery.ui.position.js
|
15
|
+
*/
|
16
|
+
(function( $, undefined ) {
|
17
|
+
|
18
|
+
var mouseHandled = false;
|
19
|
+
|
20
|
+
$.widget( "ui.menu", {
|
21
|
+
version: "@VERSION",
|
22
|
+
defaultElement: "<ul>",
|
23
|
+
delay: 300,
|
24
|
+
options: {
|
25
|
+
icons: {
|
26
|
+
submenu: "ui-icon-carat-1-e"
|
27
|
+
},
|
28
|
+
menus: "ul",
|
29
|
+
position: {
|
30
|
+
my: "left top",
|
31
|
+
at: "right top"
|
32
|
+
},
|
33
|
+
role: "menu",
|
34
|
+
|
35
|
+
// callbacks
|
36
|
+
blur: null,
|
37
|
+
focus: null,
|
38
|
+
select: null
|
39
|
+
},
|
40
|
+
|
41
|
+
_create: function() {
|
42
|
+
this.activeMenu = this.element;
|
43
|
+
this.element
|
44
|
+
.uniqueId()
|
45
|
+
.addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
|
46
|
+
.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
|
47
|
+
.attr({
|
48
|
+
role: this.options.role,
|
49
|
+
tabIndex: 0
|
50
|
+
})
|
51
|
+
// need to catch all clicks on disabled menu
|
52
|
+
// not possible through _on
|
53
|
+
.bind( "click" + this.eventNamespace, $.proxy(function( event ) {
|
54
|
+
if ( this.options.disabled ) {
|
55
|
+
event.preventDefault();
|
56
|
+
}
|
57
|
+
}, this ));
|
58
|
+
|
59
|
+
if ( this.options.disabled ) {
|
60
|
+
this.element
|
61
|
+
.addClass( "ui-state-disabled" )
|
62
|
+
.attr( "aria-disabled", "true" );
|
63
|
+
}
|
64
|
+
|
65
|
+
this._on({
|
66
|
+
// Prevent focus from sticking to links inside menu after clicking
|
67
|
+
// them (focus should always stay on UL during navigation).
|
68
|
+
"mousedown .ui-menu-item > a": function( event ) {
|
69
|
+
event.preventDefault();
|
70
|
+
},
|
71
|
+
"click .ui-state-disabled > a": function( event ) {
|
72
|
+
event.preventDefault();
|
73
|
+
},
|
74
|
+
"click .ui-menu-item:has(a)": function( event ) {
|
75
|
+
var target = $( event.target ).closest( ".ui-menu-item" );
|
76
|
+
if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) {
|
77
|
+
mouseHandled = true;
|
78
|
+
|
79
|
+
this.select( event );
|
80
|
+
// Open submenu on click
|
81
|
+
if ( target.has( ".ui-menu" ).length ) {
|
82
|
+
this.expand( event );
|
83
|
+
} else if ( !this.element.is( ":focus" ) ) {
|
84
|
+
// Redirect focus to the menu
|
85
|
+
this.element.trigger( "focus", [ true ] );
|
86
|
+
|
87
|
+
// If the active item is on the top level, let it stay active.
|
88
|
+
// Otherwise, blur the active item since it is no longer visible.
|
89
|
+
if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
|
90
|
+
clearTimeout( this.timer );
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
},
|
95
|
+
"mouseenter .ui-menu-item": function( event ) {
|
96
|
+
var target = $( event.currentTarget );
|
97
|
+
// Remove ui-state-active class from siblings of the newly focused menu item
|
98
|
+
// to avoid a jump caused by adjacent elements both having a class with a border
|
99
|
+
target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
|
100
|
+
this.focus( event, target );
|
101
|
+
},
|
102
|
+
mouseleave: "collapseAll",
|
103
|
+
"mouseleave .ui-menu": "collapseAll",
|
104
|
+
focus: function( event, keepActiveItem ) {
|
105
|
+
// If there's already an active item, keep it active
|
106
|
+
// If not, activate the first item
|
107
|
+
var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
|
108
|
+
|
109
|
+
if ( !keepActiveItem ) {
|
110
|
+
this.focus( event, item );
|
111
|
+
}
|
112
|
+
},
|
113
|
+
blur: function( event ) {
|
114
|
+
this._delay(function() {
|
115
|
+
if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
|
116
|
+
this.collapseAll( event );
|
117
|
+
}
|
118
|
+
});
|
119
|
+
},
|
120
|
+
keydown: "_keydown"
|
121
|
+
});
|
122
|
+
|
123
|
+
this.refresh();
|
124
|
+
|
125
|
+
// Clicks outside of a menu collapse any open menus
|
126
|
+
this._on( this.document, {
|
127
|
+
click: function( event ) {
|
128
|
+
if ( !$( event.target ).closest( ".ui-menu" ).length ) {
|
129
|
+
this.collapseAll( event );
|
130
|
+
}
|
131
|
+
|
132
|
+
// Reset the mouseHandled flag
|
133
|
+
mouseHandled = false;
|
134
|
+
}
|
135
|
+
});
|
136
|
+
},
|
137
|
+
|
138
|
+
_destroy: function() {
|
139
|
+
// Destroy (sub)menus
|
140
|
+
this.element
|
141
|
+
.removeAttr( "aria-activedescendant" )
|
142
|
+
.find( ".ui-menu" ).andSelf()
|
143
|
+
.removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
|
144
|
+
.removeAttr( "role" )
|
145
|
+
.removeAttr( "tabIndex" )
|
146
|
+
.removeAttr( "aria-labelledby" )
|
147
|
+
.removeAttr( "aria-expanded" )
|
148
|
+
.removeAttr( "aria-hidden" )
|
149
|
+
.removeAttr( "aria-disabled" )
|
150
|
+
.removeUniqueId()
|
151
|
+
.show();
|
152
|
+
|
153
|
+
// Destroy menu items
|
154
|
+
this.element.find( ".ui-menu-item" )
|
155
|
+
.removeClass( "ui-menu-item" )
|
156
|
+
.removeAttr( "role" )
|
157
|
+
.removeAttr( "aria-disabled" )
|
158
|
+
.children( "a" )
|
159
|
+
.removeUniqueId()
|
160
|
+
.removeClass( "ui-corner-all ui-state-hover" )
|
161
|
+
.removeAttr( "tabIndex" )
|
162
|
+
.removeAttr( "role" )
|
163
|
+
.removeAttr( "aria-haspopup" )
|
164
|
+
.children().each( function() {
|
165
|
+
var elem = $( this );
|
166
|
+
if ( elem.data( "ui-menu-submenu-carat" ) ) {
|
167
|
+
elem.remove();
|
168
|
+
}
|
169
|
+
});
|
170
|
+
|
171
|
+
// Destroy menu dividers
|
172
|
+
this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
|
173
|
+
},
|
174
|
+
|
175
|
+
_keydown: function( event ) {
|
176
|
+
var match, prev, character, skip, regex,
|
177
|
+
preventDefault = true;
|
178
|
+
|
179
|
+
function escape( value ) {
|
180
|
+
return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
|
181
|
+
}
|
182
|
+
|
183
|
+
switch ( event.keyCode ) {
|
184
|
+
case $.ui.keyCode.PAGE_UP:
|
185
|
+
this.previousPage( event );
|
186
|
+
break;
|
187
|
+
case $.ui.keyCode.PAGE_DOWN:
|
188
|
+
this.nextPage( event );
|
189
|
+
break;
|
190
|
+
case $.ui.keyCode.HOME:
|
191
|
+
this._move( "first", "first", event );
|
192
|
+
break;
|
193
|
+
case $.ui.keyCode.END:
|
194
|
+
this._move( "last", "last", event );
|
195
|
+
break;
|
196
|
+
case $.ui.keyCode.UP:
|
197
|
+
this.previous( event );
|
198
|
+
break;
|
199
|
+
case $.ui.keyCode.DOWN:
|
200
|
+
this.next( event );
|
201
|
+
break;
|
202
|
+
case $.ui.keyCode.LEFT:
|
203
|
+
this.collapse( event );
|
204
|
+
break;
|
205
|
+
case $.ui.keyCode.RIGHT:
|
206
|
+
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
|
207
|
+
this.expand( event );
|
208
|
+
}
|
209
|
+
break;
|
210
|
+
case $.ui.keyCode.ENTER:
|
211
|
+
case $.ui.keyCode.SPACE:
|
212
|
+
this._activate( event );
|
213
|
+
break;
|
214
|
+
case $.ui.keyCode.ESCAPE:
|
215
|
+
this.collapse( event );
|
216
|
+
break;
|
217
|
+
default:
|
218
|
+
preventDefault = false;
|
219
|
+
prev = this.previousFilter || "";
|
220
|
+
character = String.fromCharCode( event.keyCode );
|
221
|
+
skip = false;
|
222
|
+
|
223
|
+
clearTimeout( this.filterTimer );
|
224
|
+
|
225
|
+
if ( character === prev ) {
|
226
|
+
skip = true;
|
227
|
+
} else {
|
228
|
+
character = prev + character;
|
229
|
+
}
|
230
|
+
|
231
|
+
regex = new RegExp( "^" + escape( character ), "i" );
|
232
|
+
match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
|
233
|
+
return regex.test( $( this ).children( "a" ).text() );
|
234
|
+
});
|
235
|
+
match = skip && match.index( this.active.next() ) !== -1 ?
|
236
|
+
this.active.nextAll( ".ui-menu-item" ) :
|
237
|
+
match;
|
238
|
+
|
239
|
+
// If no matches on the current filter, reset to the last character pressed
|
240
|
+
// to move down the menu to the first item that starts with that character
|
241
|
+
if ( !match.length ) {
|
242
|
+
character = String.fromCharCode( event.keyCode );
|
243
|
+
regex = new RegExp( "^" + escape( character ), "i" );
|
244
|
+
match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
|
245
|
+
return regex.test( $( this ).children( "a" ).text() );
|
246
|
+
});
|
247
|
+
}
|
248
|
+
|
249
|
+
if ( match.length ) {
|
250
|
+
this.focus( event, match );
|
251
|
+
if ( match.length > 1 ) {
|
252
|
+
this.previousFilter = character;
|
253
|
+
this.filterTimer = this._delay(function() {
|
254
|
+
delete this.previousFilter;
|
255
|
+
}, 1000 );
|
256
|
+
} else {
|
257
|
+
delete this.previousFilter;
|
258
|
+
}
|
259
|
+
} else {
|
260
|
+
delete this.previousFilter;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
if ( preventDefault ) {
|
265
|
+
event.preventDefault();
|
266
|
+
}
|
267
|
+
},
|
268
|
+
|
269
|
+
_activate: function( event ) {
|
270
|
+
if ( !this.active.is( ".ui-state-disabled" ) ) {
|
271
|
+
if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
|
272
|
+
this.expand( event );
|
273
|
+
} else {
|
274
|
+
this.select( event );
|
275
|
+
}
|
276
|
+
}
|
277
|
+
},
|
278
|
+
|
279
|
+
refresh: function() {
|
280
|
+
var menus,
|
281
|
+
icon = this.options.icons.submenu,
|
282
|
+
submenus = this.element.find( this.options.menus );
|
283
|
+
|
284
|
+
// Initialize nested menus
|
285
|
+
submenus.filter( ":not(.ui-menu)" )
|
286
|
+
.addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
|
287
|
+
.hide()
|
288
|
+
.attr({
|
289
|
+
role: this.options.role,
|
290
|
+
"aria-hidden": "true",
|
291
|
+
"aria-expanded": "false"
|
292
|
+
})
|
293
|
+
.each(function() {
|
294
|
+
var menu = $( this ),
|
295
|
+
item = menu.prev( "a" ),
|
296
|
+
submenuCarat = $( "<span>" )
|
297
|
+
.addClass( "ui-menu-icon ui-icon " + icon )
|
298
|
+
.data( "ui-menu-submenu-carat", true );
|
299
|
+
|
300
|
+
item
|
301
|
+
.attr( "aria-haspopup", "true" )
|
302
|
+
.prepend( submenuCarat );
|
303
|
+
menu.attr( "aria-labelledby", item.attr( "id" ) );
|
304
|
+
});
|
305
|
+
|
306
|
+
menus = submenus.add( this.element );
|
307
|
+
|
308
|
+
// Don't refresh list items that are already adapted
|
309
|
+
menus.children( ":not(.ui-menu-item):has(a)" )
|
310
|
+
.addClass( "ui-menu-item" )
|
311
|
+
.attr( "role", "presentation" )
|
312
|
+
.children( "a" )
|
313
|
+
.uniqueId()
|
314
|
+
.addClass( "ui-corner-all" )
|
315
|
+
.attr({
|
316
|
+
tabIndex: -1,
|
317
|
+
role: this._itemRole()
|
318
|
+
});
|
319
|
+
|
320
|
+
// Initialize unlinked menu-items containing spaces and/or dashes only as dividers
|
321
|
+
menus.children( ":not(.ui-menu-item)" ).each(function() {
|
322
|
+
var item = $( this );
|
323
|
+
// hyphen, em dash, en dash
|
324
|
+
if ( !/[^\-—–\s]/.test( item.text() ) ) {
|
325
|
+
item.addClass( "ui-widget-content ui-menu-divider" );
|
326
|
+
}
|
327
|
+
});
|
328
|
+
|
329
|
+
// Add aria-disabled attribute to any disabled menu item
|
330
|
+
menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
|
331
|
+
|
332
|
+
// If the active item has been removed, blur the menu
|
333
|
+
if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
|
334
|
+
this.blur();
|
335
|
+
}
|
336
|
+
},
|
337
|
+
|
338
|
+
_itemRole: function() {
|
339
|
+
return {
|
340
|
+
menu: "menuitem",
|
341
|
+
listbox: "option"
|
342
|
+
}[ this.options.role ];
|
343
|
+
},
|
344
|
+
|
345
|
+
focus: function( event, item ) {
|
346
|
+
var nested, focused;
|
347
|
+
this.blur( event, event && event.type === "focus" );
|
348
|
+
|
349
|
+
this._scrollIntoView( item );
|
350
|
+
|
351
|
+
this.active = item.first();
|
352
|
+
focused = this.active.children( "a" ).addClass( "ui-state-focus" );
|
353
|
+
// Only update aria-activedescendant if there's a role
|
354
|
+
// otherwise we assume focus is managed elsewhere
|
355
|
+
if ( this.options.role ) {
|
356
|
+
this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
|
357
|
+
}
|
358
|
+
|
359
|
+
// Highlight active parent menu item, if any
|
360
|
+
this.active
|
361
|
+
.parent()
|
362
|
+
.closest( ".ui-menu-item" )
|
363
|
+
.children( "a:first" )
|
364
|
+
.addClass( "ui-state-active" );
|
365
|
+
|
366
|
+
if ( event && event.type === "keydown" ) {
|
367
|
+
this._close();
|
368
|
+
} else {
|
369
|
+
this.timer = this._delay(function() {
|
370
|
+
this._close();
|
371
|
+
}, this.delay );
|
372
|
+
}
|
373
|
+
|
374
|
+
nested = item.children( ".ui-menu" );
|
375
|
+
if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
|
376
|
+
this._startOpening(nested);
|
377
|
+
}
|
378
|
+
this.activeMenu = item.parent();
|
379
|
+
|
380
|
+
this._trigger( "focus", event, { item: item } );
|
381
|
+
},
|
382
|
+
|
383
|
+
_scrollIntoView: function( item ) {
|
384
|
+
var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
|
385
|
+
if ( this._hasScroll() ) {
|
386
|
+
borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
|
387
|
+
paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
|
388
|
+
offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
|
389
|
+
scroll = this.activeMenu.scrollTop();
|
390
|
+
elementHeight = this.activeMenu.height();
|
391
|
+
itemHeight = item.height();
|
392
|
+
|
393
|
+
if ( offset < 0 ) {
|
394
|
+
this.activeMenu.scrollTop( scroll + offset );
|
395
|
+
} else if ( offset + itemHeight > elementHeight ) {
|
396
|
+
this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
|
397
|
+
}
|
398
|
+
}
|
399
|
+
},
|
400
|
+
|
401
|
+
blur: function( event, fromFocus ) {
|
402
|
+
if ( !fromFocus ) {
|
403
|
+
clearTimeout( this.timer );
|
404
|
+
}
|
405
|
+
|
406
|
+
if ( !this.active ) {
|
407
|
+
return;
|
408
|
+
}
|
409
|
+
|
410
|
+
this.active.children( "a" ).removeClass( "ui-state-focus" );
|
411
|
+
this.active = null;
|
412
|
+
|
413
|
+
this._trigger( "blur", event, { item: this.active } );
|
414
|
+
},
|
415
|
+
|
416
|
+
_startOpening: function( submenu ) {
|
417
|
+
clearTimeout( this.timer );
|
418
|
+
|
419
|
+
// Don't open if already open fixes a Firefox bug that caused a .5 pixel
|
420
|
+
// shift in the submenu position when mousing over the carat icon
|
421
|
+
if ( submenu.attr( "aria-hidden" ) !== "true" ) {
|
422
|
+
return;
|
423
|
+
}
|
424
|
+
|
425
|
+
this.timer = this._delay(function() {
|
426
|
+
this._close();
|
427
|
+
this._open( submenu );
|
428
|
+
}, this.delay );
|
429
|
+
},
|
430
|
+
|
431
|
+
_open: function( submenu ) {
|
432
|
+
var position = $.extend({
|
433
|
+
of: this.active
|
434
|
+
}, this.options.position );
|
435
|
+
|
436
|
+
clearTimeout( this.timer );
|
437
|
+
this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
|
438
|
+
.hide()
|
439
|
+
.attr( "aria-hidden", "true" );
|
440
|
+
|
441
|
+
submenu
|
442
|
+
.show()
|
443
|
+
.removeAttr( "aria-hidden" )
|
444
|
+
.attr( "aria-expanded", "true" )
|
445
|
+
.position( position );
|
446
|
+
},
|
447
|
+
|
448
|
+
collapseAll: function( event, all ) {
|
449
|
+
clearTimeout( this.timer );
|
450
|
+
this.timer = this._delay(function() {
|
451
|
+
// If we were passed an event, look for the submenu that contains the event
|
452
|
+
var currentMenu = all ? this.element :
|
453
|
+
$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
|
454
|
+
|
455
|
+
// If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
|
456
|
+
if ( !currentMenu.length ) {
|
457
|
+
currentMenu = this.element;
|
458
|
+
}
|
459
|
+
|
460
|
+
this._close( currentMenu );
|
461
|
+
|
462
|
+
this.blur( event );
|
463
|
+
this.activeMenu = currentMenu;
|
464
|
+
}, this.delay );
|
465
|
+
},
|
466
|
+
|
467
|
+
// With no arguments, closes the currently active menu - if nothing is active
|
468
|
+
// it closes all menus. If passed an argument, it will search for menus BELOW
|
469
|
+
_close: function( startMenu ) {
|
470
|
+
if ( !startMenu ) {
|
471
|
+
startMenu = this.active ? this.active.parent() : this.element;
|
472
|
+
}
|
473
|
+
|
474
|
+
startMenu
|
475
|
+
.find( ".ui-menu" )
|
476
|
+
.hide()
|
477
|
+
.attr( "aria-hidden", "true" )
|
478
|
+
.attr( "aria-expanded", "false" )
|
479
|
+
.end()
|
480
|
+
.find( "a.ui-state-active" )
|
481
|
+
.removeClass( "ui-state-active" );
|
482
|
+
},
|
483
|
+
|
484
|
+
collapse: function( event ) {
|
485
|
+
var newItem = this.active &&
|
486
|
+
this.active.parent().closest( ".ui-menu-item", this.element );
|
487
|
+
if ( newItem && newItem.length ) {
|
488
|
+
this._close();
|
489
|
+
this.focus( event, newItem );
|
490
|
+
}
|
491
|
+
},
|
492
|
+
|
493
|
+
expand: function( event ) {
|
494
|
+
var newItem = this.active &&
|
495
|
+
this.active
|
496
|
+
.children( ".ui-menu " )
|
497
|
+
.children( ".ui-menu-item" )
|
498
|
+
.first();
|
499
|
+
|
500
|
+
if ( newItem && newItem.length ) {
|
501
|
+
this._open( newItem.parent() );
|
502
|
+
|
503
|
+
// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
|
504
|
+
this._delay(function() {
|
505
|
+
this.focus( event, newItem );
|
506
|
+
});
|
507
|
+
}
|
508
|
+
},
|
509
|
+
|
510
|
+
next: function( event ) {
|
511
|
+
this._move( "next", "first", event );
|
512
|
+
},
|
513
|
+
|
514
|
+
previous: function( event ) {
|
515
|
+
this._move( "prev", "last", event );
|
516
|
+
},
|
517
|
+
|
518
|
+
isFirstItem: function() {
|
519
|
+
return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
|
520
|
+
},
|
521
|
+
|
522
|
+
isLastItem: function() {
|
523
|
+
return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
|
524
|
+
},
|
525
|
+
|
526
|
+
_move: function( direction, filter, event ) {
|
527
|
+
var next;
|
528
|
+
if ( this.active ) {
|
529
|
+
if ( direction === "first" || direction === "last" ) {
|
530
|
+
next = this.active
|
531
|
+
[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
|
532
|
+
.eq( -1 );
|
533
|
+
} else {
|
534
|
+
next = this.active
|
535
|
+
[ direction + "All" ]( ".ui-menu-item" )
|
536
|
+
.eq( 0 );
|
537
|
+
}
|
538
|
+
}
|
539
|
+
if ( !next || !next.length || !this.active ) {
|
540
|
+
next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
|
541
|
+
}
|
542
|
+
|
543
|
+
this.focus( event, next );
|
544
|
+
},
|
545
|
+
|
546
|
+
nextPage: function( event ) {
|
547
|
+
var item, base, height;
|
548
|
+
|
549
|
+
if ( !this.active ) {
|
550
|
+
this.next( event );
|
551
|
+
return;
|
552
|
+
}
|
553
|
+
if ( this.isLastItem() ) {
|
554
|
+
return;
|
555
|
+
}
|
556
|
+
if ( this._hasScroll() ) {
|
557
|
+
base = this.active.offset().top;
|
558
|
+
height = this.element.height();
|
559
|
+
this.active.nextAll( ".ui-menu-item" ).each(function() {
|
560
|
+
item = $( this );
|
561
|
+
return item.offset().top - base - height < 0;
|
562
|
+
});
|
563
|
+
|
564
|
+
this.focus( event, item );
|
565
|
+
} else {
|
566
|
+
this.focus( event, this.activeMenu.children( ".ui-menu-item" )
|
567
|
+
[ !this.active ? "first" : "last" ]() );
|
568
|
+
}
|
569
|
+
},
|
570
|
+
|
571
|
+
previousPage: function( event ) {
|
572
|
+
var item, base, height;
|
573
|
+
if ( !this.active ) {
|
574
|
+
this.next( event );
|
575
|
+
return;
|
576
|
+
}
|
577
|
+
if ( this.isFirstItem() ) {
|
578
|
+
return;
|
579
|
+
}
|
580
|
+
if ( this._hasScroll() ) {
|
581
|
+
base = this.active.offset().top;
|
582
|
+
height = this.element.height();
|
583
|
+
this.active.prevAll( ".ui-menu-item" ).each(function() {
|
584
|
+
item = $( this );
|
585
|
+
return item.offset().top - base + height > 0;
|
586
|
+
});
|
587
|
+
|
588
|
+
this.focus( event, item );
|
589
|
+
} else {
|
590
|
+
this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
|
591
|
+
}
|
592
|
+
},
|
593
|
+
|
594
|
+
_hasScroll: function() {
|
595
|
+
return this.element.outerHeight() < this.element.prop( "scrollHeight" );
|
596
|
+
},
|
597
|
+
|
598
|
+
select: function( event ) {
|
599
|
+
// TODO: It should never be possible to not have an active item at this
|
600
|
+
// point, but the tests don't trigger mouseenter before click.
|
601
|
+
this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
|
602
|
+
var ui = { item: this.active };
|
603
|
+
if ( !this.active.has( ".ui-menu" ).length ) {
|
604
|
+
this.collapseAll( event, true );
|
605
|
+
}
|
606
|
+
this._trigger( "select", event, ui );
|
607
|
+
}
|
608
|
+
});
|
609
|
+
|
610
|
+
}( jQuery ));
|