monocle-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 (50) hide show
  1. data/.DS_Store +0 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/lib/monocle/rails.rb +8 -0
  8. data/lib/monocle/rails/version.rb +5 -0
  9. data/monocle-rails.gemspec +23 -0
  10. data/vendor/.DS_Store +0 -0
  11. data/vendor/assets/.DS_Store +0 -0
  12. data/vendor/assets/javascripts/.DS_Store +0 -0
  13. data/vendor/assets/javascripts/compat/browser.js +120 -0
  14. data/vendor/assets/javascripts/compat/css.js +145 -0
  15. data/vendor/assets/javascripts/compat/env.js +463 -0
  16. data/vendor/assets/javascripts/compat/gala.js +469 -0
  17. data/vendor/assets/javascripts/compat/stubs.js +50 -0
  18. data/vendor/assets/javascripts/controls/contents.js +59 -0
  19. data/vendor/assets/javascripts/controls/magnifier.js +51 -0
  20. data/vendor/assets/javascripts/controls/panel.js +136 -0
  21. data/vendor/assets/javascripts/controls/placesaver.js +100 -0
  22. data/vendor/assets/javascripts/controls/scrubber.js +140 -0
  23. data/vendor/assets/javascripts/controls/spinner.js +99 -0
  24. data/vendor/assets/javascripts/controls/stencil.js +410 -0
  25. data/vendor/assets/javascripts/core/billboard.js +120 -0
  26. data/vendor/assets/javascripts/core/book.js +467 -0
  27. data/vendor/assets/javascripts/core/bookdata.js +59 -0
  28. data/vendor/assets/javascripts/core/component.js +413 -0
  29. data/vendor/assets/javascripts/core/events.js +56 -0
  30. data/vendor/assets/javascripts/core/factory.js +194 -0
  31. data/vendor/assets/javascripts/core/formatting.js +317 -0
  32. data/vendor/assets/javascripts/core/monocle.js +16 -0
  33. data/vendor/assets/javascripts/core/place.js +210 -0
  34. data/vendor/assets/javascripts/core/reader.js +683 -0
  35. data/vendor/assets/javascripts/core/selection.js +158 -0
  36. data/vendor/assets/javascripts/core/styles.js +155 -0
  37. data/vendor/assets/javascripts/dimensions/columns.js +218 -0
  38. data/vendor/assets/javascripts/flippers/instant.js +78 -0
  39. data/vendor/assets/javascripts/flippers/scroller.js +128 -0
  40. data/vendor/assets/javascripts/flippers/slider.js +469 -0
  41. data/vendor/assets/javascripts/monocore.js +27 -0
  42. data/vendor/assets/javascripts/monoctrl.js +1 -0
  43. data/vendor/assets/javascripts/panels/eink.js +61 -0
  44. data/vendor/assets/javascripts/panels/imode.js +180 -0
  45. data/vendor/assets/javascripts/panels/magic.js +297 -0
  46. data/vendor/assets/javascripts/panels/marginal.js +50 -0
  47. data/vendor/assets/javascripts/panels/twopane.js +34 -0
  48. data/vendor/assets/stylesheets/monocore.css +194 -0
  49. data/vendor/assets/stylesheets/monoctrl.css +168 -0
  50. metadata +129 -0
