transit 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. data/Gemfile +19 -11
  2. data/app/assets/images/transit/icon24x24.png +0 -0
  3. data/app/assets/images/transit/icon24x24_files.png +0 -0
  4. data/app/assets/images/transit/jplayer.swf +0 -0
  5. data/app/assets/images/transit/uploadify.swf +0 -0
  6. data/app/assets/images/transit/video_player.swf +0 -0
  7. data/app/assets/javascripts/jqtools/expose.js +224 -0
  8. data/app/assets/javascripts/jqtools/flashembed.js +300 -0
  9. data/app/assets/javascripts/jqtools/overlay.js +294 -0
  10. data/app/assets/javascripts/jqtools/scrollable.js +3 -0
  11. data/app/assets/javascripts/jqtools/scrollable/autoscroll.js +81 -0
  12. data/app/assets/javascripts/jqtools/scrollable/base.js +335 -0
  13. data/app/assets/javascripts/jqtools/scrollable/navigator.js +139 -0
  14. data/app/assets/javascripts/jqtools/validator.js +590 -0
  15. data/app/assets/javascripts/jqueryui/accordion.js +611 -0
  16. data/app/assets/javascripts/jqueryui/autocomplete.js +612 -0
  17. data/app/assets/javascripts/jqueryui/button.js +388 -0
  18. data/app/assets/javascripts/jqueryui/core.js +312 -0
  19. data/app/assets/javascripts/jqueryui/datepicker.js +1791 -0
  20. data/app/assets/javascripts/jqueryui/dialog.js +878 -0
  21. data/app/assets/javascripts/jqueryui/draggable.js +815 -0
  22. data/app/assets/javascripts/jqueryui/droppable.js +285 -0
  23. data/app/assets/javascripts/jqueryui/effects/blind.js +49 -0
  24. data/app/assets/javascripts/jqueryui/effects/bounce.js +78 -0
  25. data/app/assets/javascripts/jqueryui/effects/clip.js +54 -0
  26. data/app/assets/javascripts/jqueryui/effects/core.js +746 -0
  27. data/app/assets/javascripts/jqueryui/effects/drop.js +50 -0
  28. data/app/assets/javascripts/jqueryui/effects/explode.js +79 -0
  29. data/app/assets/javascripts/jqueryui/effects/fade.js +32 -0
  30. data/app/assets/javascripts/jqueryui/effects/fold.js +56 -0
  31. data/app/assets/javascripts/jqueryui/effects/highlight.js +50 -0
  32. data/app/assets/javascripts/jqueryui/effects/pulsate.js +51 -0
  33. data/app/assets/javascripts/jqueryui/effects/scale.js +178 -0
  34. data/app/assets/javascripts/jqueryui/effects/shake.js +57 -0
  35. data/app/assets/javascripts/jqueryui/effects/slide.js +50 -0
  36. data/app/assets/javascripts/jqueryui/effects/transfer.js +45 -0
  37. data/app/assets/javascripts/jqueryui/mouse.js +160 -0
  38. data/app/assets/javascripts/jqueryui/position.js +252 -0
  39. data/app/assets/javascripts/jqueryui/progressbar.js +109 -0
  40. data/app/assets/javascripts/jqueryui/resizable.js +814 -0
  41. data/app/assets/javascripts/jqueryui/selectable.js +266 -0
  42. data/app/assets/javascripts/jqueryui/slider.js +666 -0
  43. data/app/assets/javascripts/jqueryui/sortable.js +1077 -0
  44. data/app/assets/javascripts/jqueryui/tabs.js +758 -0
  45. data/app/assets/javascripts/jqueryui/widget.js +262 -0
  46. data/app/assets/javascripts/libs/backbone.js +1152 -0
  47. data/app/assets/javascripts/libs/cookie.js +89 -0
  48. data/app/assets/javascripts/libs/fileinput.js +130 -0
  49. data/app/assets/javascripts/libs/jplayer.js +1768 -0
  50. data/app/assets/javascripts/libs/proper.js +541 -0
  51. data/app/assets/javascripts/libs/sanitize.js +282 -0
  52. data/app/assets/javascripts/libs/selecttolist.js +75 -0
  53. data/app/assets/javascripts/libs/underscore.js +807 -0
  54. data/app/assets/javascripts/libs/uploadify.js +677 -0
  55. data/app/assets/javascripts/libs/wymeditor.js +9538 -0
  56. data/app/assets/javascripts/transit.js +4 -0
  57. data/app/assets/javascripts/transit/admin.js +22 -0
  58. data/app/assets/javascripts/transit/admin/contexts.js +52 -0
  59. data/app/assets/javascripts/transit/admin/fields.js +36 -0
  60. data/app/assets/javascripts/transit/admin/upload.js +109 -0
  61. data/app/assets/javascripts/transit/config.js.erb +101 -0
  62. data/app/assets/javascripts/transit/contexts/audio.js +39 -0
  63. data/app/assets/javascripts/transit/contexts/video.js +79 -0
  64. data/app/assets/javascripts/transit/core.js +171 -0
  65. data/app/assets/javascripts/transit/frontend.js +3 -0
  66. data/app/assets/javascripts/transit/lib/base64.js +120 -0
  67. data/app/assets/javascripts/transit/lib/editor.js +177 -0
  68. data/app/assets/javascripts/transit/views/audio_player.jst +22 -0
  69. data/app/assets/javascripts/transit/views/editor_toolbar.jst +12 -0
  70. data/app/assets/javascripts/transit/views/file_upload.jst +5 -0
  71. data/app/assets/javascripts/transit/views/video_player.jst +20 -0
  72. data/app/assets/javascripts/transit/views/wym_box.jst +4 -0
  73. data/app/assets/javascripts/transit/views/wym_iframe.jst +3 -0
  74. data/app/assets/stylesheets/transit.css.scss.erb +42 -0
  75. data/app/assets/stylesheets/transit/forms.css.scss +66 -0
  76. data/app/assets/stylesheets/transit/media/audio.css.scss +65 -0
  77. data/app/assets/stylesheets/transit/media/video.css.scss +30 -0
  78. data/app/assets/stylesheets/transit/panel.css.scss +100 -0
  79. data/app/assets/stylesheets/transit/ui.css.scss +507 -0
  80. data/app/controllers/pages_controller.rb +3 -0
  81. data/app/controllers/posts_controller.rb +3 -0
  82. data/app/controllers/transit/assets_controller.rb +38 -0
  83. data/app/controllers/transit/contexts_controller.rb +12 -9
  84. data/app/controllers/transit/pages_controller.rb +26 -0
  85. data/app/controllers/transit/posts_controller.rb +31 -0
  86. data/app/controllers/transit/topics_controller.rb +5 -0
  87. data/app/controllers/transit_controller.rb +16 -0
  88. data/app/helpers/transit/admin_helper.rb +43 -0
  89. data/app/helpers/transit/form_helper.rb +17 -0
  90. data/app/helpers/transit/package_helper.rb +41 -0
  91. data/app/helpers/transit/pagination_helper.rb +58 -0
  92. data/app/helpers/transit_helper.rb +42 -0
  93. data/app/models/comment.rb +37 -0
  94. data/app/models/contexts/audio.rb +12 -0
  95. data/app/models/{text.rb → contexts/text.rb} +0 -0
  96. data/app/models/contexts/video.rb +24 -0
  97. data/app/models/topic.rb +19 -0
  98. data/app/models/transit/asset.rb +68 -0
  99. data/{lib → app/models}/transit/context.rb +29 -0
  100. data/app/views/contexts/_text.html.erb +1 -1
  101. data/app/views/posts/index.rss.builder +18 -0
  102. data/app/views/transit/assets/_file.html.erb +4 -0
  103. data/app/views/transit/assets/_image.html.erb +13 -0
  104. data/app/views/transit/assets/create.js.erb +8 -0
  105. data/app/views/transit/assets/destroy.js.erb +3 -0
  106. data/app/views/transit/assets/manage.html.erb +20 -0
  107. data/app/views/transit/contexts/_audio.html.erb +18 -0
  108. data/app/views/transit/contexts/_text.html.erb +6 -0
  109. data/app/views/transit/contexts/_video.html.erb +13 -0
  110. data/app/views/transit/contexts/destroy.js.erb +1 -0
  111. data/app/views/transit/contexts/index.html.erb +5 -0
  112. data/app/views/transit/contexts/new.js.erb +7 -0
  113. data/app/views/transit/contexts/show.html.erb +8 -0
  114. data/app/views/transit/index.html.erb +26 -0
  115. data/app/views/transit/index.js.erb +1 -0
  116. data/app/views/transit/interface/post_panel.html.erb +96 -0
  117. data/app/views/transit/pages/_table.html.erb +7 -0
  118. data/app/views/transit/pages/edit.html.erb +17 -0
  119. data/app/views/transit/pages/index.html.erb +17 -0
  120. data/app/views/transit/pages/update.js.erb +1 -0
  121. data/app/views/transit/posts/_form.html.erb +49 -0
  122. data/app/views/transit/posts/edit.html.erb +14 -0
  123. data/app/views/transit/posts/new.html.erb +21 -0
  124. data/app/views/transit/table.html.erb +13 -0
  125. data/app/views/transit/table.js.erb +8 -0
  126. data/app/views/transit/topics/manage.html.erb +28 -0
  127. data/config/locales/en.yml +22 -0
  128. data/config/routes.rb +3 -3
  129. data/lib/transit.rb +51 -17
  130. data/lib/transit/admin.rb +85 -0
  131. data/lib/transit/builders/form_builder.rb +319 -0
  132. data/lib/transit/builders/jst_builder.rb +38 -0
  133. data/lib/transit/builders/package_builder.rb +45 -0
  134. data/lib/transit/config.rb +20 -0
  135. data/lib/transit/controller/generator.rb +42 -0
  136. data/lib/transit/controller/responder.rb +34 -0
  137. data/lib/transit/core_ext.rb +18 -0
  138. data/lib/transit/errors/resource_not_found.rb +6 -0
  139. data/lib/transit/model/assets.rb +14 -0
  140. data/lib/transit/model/attachments.rb +55 -0
  141. data/lib/transit/model/auto_increment.rb +22 -0
  142. data/lib/transit/model/base.rb +56 -0
  143. data/lib/transit/model/comments.rb +19 -0
  144. data/lib/transit/model/hooks.rb +38 -0
  145. data/lib/transit/model/owners.rb +14 -0
  146. data/lib/transit/model/paginator.rb +92 -0
  147. data/lib/transit/model/topics.rb +14 -0
  148. data/lib/transit/package/page.rb +20 -12
  149. data/lib/transit/package/post.rb +87 -33
  150. data/lib/transit/package/post/validations.rb +14 -0
  151. data/lib/transit/rails/engine.rb +29 -13
  152. data/lib/transit/rails/railtie.rb +31 -0
  153. data/lib/transit/rails/routing.rb +11 -6
  154. data/lib/transit/services.rb +13 -0
  155. data/lib/transit/services/base.rb +14 -0
  156. data/lib/transit/services/facebook.rb +13 -0
  157. data/lib/transit/services/ted.rb +10 -0
  158. data/lib/transit/services/twitter.rb +13 -0
  159. data/lib/transit/services/vimeo.rb +10 -0
  160. data/lib/transit/services/you_tube.rb +12 -0
  161. data/lib/transit/version.rb +1 -1
  162. metadata +178 -31
  163. data/app/assets/stylesheets/includes/_compat.scss +0 -24
  164. data/app/assets/stylesheets/includes/_defaults.scss +0 -99
  165. data/app/assets/stylesheets/includes/_global.scss +0 -16
  166. data/app/assets/stylesheets/includes/_imports.scss +0 -27
  167. data/app/assets/stylesheets/includes/_mixins.scss +0 -38
  168. data/app/assets/stylesheets/includes/_setup.scss +0 -85
  169. data/app/assets/stylesheets/layout.css.scss +0 -29
  170. data/app/assets/stylesheets/transit.css +0 -3
  171. data/app/controllers/application_controller.rb +0 -5
  172. data/app/controllers/transit/index_controller.rb +0 -7
  173. data/app/controllers/transit/packages_controller.rb +0 -64
  174. data/app/controllers/transit/transit_controller.rb +0 -4
  175. data/app/helpers/routing_helpers.rb +0 -7
  176. data/app/models/audio.rb +0 -4
  177. data/app/models/package_asset.rb +0 -11
  178. data/app/models/video.rb +0 -8
  179. data/app/views/contexts/_audio.html.erb +0 -1
  180. data/app/views/contexts/_video.html.erb +0 -1
  181. data/app/views/layouts/transit.html.erb +0 -31
  182. data/app/views/transit/index/index.html.erb +0 -0
  183. data/lib/transit/helpers/controller_helpers.rb +0 -40
  184. data/lib/transit/helpers/model_helpers.rb +0 -26
  185. data/lib/transit/package.rb +0 -25
  186. data/lib/transit/package/base.rb +0 -49
