blacklight_range_limit 7.2.0 → 7.3.0

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/javascripts/blacklight_range_limit.js +7 -0
  4. data/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js +23 -11
  5. data/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js +83 -76
  6. data/app/assets/stylesheets/blacklight_range_limit/blacklight_range_limit.css +26 -1
  7. data/app/helpers/range_limit_helper.rb +3 -3
  8. data/app/views/blacklight_range_limit/_range_limit_panel.html.erb +30 -27
  9. data/app/views/blacklight_range_limit/_range_segments.html.erb +6 -6
  10. data/app/views/blacklight_range_limit/range_limit_panel.html.erb +10 -0
  11. data/config/locales/blacklight_range_limit.en.yml +7 -0
  12. data/lib/blacklight_range_limit.rb +2 -4
  13. data/lib/blacklight_range_limit/controller_override.rb +28 -0
  14. data/lib/blacklight_range_limit/routes.rb +1 -1
  15. data/lib/blacklight_range_limit/routes/range_searchable.rb +1 -0
  16. data/lib/blacklight_range_limit/view_helper_override.rb +0 -13
  17. data/spec/features/a_javascript_spec.rb +11 -4
  18. data/spec/spec_helper.rb +12 -1
  19. data/vendor/assets/javascripts/flot/jquery.canvaswrapper.js +550 -0
  20. data/vendor/assets/javascripts/flot/jquery.colorhelpers.js +199 -0
  21. data/vendor/assets/javascripts/flot/jquery.flot.browser.js +98 -0
  22. data/vendor/assets/javascripts/flot/jquery.flot.drawSeries.js +663 -0
  23. data/vendor/assets/javascripts/flot/jquery.flot.hover.js +360 -0
  24. data/vendor/assets/javascripts/flot/jquery.flot.js +1610 -1928
  25. data/vendor/assets/javascripts/flot/jquery.flot.saturated.js +43 -0
  26. data/vendor/assets/javascripts/flot/jquery.flot.selection.js +237 -68
  27. data/vendor/assets/javascripts/flot/jquery.flot.uiConstants.js +10 -0
  28. metadata +10 -3
  29. data/vendor/assets/javascripts/flot/excanvas.min.js +0 -1
