visualsearch-rails 0.0.1

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.
Files changed (41) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +4 -0
  3. data/Changelog.md +4 -0
  4. data/Gemfile +2 -0
  5. data/Rakefile +5 -0
  6. data/Readme.md +24 -0
  7. data/app/assets/css/icons.css +19 -0
  8. data/app/assets/css/reset.css +30 -0
  9. data/app/assets/css/workspace.css +290 -0
  10. data/app/assets/images/cancel_search.png +0 -0
  11. data/app/assets/images/search_glyph.png +0 -0
  12. data/app/assets/javascripts/backbone-0.9.10.js +1498 -0
  13. data/app/assets/javascripts/dependencies.js +14843 -0
  14. data/app/assets/javascripts/jquery.ui.autocomplete.js +614 -0
  15. data/app/assets/javascripts/jquery.ui.core.js +324 -0
  16. data/app/assets/javascripts/jquery.ui.datepicker.js +5 -0
  17. data/app/assets/javascripts/jquery.ui.menu.js +621 -0
  18. data/app/assets/javascripts/jquery.ui.position.js +497 -0
  19. data/app/assets/javascripts/jquery.ui.widget.js +521 -0
  20. data/app/assets/javascripts/underscore-1.4.3.js +1221 -0
  21. data/app/assets/javascripts/visualsearch/js/models/search_facets.js +67 -0
  22. data/app/assets/javascripts/visualsearch/js/models/search_query.js +70 -0
  23. data/app/assets/javascripts/visualsearch/js/templates/search_box.jst +8 -0
  24. data/app/assets/javascripts/visualsearch/js/templates/search_facet.jst +9 -0
  25. data/app/assets/javascripts/visualsearch/js/templates/search_input.jst +1 -0
  26. data/app/assets/javascripts/visualsearch/js/templates/templates.js +7 -0
  27. data/app/assets/javascripts/visualsearch/js/utils/backbone_extensions.js +17 -0
  28. data/app/assets/javascripts/visualsearch/js/utils/hotkeys.js +99 -0
  29. data/app/assets/javascripts/visualsearch/js/utils/inflector.js +21 -0
  30. data/app/assets/javascripts/visualsearch/js/utils/jquery_extensions.js +197 -0
  31. data/app/assets/javascripts/visualsearch/js/utils/search_parser.js +87 -0
  32. data/app/assets/javascripts/visualsearch/js/views/search_box.js +447 -0
  33. data/app/assets/javascripts/visualsearch/js/views/search_facet.js +444 -0
  34. data/app/assets/javascripts/visualsearch/js/views/search_input.js +409 -0
  35. data/app/assets/javascripts/visualsearch/js/visualsearch.js +77 -0
  36. data/lib/generators/visual_search_install.rb +30 -0
  37. data/lib/visualsearch-rails.rb +2 -0
  38. data/lib/visualsearch/rails.rb +6 -0
  39. data/lib/visualsearch/version.rb +3 -0
  40. data/visualsearch-rails.gemspec +26 -0
  41. metadata +165 -0
