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,158 @@
1
+ Monocle.Selection = function (reader) {
2
+ var API = { constructor: Monocle.Selection };
3
+ var k = API.constants = API.constructor;
4
+ var p = API.properties = {
5
+ reader: reader,
6
+ lastSelection: []
7
+ };
8
+
9
+
10
+ function initialize() {
11
+ if (k.SELECTION_POLLING_INTERVAL) {
12
+ setInterval(pollSelection, k.SELECTION_POLLING_INTERVAL);
13
+ }
14
+ }
15
+
16
+
17
+ function pollSelection() {
18
+ var index = 0, frame = null;
19
+ while (frame = reader.dom.find('component', index++)) {
20
+ if (frame.contentWindow) {
21
+ pollSelectionOnWindow(frame.contentWindow, index);
22
+ }
23
+ }
24
+ }
25
+
26
+
27
+ function pollSelectionOnWindow(win, index) {
28
+ var sel = win.getSelection();
29
+ if (!sel) { return; }
30
+ var lm = p.lastSelection[index] || {};
31
+ var nm = p.lastSelection[index] = {
32
+ selected: anythingSelected(win),
33
+ range: sel.rangeCount ? sel.getRangeAt(0) : null,
34
+ string: sel.toString()
35
+ };
36
+ if (nm.selected) {
37
+ nm.rangeStartContainer = nm.range.startContainer;
38
+ nm.rangeEndContainer = nm.range.endContainer;
39
+ nm.rangeStartOffset = nm.range.startOffset;
40
+ nm.rangeEndOffset = nm.range.endOffset;
41
+ if (!sameRange(nm, lm)) {
42
+ p.reader.dispatchEvent('monocle:selection', nm);
43
+ }
44
+ } else if (lm.selected) {
45
+ p.reader.dispatchEvent('monocle:deselection', lm);
46
+ }
47
+ }
48
+
49
+
50
+ function sameRange(m1, m2) {
51
+ return (
52
+ m1.rangeStartContainer == m2.rangeStartContainer &&
53
+ m1.rangeEndContainer == m2.rangeEndContainer &&
54
+ m1.rangeStartOffset == m2.rangeStartOffset &&
55
+ m1.rangeEndOffset == m2.rangeEndOffset
56
+ );
57
+ }
58
+
59
+
60
+ // Given a window object, remove any user selections within. Trivial in
61
+ // most browsers, but involving major mojo on iOS.
62
+ //
63
+ function deselect() {
64
+ var index = 0, frame = null;
65
+ while (frame = reader.dom.find('component', index++)) {
66
+ deselectOnWindow(frame.contentWindow);
67
+ }
68
+ }
69
+
70
+
71
+ function deselectOnWindow(win) {
72
+ win = win || window;
73
+ if (!anythingSelected(win)) { return; }
74
+
75
+ if (Monocle.Browser.iOSVersion && !Monocle.Browser.iOSVersionBelow(5)) {
76
+ preservingScale(function () {
77
+ preservingScrollPosition(function () {
78
+ var inp = document.createElement('input');
79
+ inp.style.cssText = [
80
+ 'position: absolute',
81
+ 'top: 0',
82
+ 'left: 0',
83
+ 'width: 0',
84
+ 'height: 0'
85
+ ].join(';');
86
+ document.body.appendChild(inp);
87
+ inp.focus();
88
+ document.body.removeChild(inp);
89
+ })
90
+ });
91
+ }
92
+
93
+ var sel = win.getSelection();
94
+ sel.removeAllRanges();
95
+ win.document.body.scrollLeft = 0;
96
+ win.document.body.scrollTop = 0;
97
+ }
98
+
99
+
100
+ function preservingScrollPosition(fn) {
101
+ var sx = window.scrollX, sy = window.scrollY;
102
+ fn();
103
+ window.scrollTo(sx, sy);
104
+ }
105
+
106
+
107
+ function preservingScale(fn) {
108
+ var head = document.querySelector('head');
109
+ var ovp = head.querySelector('meta[name=viewport]');
110
+ var createViewportMeta = function (content) {
111
+ var elem = document.createElement('meta');
112
+ elem.setAttribute('name', 'viewport');
113
+ elem.setAttribute('content', content);
114
+ head.appendChild(elem);
115
+ return elem;
116
+ }
117
+
118
+ var nvp;
119
+ if (ovp) {
120
+ var ovpcontent = ovp.getAttribute('content');
121
+ var re = /user-scalable\s*=\s*([^,$\s])*/;
122
+ var result = ovpcontent.match(re);
123
+ if (result && ['no', '0'].indexOf(result[1]) >= 0) {
124
+ fn();
125
+ } else {
126
+ var nvpcontent = ovpcontent.replace(re, '');
127
+ nvpcontent += nvpcontent ? ', ' : '';
128
+ nvpcontent += 'user-scalable=no';
129
+ head.removeChild(ovp);
130
+ nvp = createViewportMeta(nvpcontent);
131
+ fn();
132
+ head.removeChild(nvp);
133
+ head.appendChild(ovp);
134
+ }
135
+ } else {
136
+ nvp = createViewportMeta('user-scalable=no');
137
+ fn();
138
+ nvp.setAttribute('content', 'user-scalable=yes');
139
+ }
140
+ }
141
+
142
+
143
+ function anythingSelected(win) {
144
+ var sel = win.getSelection();
145
+ return sel && !sel.isCollapsed;
146
+ }
147
+
148
+
149
+ API.deselect = deselect;
150
+
151
+
152
+ initialize();
153
+
154
+ return API;
155
+ }
156
+
157
+
158
+ Monocle.Selection.SELECTION_POLLING_INTERVAL = 250;
@@ -0,0 +1,155 @@
1
+ Monocle.Styles = {
2
+
3
+ // Takes a hash and returns a string.
4
+ rulesToString: function (rules) {
5
+ if (typeof rules != 'string') {
6
+ var parts = [];
7
+ for (var declaration in rules) {
8
+ parts.push(declaration+": "+rules[declaration]+";")
9
+ }
10
+ rules = parts.join(" ");
11
+ }
12
+ return rules;
13
+ },
14
+
15
+
16
+ // Takes a hash or string of CSS property assignments and applies them
17
+ // to the element.
18
+ //
19
+ applyRules: function (elem, rules) {
20
+ rules = Monocle.Styles.rulesToString(rules);
21
+ elem.style.cssText += ';'+rules;
22
+ return elem.style.cssText;
23
+ },
24
+
25
+
26
+ // Generates cross-browser properties for a given property.
27
+ // ie, affix(<elem>, 'transition', 'linear 100ms') would apply that value
28
+ // to webkitTransition for WebKit browsers, and to MozTransition for Gecko.
29
+ //
30
+ affix: function (elem, property, value) {
31
+ var target = elem.style ? elem.style : elem;
32
+ var props = Monocle.Browser.css.toDOMProps(property);
33
+ while (props.length) { target[props.shift()] = value; }
34
+ },
35
+
36
+
37
+ setX: function (elem, x) {
38
+ var s = elem.style;
39
+ if (typeof x == "number") { x += "px"; }
40
+ var val = Monocle.Browser.env.supportsTransform3d ?
41
+ 'translate3d('+x+', 0, 0)' :
42
+ 'translateX('+x+')';
43
+ val = (x == '0px') ? 'none' : val;
44
+ s.webkitTransform = s.MozTransform = s.OTransform = s.transform = val;
45
+ return x;
46
+ },
47
+
48
+
49
+ setY: function (elem, y) {
50
+ var s = elem.style;
51
+ if (typeof y == "number") { y += "px"; }
52
+ var val = Monocle.Browser.env.supportsTransform3d ?
53
+ 'translate3d(0, '+y+', 0)' :
54
+ 'translateY('+y+')';
55
+ val = (y == '0px') ? 'none' : val;
56
+ s.webkitTransform = s.MozTransform = s.OTransform = s.transform = val;
57
+ return y;
58
+ },
59
+
60
+
61
+ getX: function (elem) {
62
+ var currStyle = document.defaultView.getComputedStyle(elem, null);
63
+ var re = /matrix\([^,]+,[^,]+,[^,]+,[^,]+,\s*([^,]+),[^\)]+\)/;
64
+ var props = Monocle.Browser.css.toDOMProps('transform');
65
+ var matrix = null;
66
+ while (props.length && !matrix) {
67
+ matrix = currStyle[props.shift()];
68
+ }
69
+ return parseInt(matrix.match(re)[1], 10);
70
+ },
71
+
72
+
73
+ transitionFor: function (elem, prop, duration, timing, delay) {
74
+ var tProps = Monocle.Browser.css.toDOMProps('transition');
75
+ var pProps = Monocle.Browser.css.toCSSProps(prop);
76
+ timing = timing || "linear";
77
+ delay = (delay || 0)+"ms";
78
+ for (var i = 0, ii = tProps.length; i < ii; ++i) {
79
+ var t = "none";
80
+ if (duration) {
81
+ t = [pProps[i], duration+"ms", timing, delay].join(" ");
82
+ }
83
+ elem.style[tProps[i]] = t;
84
+ }
85
+ }
86
+
87
+ }
88
+
89
+
90
+ // These rule definitions are more or less compulsory for Monocle to behave
91
+ // as expected. Which is why they appear here and not in the stylesheet.
92
+ // Adjust them if you know what you're doing.
93
+ //
94
+ Monocle.Styles.container = {
95
+ "position": "absolute",
96
+ "overflow": "hidden",
97
+ "top": "0",
98
+ "left": "0",
99
+ "bottom": "0",
100
+ "right": "0"
101
+ }
102
+
103
+ Monocle.Styles.page = {
104
+ "position": "absolute",
105
+ "z-index": "1",
106
+ "-webkit-user-select": "none",
107
+ "-moz-user-select": "none",
108
+ "-ms-user-select": "none",
109
+ "user-select": "none",
110
+ "-webkit-transform": "translate3d(0,0,0)",
111
+ "visibility": "visible"
112
+
113
+ /*
114
+ "background": "white",
115
+ "top": "0",
116
+ "left": "0",
117
+ "bottom": "0",
118
+ "right": "0"
119
+ */
120
+ }
121
+
122
+ Monocle.Styles.sheaf = {
123
+ "position": "absolute",
124
+ "overflow": "hidden"
125
+
126
+ /*
127
+ "top": "0",
128
+ "left": "0",
129
+ "bottom": "0",
130
+ "right": "0"
131
+ */
132
+ }
133
+
134
+ Monocle.Styles.component = {
135
+ "width": "100%",
136
+ "height": "100%",
137
+ "border": "none",
138
+ "-webkit-user-select": "none",
139
+ "-moz-user-select": "none",
140
+ "-ms-user-select": "none",
141
+ "user-select": "none"
142
+ }
143
+
144
+ Monocle.Styles.control = {
145
+ "z-index": "100",
146
+ "cursor": "pointer"
147
+ }
148
+
149
+ Monocle.Styles.overlay = {
150
+ "position": "absolute",
151
+ "display": "none",
152
+ "width": "100%",
153
+ "height": "100%",
154
+ "z-index": "1000"
155
+ }
@@ -0,0 +1,218 @@
1
+ Monocle.Dimensions.Columns = function (pageDiv) {
2
+
3
+ var API = { constructor: Monocle.Dimensions.Columns }
4
+ var k = API.constants = API.constructor;
5
+ var p = API.properties = {
6
+ page: pageDiv,
7
+ reader: pageDiv.m.reader,
8
+ length: 0,
9
+ width: 0
10
+ }
11
+
12
+ // Logically, forceColumn browsers can't have a gap, because that would
13
+ // make the minWidth > 200%. But how much greater? Not worth the effort.
14
+ k.GAP = Monocle.Browser.env.forceColumns ? 0 : 20;
15
+
16
+ function update(callback) {
17
+ setColumnWidth();
18
+ Monocle.defer(function () {
19
+ p.length = columnCount();
20
+ if (Monocle.DEBUG) {
21
+ console.log(
22
+ 'page['+p.page.m.pageIndex+'] -> '+p.length+
23
+ ' ('+p.page.m.activeFrame.m.component.properties.id+')'
24
+ );
25
+ }
26
+ callback(p.length);
27
+ });
28
+ }
29
+
30
+
31
+ function setColumnWidth() {
32
+ var pdims = pageDimensions();
33
+ var ce = columnedElement();
34
+
35
+ p.width = pdims.width;
36
+
37
+ var rules = Monocle.Styles.rulesToString(k.STYLE["columned"]);
38
+ rules += Monocle.Browser.css.toCSSDeclaration('column-width', pdims.col+'px');
39
+ rules += Monocle.Browser.css.toCSSDeclaration('column-gap', k.GAP+'px');
40
+ rules += Monocle.Browser.css.toCSSDeclaration('column-fill', 'auto');
41
+ rules += Monocle.Browser.css.toCSSDeclaration('transform', 'none');
42
+
43
+ if (Monocle.Browser.env.forceColumns && ce.scrollHeight > pdims.height) {
44
+ rules += Monocle.Styles.rulesToString(k.STYLE['column-force']);
45
+ if (Monocle.DEBUG) {
46
+ console.warn("Force columns ("+ce.scrollHeight+" > "+pdims.height+")");
47
+ }
48
+ }
49
+
50
+ if (ce.style.cssText != rules) {
51
+ // Update offset because we're translating to zero.
52
+ p.page.m.offset = 0;
53
+
54
+ // IE10 hack.
55
+ if (Monocle.Browser.env.documentElementHasScrollbars) {
56
+ ce.ownerDocument.documentElement.style.overflow = 'hidden';
57
+ }
58
+
59
+ // Apply body style changes.
60
+ ce.style.cssText = rules;
61
+
62
+ if (Monocle.Browser.env.scrollToApplyStyle) {
63
+ ce.scrollLeft = 0;
64
+ }
65
+ }
66
+ }
67
+
68
+
69
+ // Returns the element to which columns CSS should be applied.
70
+ //
71
+ function columnedElement() {
72
+ return p.page.m.activeFrame.contentDocument.body;
73
+ }
74
+
75
+
76
+ // Returns the width of the offsettable area of the columned element. By
77
+ // definition, the number of pages is always this divided by the
78
+ // width of a single page (eg, the client area of the columned element).
79
+ //
80
+ function columnedWidth() {
81
+ var bd = columnedElement();
82
+ var de = p.page.m.activeFrame.contentDocument.documentElement;
83
+
84
+ var w = Math.max(bd.scrollWidth, de.scrollWidth);
85
+
86
+ // Add one because the final column doesn't have right gutter.
87
+ // w += k.GAP;
88
+
89
+ if (!Monocle.Browser.env.widthsIgnoreTranslate && p.page.m.offset) {
90
+ w += p.page.m.offset;
91
+ }
92
+ return w;
93
+ }
94
+
95
+
96
+ function pageDimensions() {
97
+ var elem = p.page.m.sheafDiv;
98
+ var w = elem.clientWidth;
99
+ if (elem.getBoundingClientRect) { w = elem.getBoundingClientRect().width; }
100
+ if (Monocle.Browser.env.roundPageDimensions) { w = Math.round(w); }
101
+ return { col: w, width: w + k.GAP, height: elem.clientHeight }
102
+ }
103
+
104
+
105
+ function columnCount() {
106
+ return Math.ceil(columnedWidth() / pageDimensions().width)
107
+ }
108
+
109
+
110
+ function locusToOffset(locus) {
111
+ return pageDimensions().width * (locus.page - 1);
112
+ }
113
+
114
+
115
+ // Moves the columned element to the offset implied by the locus.
116
+ //
117
+ // The 'transition' argument is optional, allowing the translation to be
118
+ // animated. If not given, no change is made to the columned element's
119
+ // transition property.
120
+ //
121
+ function translateToLocus(locus, transition) {
122
+ var offset = locusToOffset(locus);
123
+ p.page.m.offset = offset;
124
+ translateToOffset(offset, transition);
125
+ return offset;
126
+ }
127
+
128
+
129
+ function translateToOffset(offset, transition) {
130
+ var ce = columnedElement();
131
+ if (transition) {
132
+ Monocle.Styles.affix(ce, "transition", transition);
133
+ }
134
+ // NB: can't use setX as it causes a flicker on iOS.
135
+ Monocle.Styles.affix(ce, "transform", "translateX(-"+offset+"px)");
136
+ }
137
+
138
+
139
+ function percentageThroughOfNode(target) {
140
+ if (!target) { return 0; }
141
+ var doc = p.page.m.activeFrame.contentDocument;
142
+ var offset = 0;
143
+ if (Monocle.Browser.env.findNodesByScrolling) {
144
+ // First, remove translation...
145
+ translateToOffset(0);
146
+
147
+ // Store scroll offsets for all windows.
148
+ var win, s;
149
+ win = s = p.page.m.activeFrame.contentWindow;
150
+ var scrollers = [
151
+ [win, win.scrollX, win.scrollY],
152
+ [window, window.scrollX, window.scrollY]
153
+ ];
154
+ //while (s != s.parent) { scrollers.push([s, s.scrollX]); s = s.parent; }
155
+
156
+ var scroller, x;
157
+ if (Monocle.Browser.env.sheafIsScroller) {
158
+ scroller = p.page.m.sheafDiv;
159
+ x = scroller.scrollLeft;
160
+ target.scrollIntoView();
161
+ offset = scroller.scrollLeft;
162
+ } else {
163
+ scroller = win;
164
+ x = scroller.scrollX;
165
+ target.scrollIntoView();
166
+ offset = scroller.scrollX;
167
+ }
168
+
169
+ // Restore scroll offsets for all windows.
170
+ while (s = scrollers.shift()) {
171
+ s[0].scrollTo(s[1], s[2]);
172
+ }
173
+
174
+ // ... finally, replace translation.
175
+ translateToOffset(p.page.m.offset);
176
+ } else {
177
+ offset = target.getBoundingClientRect().left;
178
+ offset -= doc.body.getBoundingClientRect().left;
179
+ }
180
+
181
+ // We know at least 1px will be visible, and offset should not be 0.
182
+ offset += 1;
183
+
184
+ // Percent is the offset divided by the total width of the component.
185
+ var percent = offset / (p.length * p.width);
186
+
187
+ // Page number would be offset divided by the width of a single page.
188
+ // var pageNum = Math.ceil(offset / pageDimensions().width);
189
+
190
+ return percent;
191
+ }
192
+
193
+
194
+ API.update = update;
195
+ API.percentageThroughOfNode = percentageThroughOfNode;
196
+
197
+ API.locusToOffset = locusToOffset;
198
+ API.translateToLocus = translateToLocus;
199
+
200
+ return API;
201
+ }
202
+
203
+
204
+ Monocle.Dimensions.Columns.STYLE = {
205
+ // Most of these are already applied to body, but they're repeated here
206
+ // in case columnedElement() is ever anything other than body.
207
+ "columned": {
208
+ "margin": "0",
209
+ "padding": "0",
210
+ "height": "100%",
211
+ "width": "100%",
212
+ "position": "absolute"
213
+ },
214
+ "column-force": {
215
+ "min-width": "200%",
216
+ "overflow": "hidden"
217
+ }
218
+ }