@@ -0,0 +1,43 @@
1
+ (function ($) {
2
+ 'use strict';
3
+ var saturated = {
4
+ saturate: function (a) {
5
+ if (a === Infinity) {
6
+ return Number.MAX_VALUE;
7
+ }
8
+
9
+ if (a === -Infinity) {
10
+ return -Number.MAX_VALUE;
11
+ }
12
+
13
+ return a;
14
+ },
15
+ delta: function(min, max, noTicks) {
16
+ return ((max - min) / noTicks) === Infinity ? (max / noTicks - min / noTicks) : (max - min) / noTicks
17
+ },
18
+ multiply: function (a, b) {
19
+ return saturated.saturate(a * b);
20
+ },
21
+ // returns c * bInt * a. Beahves properly in the case where c is negative
22
+ // and bInt * a is bigger that Number.MAX_VALUE (Infinity)
23
+ multiplyAdd: function (a, bInt, c) {
24
+ if (isFinite(a * bInt)) {
25
+ return saturated.saturate(a * bInt + c);
26
+ } else {
27
+ var result = c;
28
+
29
+ for (var i = 0; i < bInt; i++) {
30
+ result += a;
31
+ }
32
+
33
+ return saturated.saturate(result);
34
+ }
35
+ },
36
+ // round to nearby lower multiple of base
37
+ floorInBase: function(n, base) {
38
+ return base * Math.floor(n / base);
39
+ }
40
+ };
41
+
42
+ $.plot.saturated = saturated;
43
+ })(jQuery);
@@ -1,15 +1,16 @@
1
1
  /* Flot plugin for selecting regions of a plot.
2
2
 
3
- Copyright (c) 2007-2013 IOLA and Ole Laursen.
3
+ Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
4
  Licensed under the MIT license.
5
5
 
6
6
  The plugin supports these options:
7
7
 
8
8
  selection: {
9
- mode: null or "x" or "y" or "xy",
10
- color: color,
11
- shape: "round" or "miter" or "bevel",
12
- minSize: number of pixels
9
+ mode: null or "x" or "y" or "xy" or "smart",
10
+ color: color,
11
+ shape: "round" or "miter" or "bevel",
12
+ visualization: "fill" or "focus",
13
+ minSize: number of pixels
13
14
  }
14
15
 
15
16
  Selection support is enabled by setting the mode to one of "x", "y" or "xy".
@@ -19,6 +20,12 @@ specified. "color" is color of the selection (if you need to change the color
19
20
  later on, you can get to it with plot.getOptions().selection.color). "shape"
20
21
  is the shape of the corners of the selection.
21
22
 
23
+ The way how the selection is visualized, can be changed by using the option
24
+ "visualization". Flot currently supports two modes: "focus" and "fill". The
25
+ option "focus" draws a colored bezel around the selected area while keeping
26
+ the selected area clear. The option "fill" highlights (i.e., fills) the
27
+ selected area with a colored highlight.
28
+
22
29
  "minSize" is the minimum size a selection can be in pixels. This value can
23
30
  be customized to determine the smallest size a selection can be and still
24
31
  have the selection rectangle be displayed. When customizing this value, the
@@ -33,11 +40,11 @@ When selection support is enabled, a "plotselected" event will be emitted on
33
40
  the DOM element you passed into the plot function. The event handler gets a
34
41
  parameter with the ranges selected on the axes, like this:
35
42
 
36
- placeholder.bind( "plotselected", function( event, ranges ) {
37
- alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
38
- // similar for yaxis - with multiple axes, the extra ones are in
39
- // x2axis, x3axis, ...
40
- });
43
+ placeholder.bind( "plotselected", function( event, ranges ) {
44
+ alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
45
+ // similar for yaxis - with multiple axes, the extra ones are in
46
+ // x2axis, x3axis, ...
47
+ });
41
48
 
42
49
  The "plotselected" event is only fired when the user has finished making the
43
50
  selection. A "plotselecting" event is fired during the process with the same
@@ -58,7 +65,7 @@ The plugin allso adds the following methods to the plot object:
58
65
  an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
59
66
  this:
60
67
 
61
- setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
68
+ setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
62
69
 
63
70
  setSelection will trigger the "plotselected" event when called. If you don't
64
71
  want that to happen, e.g. if you're inside a "plotselected" handler, pass
@@ -81,10 +88,14 @@ The plugin allso adds the following methods to the plot object:
81
88
  (function ($) {
82
89
  function init(plot) {
83
90
  var selection = {
84
- first: { x: -1, y: -1}, second: { x: -1, y: -1},
85
- show: false,
86
- active: false
87
- };
91
+ first: {x: -1, y: -1},
92
+ second: {x: -1, y: -1},
93
+ show: false,
94
+ currentMode: 'xy',
95
+ active: false
96
+ };
97
+
98
+ var SNAPPING_CONSTANT = $.plot.uiConstants.SNAPPING_CONSTANT;
88
99
 
89
100
  // FIXME: The drag handling implemented here should be
90
101
  // abstracted out, there's some similar code from a library in
@@ -94,19 +105,23 @@ The plugin allso adds the following methods to the plot object:
94
105
  var savedhandlers = {};
95
106
 
96
107
  var mouseUpHandler = null;
97
-
108
+
98
109
  function onMouseMove(e) {
99
110
  if (selection.active) {
100
111
  updateSelection(e);
101
-
112
+
102
113
  plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
103
114
  }
104
115
  }
105
116
 
106
117
  function onMouseDown(e) {
107
- if (e.which != 1) // only accept left-click
108
- return;
109
-
118
+ var o = plot.getOptions();
119
+ // only accept left-click
120
+ if (e.which !== 1 || o.selection.mode === null) return;
121
+
122
+ // reinitialize currentMode
123
+ selection.currentMode = 'xy';
124
+
110
125
  // cancel out any text selections
111
126
  document.body.focus();
112
127
 
@@ -127,26 +142,29 @@ The plugin allso adds the following methods to the plot object:
127
142
  // this is a bit silly, but we have to use a closure to be
128
143
  // able to whack the same handler again
129
144
  mouseUpHandler = function (e) { onMouseUp(e); };
130
-
145
+
131
146
  $(document).one("mouseup", mouseUpHandler);
132
147
  }
133
148
 
134
149
  function onMouseUp(e) {
135
150
  mouseUpHandler = null;
136
-
151
+
137
152
  // revert drag stuff for old-school browsers
138
- if (document.onselectstart !== undefined)
153
+ if (document.onselectstart !== undefined) {
139
154
  document.onselectstart = savedhandlers.onselectstart;
140
- if (document.ondrag !== undefined)
155
+ }
156
+
157
+ if (document.ondrag !== undefined) {
141
158
  document.ondrag = savedhandlers.ondrag;
159
+ }
142
160
 
143
161
  // no more dragging
144
162
  selection.active = false;
145
163
  updateSelection(e);
146
164
 
147
- if (selectionIsSane())
165
+ if (selectionIsSane()) {
148
166
  triggerSelectedEvent();
149
- else {
167
+ } else {
150
168
  // this counts as a clear
151
169
  plot.getPlaceholder().trigger("plotunselected", [ ]);
152
170
  plot.getPlaceholder().trigger("plotselecting", [ null ]);
@@ -156,15 +174,27 @@ The plugin allso adds the following methods to the plot object:
156
174
  }
157
175
 
158
176
  function getSelection() {
159
- if (!selectionIsSane())
160
- return null;
161
-
177
+ if (!selectionIsSane()) return null;
178
+
162
179
  if (!selection.show) return null;
163
180
 
164
- var r = {}, c1 = selection.first, c2 = selection.second;
181
+ var r = {},
182
+ c1 = {x: selection.first.x, y: selection.first.y},
183
+ c2 = {x: selection.second.x, y: selection.second.y};
184
+
185
+ if (selectionDirection(plot) === 'x') {
186
+ c1.y = 0;
187
+ c2.y = plot.height();
188
+ }
189
+
190
+ if (selectionDirection(plot) === 'y') {
191
+ c1.x = 0;
192
+ c2.x = plot.width();
193
+ }
194
+
165
195
  $.each(plot.getAxes(), function (name, axis) {
166
196
  if (axis.used) {
167
- var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
197
+ var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
168
198
  r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
169
199
  }
170
200
  });
@@ -177,47 +207,77 @@ The plugin allso adds the following methods to the plot object:
177
207
  plot.getPlaceholder().trigger("plotselected", [ r ]);
178
208
 
179
209
  // backwards-compat stuff, to be removed in future
180
- if (r.xaxis && r.yaxis)
210
+ if (r.xaxis && r.yaxis) {
181
211
  plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
212
+ }
182
213
  }
183
214
 
184
215
  function clamp(min, value, max) {
185
- return value < min ? min: (value > max ? max: value);
216
+ return value < min ? min : (value > max ? max : value);
186
217
  }
187
218
 
188
- function setSelectionPos(pos, e) {
219
+ function selectionDirection(plot) {
189
220
  var o = plot.getOptions();
221
+
222
+ if (o.selection.mode === 'smart') {
223
+ return selection.currentMode;
224
+ } else {
225
+ return o.selection.mode;
226
+ }
227
+ }
228
+
229
+ function updateMode(pos) {
230
+ if (selection.first) {
231
+ var delta = {
232
+ x: pos.x - selection.first.x,
233
+ y: pos.y - selection.first.y
234
+ };
235
+
236
+ if (Math.abs(delta.x) < SNAPPING_CONSTANT) {
237
+ selection.currentMode = 'y';
238
+ } else if (Math.abs(delta.y) < SNAPPING_CONSTANT) {
239
+ selection.currentMode = 'x';
240
+ } else {
241
+ selection.currentMode = 'xy';
242
+ }
243
+ }
244
+ }
245
+
246
+ function setSelectionPos(pos, e) {
190
247
  var offset = plot.getPlaceholder().offset();
191
248
  var plotOffset = plot.getPlotOffset();
192
249
  pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
193
250
  pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
194
251
 
195
- if (o.selection.mode == "y")
196
- pos.x = pos == selection.first ? 0 : plot.width();
252
+ if (pos !== selection.first) updateMode(pos);
197
253
 
198
- if (o.selection.mode == "x")
199
- pos.y = pos == selection.first ? 0 : plot.height();
254
+ if (selectionDirection(plot) === "y") {
255
+ pos.x = pos === selection.first ? 0 : plot.width();
256
+ }
257
+
258
+ if (selectionDirection(plot) === "x") {
259
+ pos.y = pos === selection.first ? 0 : plot.height();
260
+ }
200
261
  }
201
262
 
202
263
  function updateSelection(pos) {
203
- if (pos.pageX == null)
204
- return;
264
+ if (pos.pageX == null) return;
205
265
 
206
266
  setSelectionPos(selection.second, pos);
207
267
  if (selectionIsSane()) {
208
268
  selection.show = true;
209
269
  plot.triggerRedrawOverlay();
210
- }
211
- else
212
- clearSelection(true);
270
+ } else clearSelection(true);
213
271
  }
214
272
 
215
273
  function clearSelection(preventEvent) {
216
274
  if (selection.show) {
217
275
  selection.show = false;
276
+ selection.currentMode = '';
218
277
  plot.triggerRedrawOverlay();
219
- if (!preventEvent)
278
+ if (!preventEvent) {
220
279
  plot.getPlaceholder().trigger("plotunselected", [ ]);
280
+ }
221
281
  }
222
282
  }
223
283
 
@@ -227,10 +287,13 @@ The plugin allso adds the following methods to the plot object:
227
287
 
228
288
  for (var k in axes) {
229
289
  axis = axes[k];
230
- if (axis.direction == coord) {
290
+ if (axis.direction === coord) {
231
291
  key = coord + axis.n + "axis";
232
- if (!ranges[key] && axis.n == 1)
233
- key = coord + "axis"; // support x1axis as xaxis
292
+ if (!ranges[key] && axis.n === 1) {
293
+ // support x1axis as xaxis
294
+ key = coord + "axis";
295
+ }
296
+
234
297
  if (ranges[key]) {
235
298
  from = ranges[key].from;
236
299
  to = ranges[key].to;
@@ -241,7 +304,7 @@ The plugin allso adds the following methods to the plot object:
241
304
 
242
305
  // backwards-compat stuff - to be removed in future
243
306
  if (!ranges[key]) {
244
- axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
307
+ axis = coord === "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
245
308
  from = ranges[coord + "1"];
246
309
  to = ranges[coord + "2"];
247
310
  }
@@ -252,39 +315,36 @@ The plugin allso adds the following methods to the plot object:
252
315
  from = to;
253
316
  to = tmp;
254
317
  }
255
-
318
+
256
319
  return { from: from, to: to, axis: axis };
257
320
  }
258
-
321
+
259
322
  function setSelection(ranges, preventEvent) {
260
- var axis, range, o = plot.getOptions();
323
+ var range;
261
324
 
262
- if (o.selection.mode == "y") {
325
+ if (selectionDirection(plot) === "y") {
263
326
  selection.first.x = 0;
264
327
  selection.second.x = plot.width();
265
- }
266
- else {
328
+ } else {
267
329
  range = extractRange(ranges, "x");
268
-
269
330
  selection.first.x = range.axis.p2c(range.from);
270
331
  selection.second.x = range.axis.p2c(range.to);
271
332
  }
272
333
 
273
- if (o.selection.mode == "x") {
334
+ if (selectionDirection(plot) === "x") {
274
335
  selection.first.y = 0;
275
336
  selection.second.y = plot.height();
276
- }
277
- else {
337
+ } else {
278
338
  range = extractRange(ranges, "y");
279
-
280
339
  selection.first.y = range.axis.p2c(range.from);
281
340
  selection.second.y = range.axis.p2c(range.to);
282
341
  }
283
342
 
284
343
  selection.show = true;
285
344
  plot.triggerRedrawOverlay();
286
- if (!preventEvent && selectionIsSane())
345
+ if (!preventEvent && selectionIsSane()) {
287
346
  triggerSelectedEvent();
347
+ }
288
348
  }
289
349
 
290
350
  function selectionIsSane() {
@@ -305,6 +365,88 @@ The plugin allso adds the following methods to the plot object:
305
365
  }
306
366
  });
307
367
 
368
+ function drawSelectionDecorations(ctx, x, y, w, h, oX, oY, mode) {
369
+ var spacing = 3;
370
+ var fullEarWidth = 15;
371
+ var earWidth = Math.max(0, Math.min(fullEarWidth, w / 2 - 2, h / 2 - 2));
372
+ ctx.fillStyle = '#ffffff';
373
+
374
+ if (mode === 'xy') {
375
+ ctx.beginPath();
376
+ ctx.moveTo(x, y + earWidth);
377
+ ctx.lineTo(x - 3, y + earWidth);
378
+ ctx.lineTo(x - 3, y - 3);
379
+ ctx.lineTo(x + earWidth, y - 3);
380
+ ctx.lineTo(x + earWidth, y);
381
+ ctx.lineTo(x, y);
382
+ ctx.closePath();
383
+
384
+ ctx.moveTo(x, y + h - earWidth);
385
+ ctx.lineTo(x - 3, y + h - earWidth);
386
+ ctx.lineTo(x - 3, y + h + 3);
387
+ ctx.lineTo(x + earWidth, y + h + 3);
388
+ ctx.lineTo(x + earWidth, y + h);
389
+ ctx.lineTo(x, y + h);
390
+ ctx.closePath();
391
+
392
+ ctx.moveTo(x + w, y + earWidth);
393
+ ctx.lineTo(x + w + 3, y + earWidth);
394
+ ctx.lineTo(x + w + 3, y - 3);
395
+ ctx.lineTo(x + w - earWidth, y - 3);
396
+ ctx.lineTo(x + w - earWidth, y);
397
+ ctx.lineTo(x + w, y);
398
+ ctx.closePath();
399
+
400
+ ctx.moveTo(x + w, y + h - earWidth);
401
+ ctx.lineTo(x + w + 3, y + h - earWidth);
402
+ ctx.lineTo(x + w + 3, y + h + 3);
403
+ ctx.lineTo(x + w - earWidth, y + h + 3);
404
+ ctx.lineTo(x + w - earWidth, y + h);
405
+ ctx.lineTo(x + w, y + h);
406
+ ctx.closePath();
407
+
408
+ ctx.stroke();
409
+ ctx.fill();
410
+ }
411
+
412
+ x = oX;
413
+ y = oY;
414
+
415
+ if (mode === 'x') {
416
+ ctx.beginPath();
417
+ ctx.moveTo(x, y + fullEarWidth);
418
+ ctx.lineTo(x, y - fullEarWidth);
419
+ ctx.lineTo(x - spacing, y - fullEarWidth);
420
+ ctx.lineTo(x - spacing, y + fullEarWidth);
421
+ ctx.closePath();
422
+
423
+ ctx.moveTo(x + w, y + fullEarWidth);
424
+ ctx.lineTo(x + w, y - fullEarWidth);
425
+ ctx.lineTo(x + w + spacing, y - fullEarWidth);
426
+ ctx.lineTo(x + w + spacing, y + fullEarWidth);
427
+ ctx.closePath();
428
+ ctx.stroke();
429
+ ctx.fill();
430
+ }
431
+
432
+ if (mode === 'y') {
433
+ ctx.beginPath();
434
+
435
+ ctx.moveTo(x - fullEarWidth, y);
436
+ ctx.lineTo(x + fullEarWidth, y);
437
+ ctx.lineTo(x + fullEarWidth, y - spacing);
438
+ ctx.lineTo(x - fullEarWidth, y - spacing);
439
+ ctx.closePath();
440
+
441
+ ctx.moveTo(x - fullEarWidth, y + h);
442
+ ctx.lineTo(x + fullEarWidth, y + h);
443
+ ctx.lineTo(x + fullEarWidth, y + h + spacing);
444
+ ctx.lineTo(x - fullEarWidth, y + h + spacing);
445
+ ctx.closePath();
446
+ ctx.stroke();
447
+ ctx.fill();
448
+ }
449
+ }
308
450
 
309
451
  plot.hooks.drawOverlay.push(function (plot, ctx) {
310
452
  // draw selection
@@ -316,32 +458,58 @@ The plugin allso adds the following methods to the plot object:
316
458
  ctx.translate(plotOffset.left, plotOffset.top);
317
459
 
318
460
  var c = $.color.parse(o.selection.color);
461
+ var visualization = o.selection.visualization;
462
+
463
+ var scalingFactor = 1;
319
464
 
320
- ctx.strokeStyle = c.scale('a', 0.8).toString();
465
+ // use a dimmer scaling factor if visualization is "fill"
466
+ if (visualization === "fill") {
467
+ scalingFactor = 0.8;
468
+ }
469
+
470
+ ctx.strokeStyle = c.scale('a', scalingFactor).toString();
321
471
  ctx.lineWidth = 1;
322
472
  ctx.lineJoin = o.selection.shape;
323
473
  ctx.fillStyle = c.scale('a', 0.4).toString();
324
474
 
325
475
  var x = Math.min(selection.first.x, selection.second.x) + 0.5,
476
+ oX = x,
326
477
  y = Math.min(selection.first.y, selection.second.y) + 0.5,
478
+ oY = y,
327
479
  w = Math.abs(selection.second.x - selection.first.x) - 1,
328
480
  h = Math.abs(selection.second.y - selection.first.y) - 1;
329
481
 
330
- ctx.fillRect(x, y, w, h);
331
- ctx.strokeRect(x, y, w, h);
482
+ if (selectionDirection(plot) === 'x') {
483
+ h += y;
484
+ y = 0;
485
+ }
486
+
487
+ if (selectionDirection(plot) === 'y') {
488
+ w += x;
489
+ x = 0;
490
+ }
491
+
492
+ if (visualization === "fill") {
493
+ ctx.fillRect(x, y, w, h);
494
+ ctx.strokeRect(x, y, w, h);
495
+ } else {
496
+ ctx.fillRect(0, 0, plot.width(), plot.height());
497
+ ctx.clearRect(x, y, w, h);
498
+ drawSelectionDecorations(ctx, x, y, w, h, oX, oY, selectionDirection(plot));
499
+ }
332
500
 
333
501
  ctx.restore();
334
502
  }
335
503
  });
336
-
504
+
337
505
  plot.hooks.shutdown.push(function (plot, eventHolder) {
338
506
  eventHolder.unbind("mousemove", onMouseMove);
339
507
  eventHolder.unbind("mousedown", onMouseDown);
340
-
341
- if (mouseUpHandler)
508
+
509
+ if (mouseUpHandler) {
342
510
  $(document).unbind("mouseup", mouseUpHandler);
511
+ }
343
512
  });
344
-
345
513
  }
346
514
 
347
515
  $.plot.plugins.push({
@@ -349,7 +517,8 @@ The plugin allso adds the following methods to the plot object:
349
517
  options: {
350
518
  selection: {
351
519
  mode: null, // one of null, "x", "y" or "xy"
352
- color: "#e8cfac",
520
+ visualization: "focus", // "focus" or "fill"
521
+ color: "#888888",
353
522
  shape: "round", // one of "round", "miter", or "bevel"
354
523
  minSize: 5 // minimum number of pixels
355
524
  }