@@ -0,0 +1,497 @@
1
+ /*!
2
+ * jQuery UI Position 1.10.0
3
+ * http://jqueryui.com
4
+ *
5
+ * Copyright 2013 jQuery Foundation and other contributors
6
+ * Released under the MIT license.
7
+ * http://jquery.org/license
8
+ *
9
+ * http://api.jqueryui.com/position/
10
+ */
11
+ (function( $, undefined ) {
12
+
13
+ $.ui = $.ui || {};
14
+
15
+ var cachedScrollbarWidth,
16
+ max = Math.max,
17
+ abs = Math.abs,
18
+ round = Math.round,
19
+ rhorizontal = /left|center|right/,
20
+ rvertical = /top|center|bottom/,
21
+ roffset = /[\+\-]\d+%?/,
22
+ rposition = /^\w+/,
23
+ rpercent = /%$/,
24
+ _position = $.fn.position;
25
+
26
+ function getOffsets( offsets, width, height ) {
27
+ return [
28
+ parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
29
+ parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
30
+ ];
31
+ }
32
+
33
+ function parseCss( element, property ) {
34
+ return parseInt( $.css( element, property ), 10 ) || 0;
35
+ }
36
+
37
+ function getDimensions( elem ) {
38
+ var raw = elem[0];
39
+ if ( raw.nodeType === 9 ) {
40
+ return {
41
+ width: elem.width(),
42
+ height: elem.height(),
43
+ offset: { top: 0, left: 0 }
44
+ };
45
+ }
46
+ if ( $.isWindow( raw ) ) {
47
+ return {
48
+ width: elem.width(),
49
+ height: elem.height(),
50
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
51
+ };
52
+ }
53
+ if ( raw.preventDefault ) {
54
+ return {
55
+ width: 0,
56
+ height: 0,
57
+ offset: { top: raw.pageY, left: raw.pageX }
58
+ };
59
+ }
60
+ return {
61
+ width: elem.outerWidth(),
62
+ height: elem.outerHeight(),
63
+ offset: elem.offset()
64
+ };
65
+ }
66
+
67
+ $.position = {
68
+ scrollbarWidth: function() {
69
+ if ( cachedScrollbarWidth !== undefined ) {
70
+ return cachedScrollbarWidth;
71
+ }
72
+ var w1, w2,
73
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
74
+ innerDiv = div.children()[0];
75
+
76
+ $( "body" ).append( div );
77
+ w1 = innerDiv.offsetWidth;
78
+ div.css( "overflow", "scroll" );
79
+
80
+ w2 = innerDiv.offsetWidth;
81
+
82
+ if ( w1 === w2 ) {
83
+ w2 = div[0].clientWidth;
84
+ }
85
+
86
+ div.remove();
87
+
88
+ return (cachedScrollbarWidth = w1 - w2);
89
+ },
90
+ getScrollInfo: function( within ) {
91
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
92
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
93
+ hasOverflowX = overflowX === "scroll" ||
94
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
95
+ hasOverflowY = overflowY === "scroll" ||
96
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
97
+ return {
98
+ width: hasOverflowX ? $.position.scrollbarWidth() : 0,
99
+ height: hasOverflowY ? $.position.scrollbarWidth() : 0
100
+ };
101
+ },
102
+ getWithinInfo: function( element ) {
103
+ var withinElement = $( element || window ),
104
+ isWindow = $.isWindow( withinElement[0] );
105
+ return {
106
+ element: withinElement,
107
+ isWindow: isWindow,
108
+ offset: withinElement.offset() || { left: 0, top: 0 },
109
+ scrollLeft: withinElement.scrollLeft(),
110
+ scrollTop: withinElement.scrollTop(),
111
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
112
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
113
+ };
114
+ }
115
+ };
116
+
117
+ $.fn.position = function( options ) {
118
+ if ( !options || !options.of ) {
119
+ return _position.apply( this, arguments );
120
+ }
121
+
122
+ // make a copy, we don't want to modify arguments
123
+ options = $.extend( {}, options );
124
+
125
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
126
+ target = $( options.of ),
127
+ within = $.position.getWithinInfo( options.within ),
128
+ scrollInfo = $.position.getScrollInfo( within ),
129
+ collision = ( options.collision || "flip" ).split( " " ),
130
+ offsets = {};
131
+
132
+ dimensions = getDimensions( target );
133
+ if ( target[0].preventDefault ) {
134
+ // force left top to allow flipping
135
+ options.at = "left top";
136
+ }
137
+ targetWidth = dimensions.width;
138
+ targetHeight = dimensions.height;
139
+ targetOffset = dimensions.offset;
140
+ // clone to reuse original targetOffset later
141
+ basePosition = $.extend( {}, targetOffset );
142
+
143
+ // force my and at to have valid horizontal and vertical positions
144
+ // if a value is missing or invalid, it will be converted to center
145
+ $.each( [ "my", "at" ], function() {
146
+ var pos = ( options[ this ] || "" ).split( " " ),
147
+ horizontalOffset,
148
+ verticalOffset;
149
+
150
+ if ( pos.length === 1) {
151
+ pos = rhorizontal.test( pos[ 0 ] ) ?
152
+ pos.concat( [ "center" ] ) :
153
+ rvertical.test( pos[ 0 ] ) ?
154
+ [ "center" ].concat( pos ) :
155
+ [ "center", "center" ];
156
+ }
157
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
158
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
159
+
160
+ // calculate offsets
161
+ horizontalOffset = roffset.exec( pos[ 0 ] );
162
+ verticalOffset = roffset.exec( pos[ 1 ] );
163
+ offsets[ this ] = [
164
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
165
+ verticalOffset ? verticalOffset[ 0 ] : 0
166
+ ];
167
+
168
+ // reduce to just the positions without the offsets
169
+ options[ this ] = [
170
+ rposition.exec( pos[ 0 ] )[ 0 ],
171
+ rposition.exec( pos[ 1 ] )[ 0 ]
172
+ ];
173
+ });
174
+
175
+ // normalize collision option
176
+ if ( collision.length === 1 ) {
177
+ collision[ 1 ] = collision[ 0 ];
178
+ }
179
+
180
+ if ( options.at[ 0 ] === "right" ) {
181
+ basePosition.left += targetWidth;
182
+ } else if ( options.at[ 0 ] === "center" ) {
183
+ basePosition.left += targetWidth / 2;
184
+ }
185
+
186
+ if ( options.at[ 1 ] === "bottom" ) {
187
+ basePosition.top += targetHeight;
188
+ } else if ( options.at[ 1 ] === "center" ) {
189
+ basePosition.top += targetHeight / 2;
190
+ }
191
+
192
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
193
+ basePosition.left += atOffset[ 0 ];
194
+ basePosition.top += atOffset[ 1 ];
195
+
196
+ return this.each(function() {
197
+ var collisionPosition, using,
198
+ elem = $( this ),
199
+ elemWidth = elem.outerWidth(),
200
+ elemHeight = elem.outerHeight(),
201
+ marginLeft = parseCss( this, "marginLeft" ),
202
+ marginTop = parseCss( this, "marginTop" ),
203
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
204
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
205
+ position = $.extend( {}, basePosition ),
206
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
207
+
208
+ if ( options.my[ 0 ] === "right" ) {
209
+ position.left -= elemWidth;
210
+ } else if ( options.my[ 0 ] === "center" ) {
211
+ position.left -= elemWidth / 2;
212
+ }
213
+
214
+ if ( options.my[ 1 ] === "bottom" ) {
215
+ position.top -= elemHeight;
216
+ } else if ( options.my[ 1 ] === "center" ) {
217
+ position.top -= elemHeight / 2;
218
+ }
219
+
220
+ position.left += myOffset[ 0 ];
221
+ position.top += myOffset[ 1 ];
222
+
223
+ // if the browser doesn't support fractions, then round for consistent results
224
+ if ( !$.support.offsetFractions ) {
225
+ position.left = round( position.left );
226
+ position.top = round( position.top );
227
+ }
228
+
229
+ collisionPosition = {
230
+ marginLeft: marginLeft,
231
+ marginTop: marginTop
232
+ };
233
+
234
+ $.each( [ "left", "top" ], function( i, dir ) {
235
+ if ( $.ui.position[ collision[ i ] ] ) {
236
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
237
+ targetWidth: targetWidth,
238
+ targetHeight: targetHeight,
239
+ elemWidth: elemWidth,
240
+ elemHeight: elemHeight,
241
+ collisionPosition: collisionPosition,
242
+ collisionWidth: collisionWidth,
243
+ collisionHeight: collisionHeight,
244
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
245
+ my: options.my,
246
+ at: options.at,
247
+ within: within,
248
+ elem : elem
249
+ });
250
+ }
251
+ });
252
+
253
+ if ( options.using ) {
254
+ // adds feedback as second argument to using callback, if present
255
+ using = function( props ) {
256
+ var left = targetOffset.left - position.left,
257
+ right = left + targetWidth - elemWidth,
258
+ top = targetOffset.top - position.top,
259
+ bottom = top + targetHeight - elemHeight,
260
+ feedback = {
261
+ target: {
262
+ element: target,
263
+ left: targetOffset.left,
264
+ top: targetOffset.top,
265
+ width: targetWidth,
266
+ height: targetHeight
267
+ },
268
+ element: {
269
+ element: elem,
270
+ left: position.left,
271
+ top: position.top,
272
+ width: elemWidth,
273
+ height: elemHeight
274
+ },
275
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
276
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
277
+ };
278
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
279
+ feedback.horizontal = "center";
280
+ }
281
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
282
+ feedback.vertical = "middle";
283
+ }
284
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
285
+ feedback.important = "horizontal";
286
+ } else {
287
+ feedback.important = "vertical";
288
+ }
289
+ options.using.call( this, props, feedback );
290
+ };
291
+ }
292
+
293
+ elem.offset( $.extend( position, { using: using } ) );
294
+ });
295
+ };
296
+
297
+ $.ui.position = {
298
+ fit: {
299
+ left: function( position, data ) {
300
+ var within = data.within,
301
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
302
+ outerWidth = within.width,
303
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
304
+ overLeft = withinOffset - collisionPosLeft,
305
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
306
+ newOverRight;
307
+
308
+ // element is wider than within
309
+ if ( data.collisionWidth > outerWidth ) {
310
+ // element is initially over the left side of within
311
+ if ( overLeft > 0 && overRight <= 0 ) {
312
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
313
+ position.left += overLeft - newOverRight;
314
+ // element is initially over right side of within
315
+ } else if ( overRight > 0 && overLeft <= 0 ) {
316
+ position.left = withinOffset;
317
+ // element is initially over both left and right sides of within
318
+ } else {
319
+ if ( overLeft > overRight ) {
320
+ position.left = withinOffset + outerWidth - data.collisionWidth;
321
+ } else {
322
+ position.left = withinOffset;
323
+ }
324
+ }
325
+ // too far left -> align with left edge
326
+ } else if ( overLeft > 0 ) {
327
+ position.left += overLeft;
328
+ // too far right -> align with right edge
329
+ } else if ( overRight > 0 ) {
330
+ position.left -= overRight;
331
+ // adjust based on position and margin
332
+ } else {
333
+ position.left = max( position.left - collisionPosLeft, position.left );
334
+ }
335
+ },
336
+ top: function( position, data ) {
337
+ var within = data.within,
338
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
339
+ outerHeight = data.within.height,
340
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
341
+ overTop = withinOffset - collisionPosTop,
342
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
343
+ newOverBottom;
344
+
345
+ // element is taller than within
346
+ if ( data.collisionHeight > outerHeight ) {
347
+ // element is initially over the top of within
348
+ if ( overTop > 0 && overBottom <= 0 ) {
349
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
350
+ position.top += overTop - newOverBottom;
351
+ // element is initially over bottom of within
352
+ } else if ( overBottom > 0 && overTop <= 0 ) {
353
+ position.top = withinOffset;
354
+ // element is initially over both top and bottom of within
355
+ } else {
356
+ if ( overTop > overBottom ) {
357
+ position.top = withinOffset + outerHeight - data.collisionHeight;
358
+ } else {
359
+ position.top = withinOffset;
360
+ }
361
+ }
362
+ // too far up -> align with top
363
+ } else if ( overTop > 0 ) {
364
+ position.top += overTop;
365
+ // too far down -> align with bottom edge
366
+ } else if ( overBottom > 0 ) {
367
+ position.top -= overBottom;
368
+ // adjust based on position and margin
369
+ } else {
370
+ position.top = max( position.top - collisionPosTop, position.top );
371
+ }
372
+ }
373
+ },
374
+ flip: {
375
+ left: function( position, data ) {
376
+ var within = data.within,
377
+ withinOffset = within.offset.left + within.scrollLeft,
378
+ outerWidth = within.width,
379
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
380
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
381
+ overLeft = collisionPosLeft - offsetLeft,
382
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
383
+ myOffset = data.my[ 0 ] === "left" ?
384
+ -data.elemWidth :
385
+ data.my[ 0 ] === "right" ?
386
+ data.elemWidth :
387
+ 0,
388
+ atOffset = data.at[ 0 ] === "left" ?
389
+ data.targetWidth :
390
+ data.at[ 0 ] === "right" ?
391
+ -data.targetWidth :
392
+ 0,
393
+ offset = -2 * data.offset[ 0 ],
394
+ newOverRight,
395
+ newOverLeft;
396
+
397
+ if ( overLeft < 0 ) {
398
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
399
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
400
+ position.left += myOffset + atOffset + offset;
401
+ }
402
+ }
403
+ else if ( overRight > 0 ) {
404
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
405
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
406
+ position.left += myOffset + atOffset + offset;
407
+ }
408
+ }
409
+ },
410
+ top: function( position, data ) {
411
+ var within = data.within,
412
+ withinOffset = within.offset.top + within.scrollTop,
413
+ outerHeight = within.height,
414
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
415
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
416
+ overTop = collisionPosTop - offsetTop,
417
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
418
+ top = data.my[ 1 ] === "top",
419
+ myOffset = top ?
420
+ -data.elemHeight :
421
+ data.my[ 1 ] === "bottom" ?
422
+ data.elemHeight :
423
+ 0,
424
+ atOffset = data.at[ 1 ] === "top" ?
425
+ data.targetHeight :
426
+ data.at[ 1 ] === "bottom" ?
427
+ -data.targetHeight :
428
+ 0,
429
+ offset = -2 * data.offset[ 1 ],
430
+ newOverTop,
431
+ newOverBottom;
432
+ if ( overTop < 0 ) {
433
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
434
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
435
+ position.top += myOffset + atOffset + offset;
436
+ }
437
+ }
438
+ else if ( overBottom > 0 ) {
439
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
440
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
441
+ position.top += myOffset + atOffset + offset;
442
+ }
443
+ }
444
+ }
445
+ },
446
+ flipfit: {
447
+ left: function() {
448
+ $.ui.position.flip.left.apply( this, arguments );
449
+ $.ui.position.fit.left.apply( this, arguments );
450
+ },
451
+ top: function() {
452
+ $.ui.position.flip.top.apply( this, arguments );
453
+ $.ui.position.fit.top.apply( this, arguments );
454
+ }
455
+ }
456
+ };
457
+
458
+ // fraction support test
459
+ (function () {
460
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
461
+ body = document.getElementsByTagName( "body" )[ 0 ],
462
+ div = document.createElement( "div" );
463
+
464
+ //Create a "fake body" for testing based on method used in jQuery.support
465
+ testElement = document.createElement( body ? "div" : "body" );
466
+ testElementStyle = {
467
+ visibility: "hidden",
468
+ width: 0,
469
+ height: 0,
470
+ border: 0,
471
+ margin: 0,
472
+ background: "none"
473
+ };
474
+ if ( body ) {
475
+ $.extend( testElementStyle, {
476
+ position: "absolute",
477
+ left: "-1000px",
478
+ top: "-1000px"
479
+ });
480
+ }
481
+ for ( i in testElementStyle ) {
482
+ testElement.style[ i ] = testElementStyle[ i ];
483
+ }
484
+ testElement.appendChild( div );
485
+ testElementParent = body || document.documentElement;
486
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
487
+
488
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
489
+
490
+ offsetLeft = $( div ).offset().left;
491
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
492
+
493
+ testElement.innerHTML = "";
494
+ testElementParent.removeChild( testElement );
495
+ })();
496
+
497
+ }( jQuery ) );