@@ -0,0 +1,612 @@
1
+ /*
2
+ * jQuery UI Autocomplete 1.8.13
3
+ *
4
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5
+ * Dual licensed under the MIT or GPL Version 2 licenses.
6
+ * http://jquery.org/license
7
+ *
8
+ * http://docs.jquery.com/UI/Autocomplete
9
+ *
10
+ * Depends:
11
+ * jquery.ui.core.js
12
+ * jquery.ui.widget.js
13
+ * jquery.ui.position.js
14
+ */
15
+ (function( $, undefined ) {
16
+
17
+ // used to prevent race conditions with remote data sources
18
+ var requestIndex = 0;
19
+
20
+ $.widget( "ui.autocomplete", {
21
+ options: {
22
+ appendTo: "body",
23
+ autoFocus: false,
24
+ delay: 300,
25
+ minLength: 1,
26
+ position: {
27
+ my: "left top",
28
+ at: "left bottom",
29
+ collision: "none"
30
+ },
31
+ source: null
32
+ },
33
+
34
+ pending: 0,
35
+
36
+ _create: function() {
37
+ var self = this,
38
+ doc = this.element[ 0 ].ownerDocument,
39
+ suppressKeyPress;
40
+
41
+ this.element
42
+ .addClass( "ui-autocomplete-input" )
43
+ .attr( "autocomplete", "off" )
44
+ // TODO verify these actually work as intended
45
+ .attr({
46
+ role: "textbox",
47
+ "aria-autocomplete": "list",
48
+ "aria-haspopup": "true"
49
+ })
50
+ .bind( "keydown.autocomplete", function( event ) {
51
+ if ( self.options.disabled || self.element.attr( "readonly" ) ) {
52
+ return;
53
+ }
54
+
55
+ suppressKeyPress = false;
56
+ var keyCode = $.ui.keyCode;
57
+ switch( event.keyCode ) {
58
+ case keyCode.PAGE_UP:
59
+ self._move( "previousPage", event );
60
+ break;
61
+ case keyCode.PAGE_DOWN:
62
+ self._move( "nextPage", event );
63
+ break;
64
+ case keyCode.UP:
65
+ self._move( "previous", event );
66
+ // prevent moving cursor to beginning of text field in some browsers
67
+ event.preventDefault();
68
+ break;
69
+ case keyCode.DOWN:
70
+ self._move( "next", event );
71
+ // prevent moving cursor to end of text field in some browsers
72
+ event.preventDefault();
73
+ break;
74
+ case keyCode.ENTER:
75
+ case keyCode.NUMPAD_ENTER:
76
+ // when menu is open and has focus
77
+ if ( self.menu.active ) {
78
+ // #6055 - Opera still allows the keypress to occur
79
+ // which causes forms to submit
80
+ suppressKeyPress = true;
81
+ event.preventDefault();
82
+ }
83
+ //passthrough - ENTER and TAB both select the current element
84
+ case keyCode.TAB:
85
+ if ( !self.menu.active ) {
86
+ return;
87
+ }
88
+ self.menu.select( event );
89
+ break;
90
+ case keyCode.ESCAPE:
91
+ self.element.val( self.term );
92
+ self.close( event );
93
+ break;
94
+ default:
95
+ // keypress is triggered before the input value is changed
96
+ clearTimeout( self.searching );
97
+ self.searching = setTimeout(function() {
98
+ // only search if the value has changed
99
+ if ( self.term != self.element.val() ) {
100
+ self.selectedItem = null;
101
+ self.search( null, event );
102
+ }
103
+ }, self.options.delay );
104
+ break;
105
+ }
106
+ })
107
+ .bind( "keypress.autocomplete", function( event ) {
108
+ if ( suppressKeyPress ) {
109
+ suppressKeyPress = false;
110
+ event.preventDefault();
111
+ }
112
+ })
113
+ .bind( "focus.autocomplete", function() {
114
+ if ( self.options.disabled ) {
115
+ return;
116
+ }
117
+
118
+ self.selectedItem = null;
119
+ self.previous = self.element.val();
120
+ })
121
+ .bind( "blur.autocomplete", function( event ) {
122
+ if ( self.options.disabled ) {
123
+ return;
124
+ }
125
+
126
+ clearTimeout( self.searching );
127
+ // clicks on the menu (or a button to trigger a search) will cause a blur event
128
+ self.closing = setTimeout(function() {
129
+ self.close( event );
130
+ self._change( event );
131
+ }, 150 );
132
+ });
133
+ this._initSource();
134
+ this.response = function() {
135
+ return self._response.apply( self, arguments );
136
+ };
137
+ this.menu = $( "<ul></ul>" )
138
+ .addClass( "ui-autocomplete" )
139
+ .appendTo( $( this.options.appendTo || "body", doc )[0] )
140
+ // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
141
+ .mousedown(function( event ) {
142
+ // clicking on the scrollbar causes focus to shift to the body
143
+ // but we can't detect a mouseup or a click immediately afterward
144
+ // so we have to track the next mousedown and close the menu if
145
+ // the user clicks somewhere outside of the autocomplete
146
+ var menuElement = self.menu.element[ 0 ];
147
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
148
+ setTimeout(function() {
149
+ $( document ).one( 'mousedown', function( event ) {
150
+ if ( event.target !== self.element[ 0 ] &&
151
+ event.target !== menuElement &&
152
+ !$.ui.contains( menuElement, event.target ) ) {
153
+ self.close();
154
+ }
155
+ });
156
+ }, 1 );
157
+ }
158
+
159
+ // use another timeout to make sure the blur-event-handler on the input was already triggered
160
+ setTimeout(function() {
161
+ clearTimeout( self.closing );
162
+ }, 13);
163
+ })
164
+ .menu({
165
+ focus: function( event, ui ) {
166
+ var item = ui.item.data( "item.autocomplete" );
167
+ if ( false !== self._trigger( "focus", event, { item: item } ) ) {
168
+ // use value to match what will end up in the input, if it was a key event
169
+ if ( /^key/.test(event.originalEvent.type) ) {
170
+ self.element.val( item.value );
171
+ }
172
+ }
173
+ },
174
+ selected: function( event, ui ) {
175
+ var item = ui.item.data( "item.autocomplete" ),
176
+ previous = self.previous;
177
+
178
+ // only trigger when focus was lost (click on menu)
179
+ if ( self.element[0] !== doc.activeElement ) {
180
+ self.element.focus();
181
+ self.previous = previous;
182
+ // #6109 - IE triggers two focus events and the second
183
+ // is asynchronous, so we need to reset the previous
184
+ // term synchronously and asynchronously :-(
185
+ setTimeout(function() {
186
+ self.previous = previous;
187
+ self.selectedItem = item;
188
+ }, 1);
189
+ }
190
+
191
+ if ( false !== self._trigger( "select", event, { item: item } ) ) {
192
+ self.element.val( item.value );
193
+ }
194
+ // reset the term after the select event
195
+ // this allows custom select handling to work properly
196
+ self.term = self.element.val();
197
+
198
+ self.close( event );
199
+ self.selectedItem = item;
200
+ },
201
+ blur: function( event, ui ) {
202
+ // don't set the value of the text field if it's already correct
203
+ // this prevents moving the cursor unnecessarily
204
+ if ( self.menu.element.is(":visible") &&
205
+ ( self.element.val() !== self.term ) ) {
206
+ self.element.val( self.term );
207
+ }
208
+ }
209
+ })
210
+ .zIndex( this.element.zIndex() + 1 )
211
+ // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
212
+ .css({ top: 0, left: 0 })
213
+ .hide()
214
+ .data( "menu" );
215
+ if ( $.fn.bgiframe ) {
216
+ this.menu.element.bgiframe();
217
+ }
218
+ },
219
+
220
+ destroy: function() {
221
+ this.element
222
+ .removeClass( "ui-autocomplete-input" )
223
+ .removeAttr( "autocomplete" )
224
+ .removeAttr( "role" )
225
+ .removeAttr( "aria-autocomplete" )
226
+ .removeAttr( "aria-haspopup" );
227
+ this.menu.element.remove();
228
+ $.Widget.prototype.destroy.call( this );
229
+ },
230
+
231
+ _setOption: function( key, value ) {
232
+ $.Widget.prototype._setOption.apply( this, arguments );
233
+ if ( key === "source" ) {
234
+ this._initSource();
235
+ }
236
+ if ( key === "appendTo" ) {
237
+ this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
238
+ }
239
+ if ( key === "disabled" && value && this.xhr ) {
240
+ this.xhr.abort();
241
+ }
242
+ },
243
+
244
+ _initSource: function() {
245
+ var self = this,
246
+ array,
247
+ url;
248
+ if ( $.isArray(this.options.source) ) {
249
+ array = this.options.source;
250
+ this.source = function( request, response ) {
251
+ response( $.ui.autocomplete.filter(array, request.term) );
252
+ };
253
+ } else if ( typeof this.options.source === "string" ) {
254
+ url = this.options.source;
255
+ this.source = function( request, response ) {
256
+ if ( self.xhr ) {
257
+ self.xhr.abort();
258
+ }
259
+ self.xhr = $.ajax({
260
+ url: url,
261
+ data: request,
262
+ dataType: "json",
263
+ autocompleteRequest: ++requestIndex,
264
+ success: function( data, status ) {
265
+ if ( this.autocompleteRequest === requestIndex ) {
266
+ response( data );
267
+ }
268
+ },
269
+ error: function() {
270
+ if ( this.autocompleteRequest === requestIndex ) {
271
+ response( [] );
272
+ }
273
+ }
274
+ });
275
+ };
276
+ } else {
277
+ this.source = this.options.source;
278
+ }
279
+ },
280
+
281
+ search: function( value, event ) {
282
+ value = value != null ? value : this.element.val();
283
+
284
+ // always save the actual value, not the one passed as an argument
285
+ this.term = this.element.val();
286
+
287
+ if ( value.length < this.options.minLength ) {
288
+ return this.close( event );
289
+ }
290
+
291
+ clearTimeout( this.closing );
292
+ if ( this._trigger( "search", event ) === false ) {
293
+ return;
294
+ }
295
+
296
+ return this._search( value );
297
+ },
298
+
299
+ _search: function( value ) {
300
+ this.pending++;
301
+ this.element.addClass( "ui-autocomplete-loading" );
302
+
303
+ this.source( { term: value }, this.response );
304
+ },
305
+
306
+ _response: function( content ) {
307
+ if ( !this.options.disabled && content && content.length ) {
308
+ content = this._normalize( content );
309
+ this._suggest( content );
310
+ this._trigger( "open" );
311
+ } else {
312
+ this.close();
313
+ }
314
+ this.pending--;
315
+ if ( !this.pending ) {
316
+ this.element.removeClass( "ui-autocomplete-loading" );
317
+ }
318
+ },
319
+
320
+ close: function( event ) {
321
+ clearTimeout( this.closing );
322
+ if ( this.menu.element.is(":visible") ) {
323
+ this.menu.element.hide();
324
+ this.menu.deactivate();
325
+ this._trigger( "close", event );
326
+ }
327
+ },
328
+
329
+ _change: function( event ) {
330
+ if ( this.previous !== this.element.val() ) {
331
+ this._trigger( "change", event, { item: this.selectedItem } );
332
+ }
333
+ },
334
+
335
+ _normalize: function( items ) {
336
+ // assume all items have the right format when the first item is complete
337
+ if ( items.length && items[0].label && items[0].value ) {
338
+ return items;
339
+ }
340
+ return $.map( items, function(item) {
341
+ if ( typeof item === "string" ) {
342
+ return {
343
+ label: item,
344
+ value: item
345
+ };
346
+ }
347
+ return $.extend({
348
+ label: item.label || item.value,
349
+ value: item.value || item.label
350
+ }, item );
351
+ });
352
+ },
353
+
354
+ _suggest: function( items ) {
355
+ var ul = this.menu.element
356
+ .empty()
357
+ .zIndex( this.element.zIndex() + 1 );
358
+ this._renderMenu( ul, items );
359
+ // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
360
+ this.menu.deactivate();
361
+ this.menu.refresh();
362
+
363
+ // size and position menu
364
+ ul.show();
365
+ this._resizeMenu();
366
+ ul.position( $.extend({
367
+ of: this.element
368
+ }, this.options.position ));
369
+
370
+ if ( this.options.autoFocus ) {
371
+ this.menu.next( new $.Event("mouseover") );
372
+ }
373
+ },
374
+
375
+ _resizeMenu: function() {
376
+ var ul = this.menu.element;
377
+ ul.outerWidth( Math.max(
378
+ ul.width( "" ).outerWidth(),
379
+ this.element.outerWidth()
380
+ ) );
381
+ },
382
+
383
+ _renderMenu: function( ul, items ) {
384
+ var self = this;
385
+ $.each( items, function( index, item ) {
386
+ self._renderItem( ul, item );
387
+ });
388
+ },
389
+
390
+ _renderItem: function( ul, item) {
391
+ return $( "<li></li>" )
392
+ .data( "item.autocomplete", item )
393
+ .append( $( "<a></a>" ).text( item.label ) )
394
+ .appendTo( ul );
395
+ },
396
+
397
+ _move: function( direction, event ) {
398
+ if ( !this.menu.element.is(":visible") ) {
399
+ this.search( null, event );
400
+ return;
401
+ }
402
+ if ( this.menu.first() && /^previous/.test(direction) ||
403
+ this.menu.last() && /^next/.test(direction) ) {
404
+ this.element.val( this.term );
405
+ this.menu.deactivate();
406
+ return;
407
+ }
408
+ this.menu[ direction ]( event );
409
+ },
410
+
411
+ widget: function() {
412
+ return this.menu.element;
413
+ }
414
+ });
415
+
416
+ $.extend( $.ui.autocomplete, {
417
+ escapeRegex: function( value ) {
418
+ return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
419
+ },
420
+ filter: function(array, term) {
421
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
422
+ return $.grep( array, function(value) {
423
+ return matcher.test( value.label || value.value || value );
424
+ });
425
+ }
426
+ });
427
+
428
+ }( jQuery ));
429
+
430
+ /*
431
+ * jQuery UI Menu (not officially released)
432
+ *
433
+ * This widget isn't yet finished and the API is subject to change. We plan to finish
434
+ * it for the next release. You're welcome to give it a try anyway and give us feedback,
435
+ * as long as you're okay with migrating your code later on. We can help with that, too.
436
+ *
437
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
438
+ * Dual licensed under the MIT or GPL Version 2 licenses.
439
+ * http://jquery.org/license
440
+ *
441
+ * http://docs.jquery.com/UI/Menu
442
+ *
443
+ * Depends:
444
+ * jquery.ui.core.js
445
+ * jquery.ui.widget.js
446
+ */
447
+ (function($) {
448
+
449
+ $.widget("ui.menu", {
450
+ _create: function() {
451
+ var self = this;
452
+ this.element
453
+ .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
454
+ .attr({
455
+ role: "listbox",
456
+ "aria-activedescendant": "ui-active-menuitem"
457
+ })
458
+ .click(function( event ) {
459
+ if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
460
+ return;
461
+ }
462
+ // temporary
463
+ event.preventDefault();
464
+ self.select( event );
465
+ });
466
+ this.refresh();
467
+ },
468
+
469
+ refresh: function() {
470
+ var self = this;
471
+
472
+ // don't refresh list items that are already adapted
473
+ var items = this.element.children("li:not(.ui-menu-item):has(a)")
474
+ .addClass("ui-menu-item")
475
+ .attr("role", "menuitem");
476
+
477
+ items.children("a")
478
+ .addClass("ui-corner-all")
479
+ .attr("tabindex", -1)
480
+ // mouseenter doesn't work with event delegation
481
+ .mouseenter(function( event ) {
482
+ self.activate( event, $(this).parent() );
483
+ })
484
+ .mouseleave(function() {
485
+ self.deactivate();
486
+ });
487
+ },
488
+
489
+ activate: function( event, item ) {
490
+ this.deactivate();
491
+ if (this.hasScroll()) {
492
+ var offset = item.offset().top - this.element.offset().top,
493
+ scroll = this.element.scrollTop(),
494
+ elementHeight = this.element.height();
495
+ if (offset < 0) {
496
+ this.element.scrollTop( scroll + offset);
497
+ } else if (offset >= elementHeight) {
498
+ this.element.scrollTop( scroll + offset - elementHeight + item.height());
499
+ }
500
+ }
501
+ this.active = item.eq(0)
502
+ .children("a")
503
+ .addClass("ui-state-hover")
504
+ .attr("id", "ui-active-menuitem")
505
+ .end();
506
+ this._trigger("focus", event, { item: item });
507
+ },
508
+
509
+ deactivate: function() {
510
+ if (!this.active) { return; }
511
+
512
+ this.active.children("a")
513
+ .removeClass("ui-state-hover")
514
+ .removeAttr("id");
515
+ this._trigger("blur");
516
+ this.active = null;
517
+ },
518
+
519
+ next: function(event) {
520
+ this.move("next", ".ui-menu-item:first", event);
521
+ },
522
+
523
+ previous: function(event) {
524
+ this.move("prev", ".ui-menu-item:last", event);
525
+ },
526
+
527
+ first: function() {
528
+ return this.active && !this.active.prevAll(".ui-menu-item").length;
529
+ },
530
+
531
+ last: function() {
532
+ return this.active && !this.active.nextAll(".ui-menu-item").length;
533
+ },
534
+
535
+ move: function(direction, edge, event) {
536
+ if (!this.active) {
537
+ this.activate(event, this.element.children(edge));
538
+ return;
539
+ }
540
+ var next = this.active[direction + "All"](".ui-menu-item").eq(0);
541
+ if (next.length) {
542
+ this.activate(event, next);
543
+ } else {
544
+ this.activate(event, this.element.children(edge));
545
+ }
546
+ },
547
+
548
+ // TODO merge with previousPage
549
+ nextPage: function(event) {
550
+ if (this.hasScroll()) {
551
+ // TODO merge with no-scroll-else
552
+ if (!this.active || this.last()) {
553
+ this.activate(event, this.element.children(".ui-menu-item:first"));
554
+ return;
555
+ }
556
+ var base = this.active.offset().top,
557
+ height = this.element.height(),
558
+ result = this.element.children(".ui-menu-item").filter(function() {
559
+ var close = $(this).offset().top - base - height + $(this).height();
560
+ // TODO improve approximation
561
+ return close < 10 && close > -10;
562
+ });
563
+
564
+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
565
+ if (!result.length) {
566
+ result = this.element.children(".ui-menu-item:last");
567
+ }
568
+ this.activate(event, result);
569
+ } else {
570
+ this.activate(event, this.element.children(".ui-menu-item")
571
+ .filter(!this.active || this.last() ? ":first" : ":last"));
572
+ }
573
+ },
574
+
575
+ // TODO merge with nextPage
576
+ previousPage: function(event) {
577
+ if (this.hasScroll()) {
578
+ // TODO merge with no-scroll-else
579
+ if (!this.active || this.first()) {
580
+ this.activate(event, this.element.children(".ui-menu-item:last"));
581
+ return;
582
+ }
583
+
584
+ var base = this.active.offset().top,
585
+ height = this.element.height();
586
+ result = this.element.children(".ui-menu-item").filter(function() {
587
+ var close = $(this).offset().top - base + height - $(this).height();
588
+ // TODO improve approximation
589
+ return close < 10 && close > -10;
590
+ });
591
+
592
+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
593
+ if (!result.length) {
594
+ result = this.element.children(".ui-menu-item:first");
595
+ }
596
+ this.activate(event, result);
597
+ } else {
598
+ this.activate(event, this.element.children(".ui-menu-item")
599
+ .filter(!this.active || this.first() ? ":last" : ":first"));
600
+ }
601
+ },
602
+
603
+ hasScroll: function() {
604
+ return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight");
605
+ },
606
+
607
+ select: function( event ) {
608
+ this._trigger("selected", event, { item: this.active });
609
+ }
610
+ });
611
+
612
+ }(jQuery));