monocle-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }