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,50 @@
1
+ // STUBS - simple debug functions and polyfills to normalise client
2
+ // execution environments.
3
+
4
+
5
+ // A little console stub if not initialized in a console-equipped browser.
6
+ //
7
+ if (typeof window.console == "undefined") {
8
+ window.console = { messages: [] }
9
+ window.console.log = function (msg) {
10
+ this.messages.push(msg);
11
+ }
12
+ window.console.warn = window.console.log;
13
+ }
14
+
15
+
16
+ // A simple version of console.dir that works on iOS.
17
+ //
18
+ window.console.compatDir = function (obj) {
19
+ var stringify = function (o) {
20
+ var parts = [];
21
+ for (var x in o) {
22
+ parts.push(x + ": " + o[x]);
23
+ }
24
+ return parts.join(";\n");
25
+ }
26
+
27
+ var out = stringify(obj);
28
+ window.console.log(out);
29
+ return out;
30
+ }
31
+
32
+
33
+ // This is called by Monocle methods and practices that are no longer
34
+ // recommended and will soon be removed.
35
+ //
36
+ window.console.deprecation = function (msg) {
37
+ console.warn("[DEPRECATION]: "+msg);
38
+ if (typeof console.trace == "function") {
39
+ console.trace();
40
+ }
41
+ }
42
+
43
+
44
+ // A convenient alias for setTimeout that assumes 0 if no timeout is specified.
45
+ //
46
+ Monocle.defer = function (fn, time) {
47
+ if (typeof fn == "function") {
48
+ return setTimeout(fn, time || 0);
49
+ }
50
+ }
@@ -0,0 +1,59 @@
1
+ Monocle.Controls.Contents = function (reader) {
2
+
3
+ var API = { constructor: Monocle.Controls.Contents }
4
+ var k = API.constants = API.constructor;
5
+ var p = API.properties = {
6
+ reader: reader
7
+ }
8
+
9
+
10
+ function createControlElements() {
11
+ var div = reader.dom.make('div', 'controls_contents_container');
12
+ contentsForBook(div, reader.getBook());
13
+ return div;
14
+ }
15
+
16
+
17
+ function contentsForBook(div, book) {
18
+ while (div.hasChildNodes()) {
19
+ div.removeChild(div.firstChild);
20
+ }
21
+ var list = div.dom.append('ol', 'controls_contents_list');
22
+
23
+ var contents = book.properties.contents;
24
+ for (var i = 0; i < contents.length; ++i) {
25
+ chapterBuilder(list, contents[i], 0);
26
+ }
27
+ }
28
+
29
+
30
+ function chapterBuilder(list, chp, padLvl) {
31
+ var index = list.childNodes.length;
32
+ var li = list.dom.append('li', 'controls_contents_chapter', index);
33
+ var span = li.dom.append(
34
+ 'span',
35
+ 'controls_contents_chapterTitle',
36
+ index,
37
+ { html: chp.title }
38
+ );
39
+ span.style.paddingLeft = padLvl + "em";
40
+
41
+ var invoked = function () {
42
+ p.reader.skipToChapter(chp.src);
43
+ p.reader.hideControl(API);
44
+ }
45
+
46
+ Monocle.Events.listenForTap(li, invoked, 'controls_contents_chapter_active');
47
+
48
+ if (chp.children) {
49
+ for (var i = 0; i < chp.children.length; ++i) {
50
+ chapterBuilder(list, chp.children[i], padLvl + 1);
51
+ }
52
+ }
53
+ }
54
+
55
+
56
+ API.createControlElements = createControlElements;
57
+
58
+ return API;
59
+ }
@@ -0,0 +1,51 @@
1
+ Monocle.Controls.Magnifier = function (reader) {
2
+
3
+ var API = { constructor: Monocle.Controls.Magnifier }
4
+ var k = API.constants = API.constructor;
5
+ var p = API.properties = {
6
+ buttons: [],
7
+ magnified: false
8
+ }
9
+
10
+
11
+ function initialize() {
12
+ p.reader = reader;
13
+ }
14
+
15
+
16
+ function createControlElements(holder) {
17
+ var btn = holder.dom.make('div', 'controls_magnifier_button');
18
+ btn.smallA = btn.dom.append('span', 'controls_magnifier_a', { text: 'A' });
19
+ btn.largeA = btn.dom.append('span', 'controls_magnifier_A', { text: 'A' });
20
+ p.buttons.push(btn);
21
+ Monocle.Events.listenForTap(btn, toggleMagnification);
22
+ return btn;
23
+ }
24
+
25
+
26
+ function toggleMagnification(evt) {
27
+ var opacities;
28
+ p.magnified = !p.magnified;
29
+ if (p.magnified) {
30
+ opacities = [0.3, 1];
31
+ p.reader.formatting.setFontScale(k.MAGNIFICATION, true);
32
+ } else {
33
+ opacities = [1, 0.3];
34
+ p.reader.formatting.setFontScale(null, true);
35
+ }
36
+
37
+ for (var i = 0; i < p.buttons.length; i++) {
38
+ p.buttons[i].smallA.style.opacity = opacities[0];
39
+ p.buttons[i].largeA.style.opacity = opacities[1];
40
+ }
41
+ }
42
+
43
+ API.createControlElements = createControlElements;
44
+
45
+ initialize();
46
+
47
+ return API;
48
+ }
49
+
50
+
51
+ Monocle.Controls.Magnifier.MAGNIFICATION = 1.2;
@@ -0,0 +1,136 @@
1
+ // A panel is an invisible column of interactivity. When contact occurs
2
+ // (mousedown, touchstart), the panel expands to the full width of its
3
+ // container, to catch all interaction events and prevent them from hitting
4
+ // other things.
5
+ //
6
+ // Panels are used primarily to provide hit zones for page flipping
7
+ // interactions, but you can do whatever you like with them.
8
+ //
9
+ // After instantiating a panel and adding it to the reader as a control,
10
+ // you can call listenTo() with a hash of methods for any of 'start', 'move'
11
+ // 'end' and 'cancel'.
12
+ //
13
+ Monocle.Controls.Panel = function () {
14
+
15
+ var API = { constructor: Monocle.Controls.Panel }
16
+ var k = API.constants = API.constructor;
17
+ var p = API.properties = {
18
+ evtCallbacks: {}
19
+ }
20
+
21
+ function createControlElements(cntr) {
22
+ p.div = cntr.dom.make('div', k.CLS.panel);
23
+ p.div.dom.setStyles(k.DEFAULT_STYLES);
24
+ Monocle.Events.listenForContact(
25
+ p.div,
26
+ {
27
+ 'start': start,
28
+ 'move': move,
29
+ 'end': end,
30
+ 'cancel': cancel
31
+ },
32
+ { useCapture: false }
33
+ );
34
+ return p.div;
35
+ }
36
+
37
+
38
+ function setDirection(dir) {
39
+ p.direction = dir;
40
+ }
41
+
42
+
43
+ function listenTo(evtCallbacks) {
44
+ p.evtCallbacks = evtCallbacks;
45
+ }
46
+
47
+
48
+ function deafen() {
49
+ p.evtCallbacks = {}
50
+ }
51
+
52
+
53
+ function start(evt) {
54
+ p.contact = true;
55
+ evt.m.offsetX += p.div.offsetLeft;
56
+ evt.m.offsetY += p.div.offsetTop;
57
+ expand();
58
+ invoke('start', evt);
59
+ }
60
+
61
+
62
+ function move(evt) {
63
+ if (!p.contact) {
64
+ return;
65
+ }
66
+ invoke('move', evt);
67
+ }
68
+
69
+
70
+ function end(evt) {
71
+ if (!p.contact) {
72
+ return;
73
+ }
74
+ Monocle.Events.deafenForContact(p.div, p.listeners);
75
+ contract();
76
+ p.contact = false;
77
+ invoke('end', evt);
78
+ }
79
+
80
+
81
+ function cancel(evt) {
82
+ if (!p.contact) {
83
+ return;
84
+ }
85
+ Monocle.Events.deafenForContact(p.div, p.listeners);
86
+ contract();
87
+ p.contact = false;
88
+ invoke('cancel', evt);
89
+ }
90
+
91
+
92
+ function invoke(evtType, evt) {
93
+ if (p.evtCallbacks[evtType]) {
94
+ p.evtCallbacks[evtType](p.direction, evt.m.offsetX, evt.m.offsetY, API);
95
+ }
96
+ evt.preventDefault();
97
+ }
98
+
99
+
100
+ function expand() {
101
+ if (p.expanded) {
102
+ return;
103
+ }
104
+ p.div.dom.addClass(k.CLS.expanded);
105
+ p.expanded = true;
106
+ }
107
+
108
+
109
+ function contract(evt) {
110
+ if (!p.expanded) {
111
+ return;
112
+ }
113
+ p.div.dom.removeClass(k.CLS.expanded);
114
+ p.expanded = false;
115
+ }
116
+
117
+
118
+ API.createControlElements = createControlElements;
119
+ API.listenTo = listenTo;
120
+ API.deafen = deafen;
121
+ API.expand = expand;
122
+ API.contract = contract;
123
+ API.setDirection = setDirection;
124
+
125
+ return API;
126
+ }
127
+
128
+
129
+ Monocle.Controls.Panel.CLS = {
130
+ panel: 'panel',
131
+ expanded: 'controls_panel_expanded'
132
+ }
133
+ Monocle.Controls.Panel.DEFAULT_STYLES = {
134
+ position: 'absolute',
135
+ height: '100%'
136
+ }
@@ -0,0 +1,100 @@
1
+ Monocle.Controls.PlaceSaver = function (bookId) {
2
+
3
+ var API = { constructor: Monocle.Controls.PlaceSaver }
4
+ var k = API.constants = API.constructor;
5
+ var p = API.properties = {}
6
+
7
+
8
+ function initialize() {
9
+ applyToBook(bookId);
10
+ }
11
+
12
+
13
+ function assignToReader(reader) {
14
+ p.reader = reader;
15
+ p.reader.listen('monocle:turn', savePlaceToCookie);
16
+ }
17
+
18
+
19
+ function applyToBook(bookId) {
20
+ p.bkTitle = bookId.toLowerCase().replace(/[^a-z0-9]/g, '');
21
+ p.prefix = k.COOKIE_NAMESPACE + p.bkTitle + ".";
22
+ }
23
+
24
+
25
+ function setCookie(key, value, days) {
26
+ var expires = "";
27
+ if (days) {
28
+ var d = new Date();
29
+ d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
30
+ expires = "; expires="+d.toGMTString();
31
+ }
32
+ var path = "; path=/";
33
+ document.cookie = p.prefix + key + "=" + value + expires + path;
34
+ return value;
35
+ }
36
+
37
+
38
+ function getCookie(key) {
39
+ if (!document.cookie) {
40
+ return null;
41
+ }
42
+ var regex = new RegExp(p.prefix + key + "=(.+?)(;|$)");
43
+ var matches = document.cookie.match(regex);
44
+ if (matches) {
45
+ return matches[1];
46
+ } else {
47
+ return null;
48
+ }
49
+ }
50
+
51
+
52
+ function savePlaceToCookie() {
53
+ var place = p.reader.getPlace();
54
+ setCookie(
55
+ "component",
56
+ encodeURIComponent(place.componentId()),
57
+ k.COOKIE_EXPIRES_IN_DAYS
58
+ );
59
+ setCookie(
60
+ "percent",
61
+ place.percentageThrough(),
62
+ k.COOKIE_EXPIRES_IN_DAYS
63
+ );
64
+ }
65
+
66
+
67
+ function savedPlace() {
68
+ var locus = {
69
+ componentId: getCookie('component'),
70
+ percent: getCookie('percent')
71
+ }
72
+ if (locus.componentId && locus.percent) {
73
+ locus.componentId = decodeURIComponent(locus.componentId);
74
+ locus.percent = parseFloat(locus.percent);
75
+ return locus;
76
+ } else {
77
+ return null;
78
+ }
79
+ }
80
+
81
+
82
+ function restorePlace() {
83
+ var locus = savedPlace();
84
+ if (locus) {
85
+ p.reader.moveTo(locus);
86
+ }
87
+ }
88
+
89
+
90
+ API.assignToReader = assignToReader;
91
+ API.savedPlace = savedPlace;
92
+ API.restorePlace = restorePlace;
93
+
94
+ initialize();
95
+
96
+ return API;
97
+ }
98
+
99
+ Monocle.Controls.PlaceSaver.COOKIE_NAMESPACE = "monocle.controls.placesaver.";
100
+ Monocle.Controls.PlaceSaver.COOKIE_EXPIRES_IN_DAYS = 7; // Set to 0 for session-based expiry.
@@ -0,0 +1,140 @@
1
+ Monocle.Controls.Scrubber = function (reader) {
2
+
3
+ var API = { constructor: Monocle.Controls.Scrubber }
4
+ var k = API.constants = API.constructor;
5
+ var p = API.properties = {}
6
+
7
+
8
+ function initialize() {
9
+ p.reader = reader;
10
+ p.reader.listen('monocle:turn', updateNeedles);
11
+ updateNeedles();
12
+ }
13
+
14
+
15
+ function pixelToPlace(x, cntr) {
16
+ if (!p.componentIds) {
17
+ p.componentIds = p.reader.getBook().properties.componentIds;
18
+ p.componentWidth = 100 / p.componentIds.length;
19
+ }
20
+ var pc = (x / cntr.offsetWidth) * 100;
21
+ var cmpt = p.componentIds[Math.floor(pc / p.componentWidth)];
22
+ var cmptPc = ((pc % p.componentWidth) / p.componentWidth);
23
+ return { componentId: cmpt, percentageThrough: cmptPc };
24
+ }
25
+
26
+
27
+ function placeToPixel(place, cntr) {
28
+ if (!p.componentIds) {
29
+ p.componentIds = p.reader.getBook().properties.componentIds;
30
+ p.componentWidth = 100 / p.componentIds.length;
31
+ }
32
+ var componentIndex = p.componentIds.indexOf(place.componentId());
33
+ var pc = p.componentWidth * componentIndex;
34
+ pc += place.percentageThrough() * p.componentWidth;
35
+ return Math.round((pc / 100) * cntr.offsetWidth);
36
+ }
37
+
38
+
39
+ function updateNeedles() {
40
+ if (p.hidden || !p.reader.dom.find(k.CLS.container)) {
41
+ return;
42
+ }
43
+ var place = p.reader.getPlace();
44
+ var x = placeToPixel(place, p.reader.dom.find(k.CLS.container));
45
+ for (var i = 0, needle; needle = p.reader.dom.find(k.CLS.needle, i); ++i) {
46
+ setX(needle, x - needle.offsetWidth / 2);
47
+ p.reader.dom.find(k.CLS.trail, i).style.width = x + "px";
48
+ }
49
+ }
50
+
51
+
52
+ function setX(node, x) {
53
+ var cntr = p.reader.dom.find(k.CLS.container);
54
+ x = Math.min(cntr.offsetWidth - node.offsetWidth, x);
55
+ x = Math.max(x, 0);
56
+ Monocle.Styles.setX(node, x);
57
+ }
58
+
59
+
60
+ function createControlElements(holder) {
61
+ var cntr = holder.dom.make('div', k.CLS.container);
62
+ var track = cntr.dom.append('div', k.CLS.track);
63
+ var needleTrail = cntr.dom.append('div', k.CLS.trail);
64
+ var needle = cntr.dom.append('div', k.CLS.needle);
65
+ var bubble = cntr.dom.append('div', k.CLS.bubble);
66
+
67
+ var cntrListeners, bodyListeners;
68
+
69
+ var moveEvt = function (evt, x) {
70
+ evt.preventDefault();
71
+ x = (typeof x == "number") ? x : evt.m.registrantX;
72
+ var place = pixelToPlace(x, cntr);
73
+ setX(needle, x - needle.offsetWidth / 2);
74
+ var book = p.reader.getBook();
75
+ var chps = book.chaptersForComponent(place.componentId);
76
+ var cmptIndex = p.componentIds.indexOf(place.componentId);
77
+ var chp = chps[Math.floor(chps.length * place.percentageThrough)];
78
+ if (cmptIndex > -1 && book.properties.components[cmptIndex]) {
79
+ var actualPlace = Monocle.Place.FromPercentageThrough(
80
+ book.properties.components[cmptIndex],
81
+ place.percentageThrough
82
+ );
83
+ chp = actualPlace.chapterInfo() || chp;
84
+ }
85
+
86
+ if (chp) {
87
+ bubble.innerHTML = chp.title;
88
+ }
89
+ setX(bubble, x - bubble.offsetWidth / 2);
90
+
91
+ p.lastX = x;
92
+ return place;
93
+ }
94
+
95
+ var endEvt = function (evt) {
96
+ var place = moveEvt(evt, p.lastX);
97
+ p.reader.moveTo({
98
+ percent: place.percentageThrough,
99
+ componentId: place.componentId
100
+ });
101
+ Monocle.Events.deafenForContact(cntr, cntrListeners);
102
+ Monocle.Events.deafenForContact(document.body, bodyListeners);
103
+ bubble.style.display = "none";
104
+ }
105
+
106
+ var startFn = function (evt) {
107
+ evt.stopPropagation();
108
+ bubble.style.display = "block";
109
+ moveEvt(evt);
110
+ cntrListeners = Monocle.Events.listenForContact(
111
+ cntr,
112
+ { move: moveEvt }
113
+ );
114
+ bodyListeners = Monocle.Events.listenForContact(
115
+ document.body,
116
+ { end: endEvt }
117
+ );
118
+ }
119
+
120
+ Monocle.Events.listenForContact(cntr, { start: startFn });
121
+
122
+ return cntr;
123
+ }
124
+
125
+
126
+ API.createControlElements = createControlElements;
127
+ API.updateNeedles = updateNeedles;
128
+
129
+ initialize();
130
+
131
+ return API;
132
+ }
133
+
134
+ Monocle.Controls.Scrubber.CLS = {
135
+ container: 'controls_scrubber_container',
136
+ track: 'controls_scrubber_track',
137
+ needle: 'controls_scrubber_needle',
138
+ trail: 'controls_scrubber_trail',
139
+ bubble: 'controls_scrubber_bubble'
140
+ }