@@ -0,0 +1,469 @@
1
+ Gala = {}
2
+
3
+
4
+ // Register an event listener.
5
+ //
6
+ Gala.listen = function (elem, evtType, fn, useCapture) {
7
+ elem = Gala.$(elem);
8
+ if (elem.addEventListener) {
9
+ elem.addEventListener(evtType, fn, useCapture || false);
10
+ } else if (elem.attachEvent) {
11
+ if (evtType.indexOf(':') < 1) {
12
+ elem.attachEvent('on'+evtType, fn);
13
+ } else {
14
+ var h = (Gala.IE_REGISTRATIONS[elem] = Gala.IE_REGISTRATIONS[elem] || {});
15
+ var a = (h[evtType] = h[evtType] || []);
16
+ a.push(fn);
17
+ }
18
+ }
19
+ }
20
+
21
+
22
+ // Remove an event listener.
23
+ //
24
+ Gala.deafen = function (elem, evtType, fn, useCapture) {
25
+ elem = Gala.$(elem);
26
+ if (elem.removeEventListener) {
27
+ elem.removeEventListener(evtType, fn, useCapture || false);
28
+ } else if (elem.detachEvent) {
29
+ if (evtType.indexOf(':') < 1) {
30
+ elem.detachEvent('on'+evtType, fn);
31
+ } else {
32
+ var h = (Gala.IE_REGISTRATIONS[elem] = Gala.IE_REGISTRATIONS[elem] || {});
33
+ var a = (h[evtType] = h[evtType] || []);
34
+ for (var i = 0, ii = a.length; i < ii; ++i) {
35
+ if (a[i] == fn) { a.splice(i, 1); }
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+
42
+ // Fire an event on the element.
43
+ //
44
+ // The data supplied to this function will be available in the event object in
45
+ // the 'm' property -- eg, alert(evt.m) --> 'foo'
46
+ //
47
+ Gala.dispatch = function (elem, evtType, data, cancelable) {
48
+ elem = Gala.$(elem);
49
+ var evt;
50
+ if (elem.dispatchEvent) {
51
+ evt = document.createEvent('Events');
52
+ evt.initEvent(evtType, false, cancelable || false);
53
+ evt.m = data;
54
+ return elem.dispatchEvent(evt);
55
+ } else if (elem.attachEvent && evtType.indexOf(':') >= 0) {
56
+ if (!Gala.IE_REGISTRATIONS[elem]) { return true; }
57
+ var evtHandlers = Gala.IE_REGISTRATIONS[elem][evtType];
58
+ if (!evtHandlers || evtHandlers.length < 1) { return true; }
59
+ evt = {
60
+ type: evtType,
61
+ currentTarget: elem,
62
+ target: elem,
63
+ m: data,
64
+ defaultPrevented: false,
65
+ preventDefault: function () { evt.defaultPrevented = true; }
66
+ }
67
+ var q, processQueue = Gala.IE_INVOCATION_QUEUE.length === 0;
68
+ for (var i = 0, ii = evtHandlers.length; i < ii; ++i) {
69
+ q = { elem: elem, evtType: evtType, handler: evtHandlers[i], evt: evt }
70
+ Gala.IE_INVOCATION_QUEUE.push(q);
71
+ }
72
+ if (processQueue) {
73
+ while (q = Gala.IE_INVOCATION_QUEUE.shift()) {
74
+ //console.log("IE EVT on %s: '%s' with data: %s", q.elem, q.evtType, q.evt.m);
75
+ q.handler(q.evt);
76
+ }
77
+ }
78
+ return !(cancelable && evt.defaultPrevented);
79
+ } else {
80
+ console.warn('[GALA] Cannot dispatch non-namespaced events: '+evtType);
81
+ return true;
82
+ }
83
+ }
84
+
85
+
86
+ // Prevents the browser-default action on an event and stops it from
87
+ // propagating up the DOM tree.
88
+ //
89
+ Gala.stop = function (evt) {
90
+ evt = evt || window.event;
91
+ if (evt.preventDefault) { evt.preventDefault(); }
92
+ if (evt.stopPropagation) { evt.stopPropagation(); }
93
+ evt.returnValue = false;
94
+ evt.cancelBubble = true;
95
+ return false;
96
+ }
97
+
98
+
99
+ // Add a group of listeners, which is just a hash of { evtType: callback, ... }
100
+ //
101
+ Gala.listenGroup = function (elem, listeners, useCapture) {
102
+ for (var evtType in listeners) {
103
+ Gala.listen(elem, evtType, listeners[evtType], useCapture || false);
104
+ }
105
+ }
106
+
107
+
108
+ // Remove a group of listeners.
109
+ //
110
+ Gala.deafenGroup = function (elem, listeners, useCapture) {
111
+ for (var evtType in listeners) {
112
+ Gala.deafen(elem, evtType, listeners[evtType], useCapture || false);
113
+ }
114
+ }
115
+
116
+
117
+ // Replace a group of listeners with another group, re-using the same
118
+ // 'listeners' object -- a common pattern.
119
+ //
120
+ Gala.replaceGroup = function (elem, listeners, newListeners, useCapture) {
121
+ Gala.deafenGroup(elem, listeners, useCapture || false);
122
+ for (var evtType in listeners) { delete listeners[evtType]; }
123
+ for (evtType in newListeners) { listeners[evtType] = newListeners[evtType]; }
124
+ Gala.listenGroup(elem, listeners, useCapture || false);
125
+ return listeners;
126
+ }
127
+
128
+
129
+ // Listen for a tap or a click event.
130
+ //
131
+ // Returns a 'listener' object that can be passed to Gala.deafenGroup().
132
+ //
133
+ // If 'tapClass' is undefined, it defaults to 'tapping'. If it is a blank
134
+ // string, no class is assigned.
135
+ //
136
+ Gala.onTap = function (elem, fn, tapClass) {
137
+ elem = Gala.$(elem);
138
+ // Throttle the invocation to prevent double firing of the event in envs
139
+ // that support touch and mouse. Particularly in Firefox and Chrome on IE 8,
140
+ // a mouse event and touch events are both fired.
141
+ // Ref https://github.com/joseph/Monocle/pull/216#issuecomment-21424427
142
+ fn = Gala.throttle(fn, 100);
143
+
144
+ if (typeof tapClass == 'undefined') { tapClass = Gala.TAPPING_CLASS; }
145
+
146
+ var tapStartingCoords = {};
147
+
148
+ // If the tap extends beyond a few pixels, it's no longer a tap.
149
+ var tapIsValid = function (evt) {
150
+ var cur = Gala.Cursor(evt);
151
+ var xDelta = Math.abs(cur.pageX - tapStartingCoords.x);
152
+ var yDelta = Math.abs(cur.pageY - tapStartingCoords.y);
153
+ var maxContact = Math.max(xDelta, yDelta);
154
+ return Gala.TAP_MAX_CONTACT_DISTANCE >= maxContact;
155
+ }
156
+
157
+ // This ensures the element is considered 'clickable' by browsers
158
+ // like on the Kindle 3.
159
+ var noopOnClick = function (listeners) {
160
+ Gala.listen(elem, 'click', listeners.click = fns.noop);
161
+ }
162
+
163
+ var fns = {
164
+ start: function (evt) {
165
+ var cur = Gala.Cursor(evt);
166
+ tapStartingCoords = { x: cur.pageX, y: cur.pageY };
167
+ if (tapClass) { elem.classList.add(tapClass); }
168
+ },
169
+ move: function (evt) {
170
+ if (!tapStartingCoords) { return; }
171
+ if (!tapIsValid(evt)) { fns.cancel(evt); }
172
+ },
173
+ end: function (evt) {
174
+ if (!tapStartingCoords) { return; }
175
+ fns.cancel(evt);
176
+ evt.currentTarget = evt.currentTarget || evt.srcElement;
177
+ fn(evt);
178
+ },
179
+ noop: function () {},
180
+ cancel: function () {
181
+ if (!tapStartingCoords) { return; }
182
+ tapStartingCoords = null;
183
+ if (tapClass) { elem.classList.remove(tapClass); }
184
+ }
185
+ };
186
+ Gala.listen(window, Gala.CONTACT_CANCEL, fns.cancel);
187
+ return Gala.onContact(elem, fns, false, noopOnClick);
188
+ }
189
+
190
+
191
+ // Register a series of functions to listen for the start, move, end
192
+ // events of a mouse or touch interaction.
193
+ //
194
+ // 'fns' argument is an object like:
195
+ //
196
+ // {
197
+ // 'start': function () { ... },
198
+ // 'move': function () { ... },
199
+ // 'end': function () { ... },
200
+ // 'cancel': function () { ... }
201
+ // }
202
+ //
203
+ // All of the functions in this object are optional.
204
+ //
205
+ // Returns an object that can later be passed to Gala.deafenGroup.
206
+ //
207
+ Gala.onContact = function (elem, fns, useCapture, initCallback) {
208
+ elem = Gala.$(elem);
209
+
210
+ var isLeftClick = function (evt) {
211
+ return evt[typeof evt.which == 'undefined' ? 'button' : 'which'] < 2;
212
+ }
213
+
214
+ var isSingleTouch = function (evt) {
215
+ return !!(evt.touches && evt.touches.length < 2);
216
+ }
217
+
218
+ var wrapContact = function (fn) {
219
+ return function (evt) {
220
+ if (Gala.Pointers.enabled()) { Gala.Pointers.trackPointers(evt); }
221
+ var doCallFunc = (Gala.Pointers.isSinglePointer() ||
222
+ isSingleTouch(evt) ||
223
+ isLeftClick(evt));
224
+ if (doCallFunc) { fn(evt); }
225
+ }
226
+ }
227
+
228
+ var buildListeners = function (opts) {
229
+ var types = Gala.getEventTypes();
230
+
231
+ var listeners = {};
232
+ var evtTypes = ['start', 'move', 'end', 'cancel'];
233
+ for (var i = 0, ii = evtTypes.length; i < ii; ++i) {
234
+ var type = evtTypes[i];
235
+ if (opts[type]) {
236
+ var thisEvtTypes = types[type].split(' ');
237
+ for (var j = 0, jj = thisEvtTypes.length; j < jj; ++j) {
238
+ listeners[thisEvtTypes[j]] = wrapContact(opts[type]);
239
+ }
240
+ }
241
+ }
242
+ return listeners;
243
+ }
244
+
245
+ var listeners = buildListeners(fns);
246
+
247
+ Gala.listenGroup(elem, listeners);
248
+ if (typeof initCallback == 'function') { initCallback(listeners); }
249
+ return listeners;
250
+ }
251
+
252
+ // Support for pointer events
253
+ // http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx
254
+ // http://www.w3.org/Submission/pointer-events/
255
+ // Primary target of this functionality is windows 8, surface, etc
256
+ //
257
+ Gala.Pointers = {
258
+ pointers: {},
259
+
260
+
261
+ enabled: function () { return Gala.Pointers.ENV.pointer },
262
+
263
+ // Track pointer events
264
+ //
265
+ trackPointers: function (evt) {
266
+ var types = Gala.getEventTypes(),
267
+ endEvents = types.end.slice().concat(types.cancel);
268
+
269
+ // if we have an end event, I'm not sure it makes sense to only clear the
270
+ // single pointer that sent the end event. I think it makes sense to
271
+ // clear all pointers...I think it's kind of an edge case.
272
+ if (endEvents.indexOf(evt.type)) {
273
+ this.reset();
274
+ } else {
275
+ this.pointers[evt.pointerId] = evt;
276
+ }
277
+ },
278
+
279
+
280
+ // This follows the same logic as touches. To be valid, there
281
+ // is less than two.
282
+ //
283
+ isSinglePointer: function () {
284
+ return !!(this.enabled() && this.count() < 2);
285
+ },
286
+
287
+
288
+ // Get count of currently tracked pointers
289
+ //
290
+ count: function () {
291
+ // This method only exists in IE > 8 but that's ok because this code only
292
+ // applies to versions of IE > 8;
293
+ return Object.keys ? Object.keys(this.pointers).length : 0;
294
+ },
295
+
296
+
297
+ // Reset the pointers
298
+ //
299
+ reset: function () {
300
+ this.pointers = {};
301
+ }
302
+ }
303
+
304
+ Gala.Pointers.ENV = {
305
+ // Is the Pointer Events specification implemented?
306
+ // http://www.w3.org/Submission/pointer-events/
307
+ // Not sure how I feel about this spec but it makes sense to unify
308
+ // the events into a single interface to be used as needed. - DS
309
+ //
310
+ pointer: (function () {
311
+ return !!(navigator.pointerEnabled || navigator.msPointerEnabled)
312
+ })(),
313
+
314
+
315
+ // Does the system support a mouse
316
+ // This is required to identify touch devices that do not support
317
+ // a mouse interface. This is used because mouse events are still fired
318
+ // from mobile devices.
319
+ //
320
+ // This may need updated when Android desktops come out but hopefully
321
+ // everyone will just adopt the pointer spec.
322
+ //
323
+ noMouse: (function () {
324
+ var mobileRegex = /mobile|tablet|ip(ad|hone|od)|android|silk/i;
325
+ return (
326
+ ('ontouchstart' in window) &&
327
+ !!navigator.userAgent.match(mobileRegex)
328
+ );
329
+ })()
330
+ }
331
+
332
+ // Get Event Types that are used to bind the different event concepts
333
+ // start, move, end, cancel. This method helps normalize event binding and
334
+ // prevent improper event listening, etc
335
+ //
336
+ Gala.getEventTypes = function () {
337
+ var types;
338
+
339
+ if (Gala.Pointers.enabled()) {
340
+ // Microsoft screwing stuff up with pointers
341
+ // http://www.w3.org/TR/pointerevents/
342
+ types = [
343
+ 'pointerdown MSPointerDown',
344
+ 'pointermove MSPointerMove',
345
+ 'pointerup MSPointerUp',
346
+ 'pointercancel MSPointerCancel'
347
+ ];
348
+ } else if (Gala.Pointers.ENV.noMouse) {
349
+ types = [
350
+ 'touchstart',
351
+ 'touchmove',
352
+ 'touchend',
353
+ 'touchcancel'
354
+ ];
355
+ } else {
356
+ types = [
357
+ 'touchstart mousedown',
358
+ 'touchmove mousemove',
359
+ 'touchend mouseup',
360
+ 'touchcancel'
361
+ ];
362
+ }
363
+
364
+ return {
365
+ start: types[0],
366
+ move: types[1],
367
+ end: types[2],
368
+ cancel: types[3]
369
+ };
370
+ }
371
+
372
+
373
+ // The Gala.Cursor object provides more detail coordinates for the contact
374
+ // event, and normalizes differences between touch and mouse coordinates.
375
+ //
376
+ // If you have a contact event listener, you can get the coordinates for it
377
+ // with:
378
+ //
379
+ // var cursor = new Gala.Cursor(evt);
380
+ //
381
+ Gala.Cursor = function (evt) {
382
+ var API = { constructor: Gala.Cursor }
383
+
384
+
385
+ function initialize() {
386
+ var ci =
387
+ evt.type.match(/mouse|pointer/i) ? evt :
388
+ ['touchstart', 'touchmove'].indexOf(evt.type) >= 0 ? evt.targetTouches[0] :
389
+ ['touchend', 'touchcancel'].indexOf(evt.type) >= 0 ? evt.changedTouches[0] :
390
+ null;
391
+
392
+ // Basic coordinates (provided by the event).
393
+ API.pageX = ci.pageX;
394
+ API.pageY = ci.pageY;
395
+ API.clientX = ci.clientX;
396
+ API.clientY = ci.clientY;
397
+ API.screenX = ci.screenX;
398
+ API.screenY = ci.screenY;
399
+ API.event = evt;
400
+
401
+ // Coordinates relative to the target element for the event.
402
+ var tgt = API.target = evt.target || evt.srcElement;
403
+ while (tgt.nodeType != 1 && tgt.parentNode) { tgt = tgt.parentNode; }
404
+ assignOffsetFor(tgt, 'offset');
405
+
406
+ // Coordinates relative to the element that the event was registered on.
407
+ var registrant = evt.currentTarget;
408
+ if (registrant && typeof registrant.offsetLeft != 'undefined') {
409
+ assignOffsetFor(registrant, 'registrant');
410
+ }
411
+ }
412
+
413
+
414
+ function assignOffsetFor(elem, attr) {
415
+ var r;
416
+ if (elem.getBoundingClientRect) {
417
+ var er = elem.getBoundingClientRect();
418
+ var dr = document.documentElement.getBoundingClientRect();
419
+ r = { left: er.left - dr.left, top: er.top - dr.top }
420
+ } else {
421
+ r = { left: elem.offsetLeft, top: elem.offsetTop }
422
+ while (elem = elem.offsetParent) {
423
+ if (elem.offsetLeft || elem.offsetTop) {
424
+ r.left += elem.offsetLeft;
425
+ r.top += elem.offsetTop;
426
+ }
427
+ }
428
+ }
429
+ API[attr+'X'] = API.pageX - r.left;
430
+ API[attr+'Y'] = API.pageY - r.top;
431
+ }
432
+
433
+
434
+ initialize();
435
+
436
+ return API;
437
+ }
438
+
439
+
440
+ // A little utility to dereference ids into elements. You've seen this before.
441
+ //
442
+ Gala.$ = function (elem) {
443
+ if (typeof elem == 'string') { elem = document.getElementById(elem); }
444
+ return elem;
445
+ }
446
+
447
+ Gala.throttle = function (func, wait) {
448
+ var previous = 0;
449
+
450
+ return function () {
451
+ var now = new Date();
452
+ var remaining = wait - (now - previous);
453
+ if (remaining <= 0) {
454
+ previous = now;
455
+ func.apply(this, arguments);
456
+ }
457
+ }
458
+ }
459
+
460
+
461
+
462
+
463
+ // CONSTANTS
464
+ //
465
+ Gala.TAPPING_CLASS = 'tapping';
466
+ Gala.IE_REGISTRATIONS = {};
467
+ Gala.IE_INVOCATION_QUEUE = [];
468
+ Gala.CONTACT_CANCEL = "gala:contact:cancel";
469
+ Gala.TAP_MAX_CONTACT_DISTANCE = 10;