colorgy_style 0.0.0.1 → 0.0.0.2
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/assets/javascripts/colorgy/addons/holder.js +1 -0
- data/assets/javascripts/colorgy/components/alert.js +9 -0
- data/assets/javascripts/colorgy/components/dropdown.js +8 -0
- data/assets/javascripts/colorgy/flash.js +86 -0
- data/assets/javascripts/colorgy/lib/interactiveStyle.js +5 -0
- data/assets/javascripts/colorgy/lib/jquery.getOrAddChild.js +12 -0
- data/assets/javascripts/colorgy/main.js +3 -0
- data/assets/javascripts/vendor/holder.js +2471 -0
- data/assets/javascripts/vendor/toastr.js +442 -0
- data/assets/stylesheets/colorgy/components/_alert.scss +40 -0
- data/assets/stylesheets/colorgy/components/_badge.scss +9 -0
- data/assets/stylesheets/colorgy/components/_breadcrumb.scss +9 -0
- data/assets/stylesheets/colorgy/components/_button.scss +50 -7
- data/assets/stylesheets/colorgy/components/_button_group.scss +33 -0
- data/assets/stylesheets/colorgy/components/_dropdown.scss +18 -0
- data/assets/stylesheets/colorgy/components/_input_group.scss +23 -0
- data/assets/stylesheets/colorgy/components/_label.scss +39 -0
- data/assets/stylesheets/colorgy/components/_list_group.scss +9 -0
- data/assets/stylesheets/colorgy/components/_media.scss +9 -0
- data/assets/stylesheets/colorgy/components/_nav.scss +33 -0
- data/assets/stylesheets/colorgy/components/_navbar.scss +23 -0
- data/assets/stylesheets/colorgy/components/_page_header.scss +11 -0
- data/assets/stylesheets/colorgy/components/_pager.scss +9 -0
- data/assets/stylesheets/colorgy/components/_pagination.scss +23 -0
- data/assets/stylesheets/colorgy/components/_panel.scss +39 -0
- data/assets/stylesheets/colorgy/components/_progress_bar.scss +41 -0
- data/assets/stylesheets/colorgy/components/_thumbnail.scss +9 -0
- data/assets/stylesheets/colorgy/components/_toast.scss +352 -0
- data/assets/stylesheets/colorgy/components/_well.scss +23 -0
- data/assets/stylesheets/colorgy/core/_base.scss +1 -1
- data/assets/stylesheets/colorgy/core/_config.scss +1 -1
- data/assets/stylesheets/colorgy/core/_grid.scss +1 -1
- data/assets/stylesheets/colorgy/core/_tools.scss +9 -0
- data/assets/stylesheets/colorgy/layouts/_default.scss +3 -0
- data/assets/stylesheets/colorgy/main.scss +3 -1
- data/assets/stylesheets/colorgy/structures/_jumbotron.scss +9 -0
- data/assets/stylesheets/vendor/animate.scss +3272 -0
- data/lib/colorgy_style/version.rb +1 -1
- data/styleguide/index.html.haml +40 -1
- data/styleguide/javascripts/body.js +7 -1
- data/styleguide/styleblocks/_alert.html.erb +3 -0
- data/styleguide/styleblocks/_badge.html.erb +5 -0
- data/styleguide/styleblocks/_breadcrumb.html.erb +5 -0
- data/styleguide/styleblocks/_button.html.erb +6 -6
- data/styleguide/styleblocks/_button_group.html.erb +41 -0
- data/styleguide/styleblocks/_dropdown.html.erb +65 -0
- data/styleguide/styleblocks/_input_group.html.erb +131 -0
- data/styleguide/styleblocks/_label.html.erb +7 -0
- data/styleguide/styleblocks/_list_group.html.erb +31 -0
- data/styleguide/styleblocks/_media.html.erb +60 -0
- data/styleguide/styleblocks/_nav.html.erb +18 -0
- data/styleguide/styleblocks/_navbar.html.erb +53 -0
- data/styleguide/styleblocks/_page_header.html.erb +3 -0
- data/styleguide/styleblocks/_pager.html.erb +6 -0
- data/styleguide/styleblocks/_pagination.html.erb +19 -0
- data/styleguide/styleblocks/_panel.html.erb +100 -0
- data/styleguide/styleblocks/_progress_bar.html.erb +12 -0
- data/styleguide/styleblocks/_thumbnail.html.erb +56 -0
- data/styleguide/styleblocks/_toast.html.erb +35 -0
- data/styleguide/styleblocks/_well.html.erb +1 -0
- data/styleguide/stylesheets/styleguide/styles.scss +14 -0
- metadata +53 -4
- data/assets/stylesheets/colorgy/components/.keep +0 -0
- data/assets/stylesheets/colorgy/structures/.keep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e199e0cc0fe46c0bec57ad903b5e193231707f6c
|
4
|
+
data.tar.gz: de76c315edfe60dcda0a5528a117df6ea368e82f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27736f311ed1670106a4789edbd4282f70d61a6dcd41af9016cb73d2930e0566998f9573b450d52d8b1e036830655f54ede455897d08c048fbb19e28d828260e
|
7
|
+
data.tar.gz: 2d48e949e3b35b0e19a4cfe1b756e1ad17f4f9c0ce3deb671b9899ea2e8913145605a71959a76084477d5db3fd513d15fe9cb36afd32269aa8dc3e2c2dc726e1
|
data/README.md
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
//= require ../../vendor/holder.js
|
@@ -0,0 +1,9 @@
|
|
1
|
+
//= require ../lib/interactiveStyle
|
2
|
+
//= require ../lib/jquery.getOrAddChild
|
3
|
+
|
4
|
+
interactiveStyle.alert = function() {
|
5
|
+
$('.alert.dismissible').getOrAddChild('.close', '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>');
|
6
|
+
//= require bootstrap/alert
|
7
|
+
}
|
8
|
+
|
9
|
+
interactiveStyle.alert();
|
@@ -0,0 +1,86 @@
|
|
1
|
+
// Flash messages adopter
|
2
|
+
//
|
3
|
+
// API: flash.info(message, actions, title);
|
4
|
+
// ^
|
5
|
+
// can be info, success, error or warning
|
6
|
+
//
|
7
|
+
// The "actions" parameter can be a string of HTML, or an array containing
|
8
|
+
// title and callbacks like this:
|
9
|
+
// [['Cancel', function() { alert('Canceled!'); }], ['Details'] function() { alert('Yo!'); }]
|
10
|
+
//
|
11
|
+
//= require ../vendor/toastr
|
12
|
+
|
13
|
+
flash = {};
|
14
|
+
|
15
|
+
flash.count = 0;
|
16
|
+
flash.onShown = function() {
|
17
|
+
flash.count++;
|
18
|
+
var $toast = flash.hideFirstToast();
|
19
|
+
setTimeout(function() {
|
20
|
+
$toast.css({
|
21
|
+
'margin-top': '0',
|
22
|
+
'-moz-transition-property': 'margin, margin-top',
|
23
|
+
'-o-transition-property': 'margin, margin-top',
|
24
|
+
'-webkit-transition-property': 'margin, margin-top',
|
25
|
+
'transition-property': 'margin, margin-top',
|
26
|
+
'-moz-transition-duration': '0.3s',
|
27
|
+
'-o-transition-duration': '0.3s',
|
28
|
+
'-webkit-transition-duration': '0.3s',
|
29
|
+
'transition-duration': '0.3s'
|
30
|
+
});
|
31
|
+
}, 10);
|
32
|
+
};
|
33
|
+
|
34
|
+
flash.hideFirstToast = function() {
|
35
|
+
var $target = $('#toast-container .toast:first-of-type');
|
36
|
+
var tHight = $target.outerHeight(true);
|
37
|
+
$target.css({
|
38
|
+
'margin-top': '-' + (tHight) + 'px',
|
39
|
+
'-moz-transition-property': 'none',
|
40
|
+
'-o-transition-property': 'none',
|
41
|
+
'-webkit-transition-property': 'none',
|
42
|
+
'transition-property': 'none',
|
43
|
+
'-moz-transition-duration': '0',
|
44
|
+
'-o-transition-duration': '0',
|
45
|
+
'-webkit-transition-duration': '0',
|
46
|
+
'transition-duration': '0'
|
47
|
+
});
|
48
|
+
return $target;
|
49
|
+
};
|
50
|
+
|
51
|
+
toastr.options = {
|
52
|
+
"closeButton": false,
|
53
|
+
"debug": false,
|
54
|
+
"newestOnTop": true,
|
55
|
+
"progressBar": false,
|
56
|
+
"positionClass": "toast-top-center",
|
57
|
+
"preventDuplicates": false,
|
58
|
+
"onclick": null,
|
59
|
+
"showDuration": 0,
|
60
|
+
"hideDuration": 1000,
|
61
|
+
"timeOut": 5000,
|
62
|
+
"extendedTimeOut": 800,
|
63
|
+
"showEasing": "swing",
|
64
|
+
"hideEasing": "linear",
|
65
|
+
"showMethod": "fadeIn",
|
66
|
+
"hideMethod": "fadeOut",
|
67
|
+
"onShown": flash.onShown
|
68
|
+
};
|
69
|
+
|
70
|
+
flash.info = function(message, actions, title) {
|
71
|
+
toastr.info(message, title, { 'actions': actions });
|
72
|
+
};
|
73
|
+
|
74
|
+
flash.success = function(message, actions, title) {
|
75
|
+
toastr.success(message, title, { 'actions': actions });
|
76
|
+
};
|
77
|
+
|
78
|
+
flash.error = function(message, actions, title) {
|
79
|
+
toastr.error(message, title, { 'actions': actions });
|
80
|
+
};
|
81
|
+
|
82
|
+
flash.warning = function(message, actions, title) {
|
83
|
+
toastr.warning(message, title, { 'actions': actions });
|
84
|
+
};
|
85
|
+
|
86
|
+
window.flash = flash;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
// Example usage: $('.alert.dismissible').getOrAddChild('.close', '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>');
|
2
|
+
|
3
|
+
$.fn.getOrAddChild = function (selector, html) {
|
4
|
+
var $parents = this;
|
5
|
+
$parents.each(function() {
|
6
|
+
var $parent = $(this);
|
7
|
+
var $child = $parent.children(selector);
|
8
|
+
if (!$child.length)
|
9
|
+
$child = $(html).appendTo($parent);
|
10
|
+
return $child;
|
11
|
+
});
|
12
|
+
};
|
@@ -0,0 +1,2471 @@
|
|
1
|
+
/*!
|
2
|
+
|
3
|
+
Holder - client side image placeholders
|
4
|
+
Version 2.7.1+6hydf
|
5
|
+
© 2015 Ivan Malopinsky - http://imsky.co
|
6
|
+
|
7
|
+
Site: http://holderjs.com
|
8
|
+
Issues: https://github.com/imsky/holder/issues
|
9
|
+
License: http://opensource.org/licenses/MIT
|
10
|
+
|
11
|
+
*/
|
12
|
+
(function (window) {
|
13
|
+
if (!window.document) return;
|
14
|
+
var document = window.document;
|
15
|
+
|
16
|
+
//https://github.com/inexorabletash/polyfill/blob/master/web.js
|
17
|
+
if (!document.querySelectorAll) {
|
18
|
+
document.querySelectorAll = function (selectors) {
|
19
|
+
var style = document.createElement('style'), elements = [], element;
|
20
|
+
document.documentElement.firstChild.appendChild(style);
|
21
|
+
document._qsa = [];
|
22
|
+
|
23
|
+
style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
|
24
|
+
window.scrollBy(0, 0);
|
25
|
+
style.parentNode.removeChild(style);
|
26
|
+
|
27
|
+
while (document._qsa.length) {
|
28
|
+
element = document._qsa.shift();
|
29
|
+
element.style.removeAttribute('x-qsa');
|
30
|
+
elements.push(element);
|
31
|
+
}
|
32
|
+
document._qsa = null;
|
33
|
+
return elements;
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
if (!document.querySelector) {
|
38
|
+
document.querySelector = function (selectors) {
|
39
|
+
var elements = document.querySelectorAll(selectors);
|
40
|
+
return (elements.length) ? elements[0] : null;
|
41
|
+
};
|
42
|
+
}
|
43
|
+
|
44
|
+
if (!document.getElementsByClassName) {
|
45
|
+
document.getElementsByClassName = function (classNames) {
|
46
|
+
classNames = String(classNames).replace(/^|\s+/g, '.');
|
47
|
+
return document.querySelectorAll(classNames);
|
48
|
+
};
|
49
|
+
}
|
50
|
+
|
51
|
+
//https://github.com/inexorabletash/polyfill
|
52
|
+
// ES5 15.2.3.14 Object.keys ( O )
|
53
|
+
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
|
54
|
+
if (!Object.keys) {
|
55
|
+
Object.keys = function (o) {
|
56
|
+
if (o !== Object(o)) { throw TypeError('Object.keys called on non-object'); }
|
57
|
+
var ret = [], p;
|
58
|
+
for (p in o) {
|
59
|
+
if (Object.prototype.hasOwnProperty.call(o, p)) {
|
60
|
+
ret.push(p);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
return ret;
|
64
|
+
};
|
65
|
+
}
|
66
|
+
|
67
|
+
//https://github.com/inexorabletash/polyfill/blob/master/web.js
|
68
|
+
(function (global) {
|
69
|
+
var B64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
70
|
+
global.atob = global.atob || function (input) {
|
71
|
+
input = String(input);
|
72
|
+
var position = 0,
|
73
|
+
output = [],
|
74
|
+
buffer = 0, bits = 0, n;
|
75
|
+
|
76
|
+
input = input.replace(/\s/g, '');
|
77
|
+
if ((input.length % 4) === 0) { input = input.replace(/=+$/, ''); }
|
78
|
+
if ((input.length % 4) === 1) { throw Error('InvalidCharacterError'); }
|
79
|
+
if (/[^+/0-9A-Za-z]/.test(input)) { throw Error('InvalidCharacterError'); }
|
80
|
+
|
81
|
+
while (position < input.length) {
|
82
|
+
n = B64_ALPHABET.indexOf(input.charAt(position));
|
83
|
+
buffer = (buffer << 6) | n;
|
84
|
+
bits += 6;
|
85
|
+
|
86
|
+
if (bits === 24) {
|
87
|
+
output.push(String.fromCharCode((buffer >> 16) & 0xFF));
|
88
|
+
output.push(String.fromCharCode((buffer >> 8) & 0xFF));
|
89
|
+
output.push(String.fromCharCode(buffer & 0xFF));
|
90
|
+
bits = 0;
|
91
|
+
buffer = 0;
|
92
|
+
}
|
93
|
+
position += 1;
|
94
|
+
}
|
95
|
+
|
96
|
+
if (bits === 12) {
|
97
|
+
buffer = buffer >> 4;
|
98
|
+
output.push(String.fromCharCode(buffer & 0xFF));
|
99
|
+
} else if (bits === 18) {
|
100
|
+
buffer = buffer >> 2;
|
101
|
+
output.push(String.fromCharCode((buffer >> 8) & 0xFF));
|
102
|
+
output.push(String.fromCharCode(buffer & 0xFF));
|
103
|
+
}
|
104
|
+
|
105
|
+
return output.join('');
|
106
|
+
};
|
107
|
+
|
108
|
+
global.btoa = global.btoa || function (input) {
|
109
|
+
input = String(input);
|
110
|
+
var position = 0,
|
111
|
+
out = [],
|
112
|
+
o1, o2, o3,
|
113
|
+
e1, e2, e3, e4;
|
114
|
+
|
115
|
+
if (/[^\x00-\xFF]/.test(input)) { throw Error('InvalidCharacterError'); }
|
116
|
+
|
117
|
+
while (position < input.length) {
|
118
|
+
o1 = input.charCodeAt(position++);
|
119
|
+
o2 = input.charCodeAt(position++);
|
120
|
+
o3 = input.charCodeAt(position++);
|
121
|
+
|
122
|
+
// 111111 112222 222233 333333
|
123
|
+
e1 = o1 >> 2;
|
124
|
+
e2 = ((o1 & 0x3) << 4) | (o2 >> 4);
|
125
|
+
e3 = ((o2 & 0xf) << 2) | (o3 >> 6);
|
126
|
+
e4 = o3 & 0x3f;
|
127
|
+
|
128
|
+
if (position === input.length + 2) {
|
129
|
+
e3 = 64; e4 = 64;
|
130
|
+
}
|
131
|
+
else if (position === input.length + 1) {
|
132
|
+
e4 = 64;
|
133
|
+
}
|
134
|
+
|
135
|
+
out.push(B64_ALPHABET.charAt(e1),
|
136
|
+
B64_ALPHABET.charAt(e2),
|
137
|
+
B64_ALPHABET.charAt(e3),
|
138
|
+
B64_ALPHABET.charAt(e4));
|
139
|
+
}
|
140
|
+
|
141
|
+
return out.join('');
|
142
|
+
};
|
143
|
+
}(window));
|
144
|
+
|
145
|
+
//https://gist.github.com/jimeh/332357
|
146
|
+
if (!Object.prototype.hasOwnProperty){
|
147
|
+
/*jshint -W001, -W103 */
|
148
|
+
Object.prototype.hasOwnProperty = function(prop) {
|
149
|
+
var proto = this.__proto__ || this.constructor.prototype;
|
150
|
+
return (prop in this) && (!(prop in proto) || proto[prop] !== this[prop]);
|
151
|
+
};
|
152
|
+
/*jshint +W001, +W103 */
|
153
|
+
}
|
154
|
+
|
155
|
+
// @license http://opensource.org/licenses/MIT
|
156
|
+
// copyright Paul Irish 2015
|
157
|
+
|
158
|
+
|
159
|
+
// Date.now() is supported everywhere except IE8. For IE8 we use the Date.now polyfill
|
160
|
+
// github.com/Financial-Times/polyfill-service/blob/master/polyfills/Date.now/polyfill.js
|
161
|
+
// as Safari 6 doesn't have support for NavigationTiming, we use a Date.now() timestamp for relative values
|
162
|
+
|
163
|
+
// if you want values similar to what you'd get with real perf.now, place this towards the head of the page
|
164
|
+
// but in reality, you're just getting the delta between now() calls, so it's not terribly important where it's placed
|
165
|
+
|
166
|
+
|
167
|
+
(function(){
|
168
|
+
|
169
|
+
if ('performance' in window === false) {
|
170
|
+
window.performance = {};
|
171
|
+
}
|
172
|
+
|
173
|
+
Date.now = (Date.now || function () { // thanks IE8
|
174
|
+
return new Date().getTime();
|
175
|
+
});
|
176
|
+
|
177
|
+
if ('now' in window.performance === false){
|
178
|
+
|
179
|
+
var nowOffset = Date.now();
|
180
|
+
|
181
|
+
if (performance.timing && performance.timing.navigationStart){
|
182
|
+
nowOffset = performance.timing.navigationStart;
|
183
|
+
}
|
184
|
+
|
185
|
+
window.performance.now = function now(){
|
186
|
+
return Date.now() - nowOffset;
|
187
|
+
};
|
188
|
+
}
|
189
|
+
|
190
|
+
})();
|
191
|
+
|
192
|
+
//requestAnimationFrame polyfill for older Firefox/Chrome versions
|
193
|
+
if (!window.requestAnimationFrame) {
|
194
|
+
if (window.webkitRequestAnimationFrame) {
|
195
|
+
//https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/requestAnimationFrame/polyfill-webkit.js
|
196
|
+
(function (global) {
|
197
|
+
// window.requestAnimationFrame
|
198
|
+
global.requestAnimationFrame = function (callback) {
|
199
|
+
return webkitRequestAnimationFrame(function () {
|
200
|
+
callback(global.performance.now());
|
201
|
+
});
|
202
|
+
};
|
203
|
+
|
204
|
+
// window.cancelAnimationFrame
|
205
|
+
global.cancelAnimationFrame = webkitCancelAnimationFrame;
|
206
|
+
}(window));
|
207
|
+
} else if (window.mozRequestAnimationFrame) {
|
208
|
+
//https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/requestAnimationFrame/polyfill-moz.js
|
209
|
+
(function (global) {
|
210
|
+
// window.requestAnimationFrame
|
211
|
+
global.requestAnimationFrame = function (callback) {
|
212
|
+
return mozRequestAnimationFrame(function () {
|
213
|
+
callback(global.performance.now());
|
214
|
+
});
|
215
|
+
};
|
216
|
+
|
217
|
+
// window.cancelAnimationFrame
|
218
|
+
global.cancelAnimationFrame = mozCancelAnimationFrame;
|
219
|
+
}(window));
|
220
|
+
} else {
|
221
|
+
(function (global) {
|
222
|
+
global.requestAnimationFrame = function (callback) {
|
223
|
+
return global.setTimeout(callback, 1000 / 60);
|
224
|
+
};
|
225
|
+
|
226
|
+
global.cancelAnimationFrame = global.clearTimeout;
|
227
|
+
})(window);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
})(this);
|
231
|
+
|
232
|
+
(function webpackUniversalModuleDefinition(root, factory) {
|
233
|
+
if(typeof exports === 'object' && typeof module === 'object')
|
234
|
+
module.exports = factory();
|
235
|
+
else if(typeof define === 'function' && define.amd)
|
236
|
+
define(factory);
|
237
|
+
else if(typeof exports === 'object')
|
238
|
+
exports["Holder"] = factory();
|
239
|
+
else
|
240
|
+
root["Holder"] = factory();
|
241
|
+
})(this, function() {
|
242
|
+
return /******/ (function(modules) { // webpackBootstrap
|
243
|
+
/******/ // The module cache
|
244
|
+
/******/ var installedModules = {};
|
245
|
+
|
246
|
+
/******/ // The require function
|
247
|
+
/******/ function __webpack_require__(moduleId) {
|
248
|
+
|
249
|
+
/******/ // Check if module is in cache
|
250
|
+
/******/ if(installedModules[moduleId])
|
251
|
+
/******/ return installedModules[moduleId].exports;
|
252
|
+
|
253
|
+
/******/ // Create a new module (and put it into the cache)
|
254
|
+
/******/ var module = installedModules[moduleId] = {
|
255
|
+
/******/ exports: {},
|
256
|
+
/******/ id: moduleId,
|
257
|
+
/******/ loaded: false
|
258
|
+
/******/ };
|
259
|
+
|
260
|
+
/******/ // Execute the module function
|
261
|
+
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
262
|
+
|
263
|
+
/******/ // Flag the module as loaded
|
264
|
+
/******/ module.loaded = true;
|
265
|
+
|
266
|
+
/******/ // Return the exports of the module
|
267
|
+
/******/ return module.exports;
|
268
|
+
/******/ }
|
269
|
+
|
270
|
+
|
271
|
+
/******/ // expose the modules object (__webpack_modules__)
|
272
|
+
/******/ __webpack_require__.m = modules;
|
273
|
+
|
274
|
+
/******/ // expose the module cache
|
275
|
+
/******/ __webpack_require__.c = installedModules;
|
276
|
+
|
277
|
+
/******/ // __webpack_public_path__
|
278
|
+
/******/ __webpack_require__.p = "";
|
279
|
+
|
280
|
+
/******/ // Load entry module and return exports
|
281
|
+
/******/ return __webpack_require__(0);
|
282
|
+
/******/ })
|
283
|
+
/************************************************************************/
|
284
|
+
/******/ ([
|
285
|
+
/* 0 */
|
286
|
+
/***/ function(module, exports, __webpack_require__) {
|
287
|
+
|
288
|
+
/* WEBPACK VAR INJECTION */(function(global) {/*
|
289
|
+
Holder.js - client side image placeholders
|
290
|
+
© 2012-2015 Ivan Malopinsky - http://imsky.co
|
291
|
+
*/
|
292
|
+
|
293
|
+
//Libraries and functions
|
294
|
+
var onDomReady = __webpack_require__(1);
|
295
|
+
var SceneGraph = __webpack_require__(2);
|
296
|
+
var utils = __webpack_require__(3);
|
297
|
+
var querystring = __webpack_require__(4);
|
298
|
+
|
299
|
+
var extend = utils.extend;
|
300
|
+
var getNodeArray = utils.getNodeArray;
|
301
|
+
var dimensionCheck = utils.dimensionCheck;
|
302
|
+
|
303
|
+
//Constants and definitions
|
304
|
+
var SVG_NS = 'http://www.w3.org/2000/svg';
|
305
|
+
var NODE_TYPE_COMMENT = 8;
|
306
|
+
var version = '2.7.1';
|
307
|
+
var generatorComment = '\n' +
|
308
|
+
'Created with Holder.js ' + version + '.\n' +
|
309
|
+
'Learn more at http://holderjs.com\n' +
|
310
|
+
'(c) 2012-2015 Ivan Malopinsky - http://imsky.co\n';
|
311
|
+
|
312
|
+
var Holder = {
|
313
|
+
version: version,
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Adds a theme to default settings
|
317
|
+
*
|
318
|
+
* @param {string} name Theme name
|
319
|
+
* @param {Object} theme Theme object, with foreground, background, size, font, and fontweight properties.
|
320
|
+
*/
|
321
|
+
addTheme: function(name, theme) {
|
322
|
+
name != null && theme != null && (App.settings.themes[name] = theme);
|
323
|
+
delete App.vars.cache.themeKeys;
|
324
|
+
return this;
|
325
|
+
},
|
326
|
+
|
327
|
+
/**
|
328
|
+
* Appends a placeholder to an element
|
329
|
+
*
|
330
|
+
* @param {string} src Placeholder URL string
|
331
|
+
* @param {string} el Selector of target element(s)
|
332
|
+
*/
|
333
|
+
addImage: function(src, el) {
|
334
|
+
var node = document.querySelectorAll(el);
|
335
|
+
if (node.length) {
|
336
|
+
for (var i = 0, l = node.length; i < l; i++) {
|
337
|
+
var img = newEl('img');
|
338
|
+
var domProps = {};
|
339
|
+
domProps[App.vars.dataAttr] = src;
|
340
|
+
setAttr(img, domProps);
|
341
|
+
node[i].appendChild(img);
|
342
|
+
}
|
343
|
+
}
|
344
|
+
return this;
|
345
|
+
},
|
346
|
+
|
347
|
+
/**
|
348
|
+
* Sets whether or not an image is updated on resize.
|
349
|
+
* If an image is set to be updated, it is immediately rendered.
|
350
|
+
*
|
351
|
+
* @param {Object} el Image DOM element
|
352
|
+
* @param {Boolean} value Resizable update flag value
|
353
|
+
*/
|
354
|
+
setResizeUpdate: function(el, value) {
|
355
|
+
if (el.holderData) {
|
356
|
+
el.holderData.resizeUpdate = !!value;
|
357
|
+
if (el.holderData.resizeUpdate) {
|
358
|
+
updateResizableElements(el);
|
359
|
+
}
|
360
|
+
}
|
361
|
+
},
|
362
|
+
|
363
|
+
/**
|
364
|
+
* Runs Holder with options. By default runs Holder on all images with "holder.js" in their source attributes.
|
365
|
+
*
|
366
|
+
* @param {Object} userOptions Options object, can contain domain, themes, images, and bgnodes properties
|
367
|
+
*/
|
368
|
+
run: function(userOptions) {
|
369
|
+
userOptions = userOptions || {};
|
370
|
+
var engineSettings = {};
|
371
|
+
var options = extend(App.settings, userOptions);
|
372
|
+
|
373
|
+
App.vars.preempted = true;
|
374
|
+
App.vars.dataAttr = options.dataAttr || App.vars.dataAttr;
|
375
|
+
|
376
|
+
engineSettings.renderer = options.renderer ? options.renderer : App.setup.renderer;
|
377
|
+
if (App.setup.renderers.join(',').indexOf(engineSettings.renderer) === -1) {
|
378
|
+
engineSettings.renderer = App.setup.supportsSVG ? 'svg' : (App.setup.supportsCanvas ? 'canvas' : 'html');
|
379
|
+
}
|
380
|
+
|
381
|
+
var images = getNodeArray(options.images);
|
382
|
+
var bgnodes = getNodeArray(options.bgnodes);
|
383
|
+
var stylenodes = getNodeArray(options.stylenodes);
|
384
|
+
var objects = getNodeArray(options.objects);
|
385
|
+
|
386
|
+
engineSettings.stylesheets = [];
|
387
|
+
engineSettings.svgXMLStylesheet = true;
|
388
|
+
engineSettings.noFontFallback = options.noFontFallback ? options.noFontFallback : false;
|
389
|
+
|
390
|
+
for (var i = 0; i < stylenodes.length; i++) {
|
391
|
+
var styleNode = stylenodes[i];
|
392
|
+
if (styleNode.attributes.rel && styleNode.attributes.href && styleNode.attributes.rel.value == 'stylesheet') {
|
393
|
+
var href = styleNode.attributes.href.value;
|
394
|
+
//todo: write isomorphic relative-to-absolute URL function
|
395
|
+
var proxyLink = newEl('a');
|
396
|
+
proxyLink.href = href;
|
397
|
+
var stylesheetURL = proxyLink.protocol + '//' + proxyLink.host + proxyLink.pathname + proxyLink.search;
|
398
|
+
engineSettings.stylesheets.push(stylesheetURL);
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
for (i = 0; i < bgnodes.length; i++) {
|
403
|
+
//Skip processing background nodes if getComputedStyle is unavailable, since only modern browsers would be able to use canvas or SVG to render to background
|
404
|
+
if (!global.getComputedStyle) continue;
|
405
|
+
var backgroundImage = global.getComputedStyle(bgnodes[i], null).getPropertyValue('background-image');
|
406
|
+
var dataBackgroundImage = bgnodes[i].getAttribute('data-background-src');
|
407
|
+
var rawURL = null;
|
408
|
+
|
409
|
+
if (dataBackgroundImage == null) {
|
410
|
+
rawURL = backgroundImage;
|
411
|
+
} else {
|
412
|
+
rawURL = dataBackgroundImage;
|
413
|
+
}
|
414
|
+
|
415
|
+
var holderURL = null;
|
416
|
+
var holderString = '?' + options.domain + '/';
|
417
|
+
|
418
|
+
if (rawURL.indexOf(holderString) === 0) {
|
419
|
+
holderURL = rawURL.slice(1);
|
420
|
+
} else if (rawURL.indexOf(holderString) != -1) {
|
421
|
+
var fragment = rawURL.substr(rawURL.indexOf(holderString)).slice(1);
|
422
|
+
var fragmentMatch = fragment.match(/([^\"]*)"?\)/);
|
423
|
+
|
424
|
+
if (fragmentMatch != null) {
|
425
|
+
holderURL = fragmentMatch[1];
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
if (holderURL != null) {
|
430
|
+
var holderFlags = parseURL(holderURL, options);
|
431
|
+
if (holderFlags) {
|
432
|
+
prepareDOMElement({
|
433
|
+
mode: 'background',
|
434
|
+
el: bgnodes[i],
|
435
|
+
flags: holderFlags,
|
436
|
+
engineSettings: engineSettings
|
437
|
+
});
|
438
|
+
}
|
439
|
+
}
|
440
|
+
}
|
441
|
+
|
442
|
+
for (i = 0; i < objects.length; i++) {
|
443
|
+
var object = objects[i];
|
444
|
+
var objectAttr = {};
|
445
|
+
|
446
|
+
try {
|
447
|
+
objectAttr.data = object.getAttribute('data');
|
448
|
+
objectAttr.dataSrc = object.getAttribute(App.vars.dataAttr);
|
449
|
+
} catch (e) {}
|
450
|
+
|
451
|
+
var objectHasSrcURL = objectAttr.data != null && objectAttr.data.indexOf(options.domain) === 0;
|
452
|
+
var objectHasDataSrcURL = objectAttr.dataSrc != null && objectAttr.dataSrc.indexOf(options.domain) === 0;
|
453
|
+
|
454
|
+
if (objectHasSrcURL) {
|
455
|
+
prepareImageElement(options, engineSettings, objectAttr.data, object);
|
456
|
+
} else if (objectHasDataSrcURL) {
|
457
|
+
prepareImageElement(options, engineSettings, objectAttr.dataSrc, object);
|
458
|
+
}
|
459
|
+
}
|
460
|
+
|
461
|
+
for (i = 0; i < images.length; i++) {
|
462
|
+
var image = images[i];
|
463
|
+
var imageAttr = {};
|
464
|
+
|
465
|
+
try {
|
466
|
+
imageAttr.src = image.getAttribute('src');
|
467
|
+
imageAttr.dataSrc = image.getAttribute(App.vars.dataAttr);
|
468
|
+
imageAttr.rendered = image.getAttribute('data-holder-rendered');
|
469
|
+
} catch (e) {}
|
470
|
+
|
471
|
+
var imageHasSrc = imageAttr.src != null;
|
472
|
+
var imageHasDataSrcURL = imageAttr.dataSrc != null && imageAttr.dataSrc.indexOf(options.domain) === 0;
|
473
|
+
var imageRendered = imageAttr.rendered != null && imageAttr.rendered == 'true';
|
474
|
+
|
475
|
+
if (imageHasSrc) {
|
476
|
+
if (imageAttr.src.indexOf(options.domain) === 0) {
|
477
|
+
prepareImageElement(options, engineSettings, imageAttr.src, image);
|
478
|
+
} else if (imageHasDataSrcURL) {
|
479
|
+
//Image has a valid data-src and an invalid src
|
480
|
+
if (imageRendered) {
|
481
|
+
//If the placeholder has already been render, re-render it
|
482
|
+
prepareImageElement(options, engineSettings, imageAttr.dataSrc, image);
|
483
|
+
} else {
|
484
|
+
//If the placeholder has not been rendered, check if the image exists and render a fallback if it doesn't
|
485
|
+
(function(src, options, engineSettings, dataSrc, image) {
|
486
|
+
utils.imageExists(src, function(exists) {
|
487
|
+
if (!exists) {
|
488
|
+
prepareImageElement(options, engineSettings, dataSrc, image);
|
489
|
+
}
|
490
|
+
});
|
491
|
+
})(imageAttr.src, options, engineSettings, imageAttr.dataSrc, image);
|
492
|
+
}
|
493
|
+
}
|
494
|
+
} else if (imageHasDataSrcURL) {
|
495
|
+
prepareImageElement(options, engineSettings, imageAttr.dataSrc, image);
|
496
|
+
}
|
497
|
+
}
|
498
|
+
|
499
|
+
return this;
|
500
|
+
}
|
501
|
+
};
|
502
|
+
|
503
|
+
var App = {
|
504
|
+
settings: {
|
505
|
+
domain: 'holder.js',
|
506
|
+
images: 'img',
|
507
|
+
objects: 'object',
|
508
|
+
bgnodes: 'body .holderjs',
|
509
|
+
stylenodes: 'head link.holderjs',
|
510
|
+
stylesheets: [],
|
511
|
+
themes: {
|
512
|
+
'gray': {
|
513
|
+
background: '#EEEEEE',
|
514
|
+
foreground: '#AAAAAA'
|
515
|
+
},
|
516
|
+
'social': {
|
517
|
+
background: '#3a5a97',
|
518
|
+
foreground: '#FFFFFF'
|
519
|
+
},
|
520
|
+
'industrial': {
|
521
|
+
background: '#434A52',
|
522
|
+
foreground: '#C2F200'
|
523
|
+
},
|
524
|
+
'sky': {
|
525
|
+
background: '#0D8FDB',
|
526
|
+
foreground: '#FFFFFF'
|
527
|
+
},
|
528
|
+
'vine': {
|
529
|
+
background: '#39DBAC',
|
530
|
+
foreground: '#1E292C'
|
531
|
+
},
|
532
|
+
'lava': {
|
533
|
+
background: '#F8591A',
|
534
|
+
foreground: '#1C2846'
|
535
|
+
}
|
536
|
+
}
|
537
|
+
},
|
538
|
+
defaults: {
|
539
|
+
size: 10,
|
540
|
+
units: 'pt',
|
541
|
+
scale: 1 / 16
|
542
|
+
},
|
543
|
+
//todo: remove in 2.8
|
544
|
+
flags: {
|
545
|
+
dimensions: {
|
546
|
+
regex: /^(\d+)x(\d+)$/,
|
547
|
+
output: function(val) {
|
548
|
+
var exec = this.regex.exec(val);
|
549
|
+
return {
|
550
|
+
width: +exec[1],
|
551
|
+
height: +exec[2]
|
552
|
+
};
|
553
|
+
}
|
554
|
+
},
|
555
|
+
fluid: {
|
556
|
+
regex: /^([0-9]+%?)x([0-9]+%?)$/,
|
557
|
+
output: function(val) {
|
558
|
+
var exec = this.regex.exec(val);
|
559
|
+
return {
|
560
|
+
width: exec[1],
|
561
|
+
height: exec[2]
|
562
|
+
};
|
563
|
+
}
|
564
|
+
},
|
565
|
+
colors: {
|
566
|
+
regex: /(?:#|\^)([0-9a-f]{3,})\:(?:#|\^)([0-9a-f]{3,})/i,
|
567
|
+
output: function(val) {
|
568
|
+
var exec = this.regex.exec(val);
|
569
|
+
return {
|
570
|
+
foreground: '#' + exec[2],
|
571
|
+
background: '#' + exec[1]
|
572
|
+
};
|
573
|
+
}
|
574
|
+
},
|
575
|
+
text: {
|
576
|
+
regex: /text\:(.*)/,
|
577
|
+
output: function(val) {
|
578
|
+
return this.regex.exec(val)[1].replace('\\/', '/');
|
579
|
+
}
|
580
|
+
},
|
581
|
+
font: {
|
582
|
+
regex: /font\:(.*)/,
|
583
|
+
output: function(val) {
|
584
|
+
return this.regex.exec(val)[1];
|
585
|
+
}
|
586
|
+
},
|
587
|
+
auto: {
|
588
|
+
regex: /^auto$/
|
589
|
+
},
|
590
|
+
textmode: {
|
591
|
+
regex: /textmode\:(.*)/,
|
592
|
+
output: function(val) {
|
593
|
+
return this.regex.exec(val)[1];
|
594
|
+
}
|
595
|
+
},
|
596
|
+
random: {
|
597
|
+
regex: /^random$/
|
598
|
+
},
|
599
|
+
size: {
|
600
|
+
regex: /size\:(\d+)/,
|
601
|
+
output: function(val) {
|
602
|
+
return this.regex.exec(val)[1];
|
603
|
+
}
|
604
|
+
}
|
605
|
+
}
|
606
|
+
};
|
607
|
+
|
608
|
+
/**
|
609
|
+
* Processes provided source attribute and sets up the appropriate rendering workflow
|
610
|
+
*
|
611
|
+
* @private
|
612
|
+
* @param options Instance options from Holder.run
|
613
|
+
* @param renderSettings Instance configuration
|
614
|
+
* @param src Image URL
|
615
|
+
* @param el Image DOM element
|
616
|
+
*/
|
617
|
+
function prepareImageElement(options, engineSettings, src, el) {
|
618
|
+
var holderFlags = parseURL(src.substr(src.lastIndexOf(options.domain)), options);
|
619
|
+
if (holderFlags) {
|
620
|
+
prepareDOMElement({
|
621
|
+
mode: null,
|
622
|
+
el: el,
|
623
|
+
flags: holderFlags,
|
624
|
+
engineSettings: engineSettings
|
625
|
+
});
|
626
|
+
}
|
627
|
+
}
|
628
|
+
|
629
|
+
/**
|
630
|
+
* Processes a Holder URL
|
631
|
+
*
|
632
|
+
* @private
|
633
|
+
* @param url URL
|
634
|
+
* @param options Instance options from Holder.run
|
635
|
+
*/
|
636
|
+
function parseURL(url, options) {
|
637
|
+
var holder = {
|
638
|
+
theme: extend(App.settings.themes.gray, null),
|
639
|
+
stylesheets: options.stylesheets,
|
640
|
+
instanceOptions: options
|
641
|
+
};
|
642
|
+
|
643
|
+
if (url.match(/([\d]+p?)x([\d]+p?)(?:\?|$)/)) {
|
644
|
+
return parseQueryString(url, holder);
|
645
|
+
} else {
|
646
|
+
return parseFlags(url, holder);
|
647
|
+
}
|
648
|
+
}
|
649
|
+
|
650
|
+
/**
|
651
|
+
* Processes a Holder URL and extracts configuration from query string
|
652
|
+
*
|
653
|
+
* @private
|
654
|
+
* @param url URL
|
655
|
+
* @param holder Staging Holder object
|
656
|
+
*/
|
657
|
+
function parseQueryString(url, holder) {
|
658
|
+
var parts = url.split('?');
|
659
|
+
var basics = parts[0].split('/');
|
660
|
+
|
661
|
+
holder.holderURL = url;
|
662
|
+
|
663
|
+
var dimensions = basics[1];
|
664
|
+
var dimensionData = dimensions.match(/([\d]+p?)x([\d]+p?)/);
|
665
|
+
|
666
|
+
if (!dimensionData) return false;
|
667
|
+
|
668
|
+
holder.fluid = dimensions.indexOf('p') !== -1;
|
669
|
+
|
670
|
+
holder.dimensions = {
|
671
|
+
width: dimensionData[1].replace('p', '%'),
|
672
|
+
height: dimensionData[2].replace('p', '%')
|
673
|
+
};
|
674
|
+
|
675
|
+
if (parts.length === 2) {
|
676
|
+
var options = querystring.parse(parts[1]);
|
677
|
+
|
678
|
+
// Colors
|
679
|
+
|
680
|
+
if (options.bg) {
|
681
|
+
holder.theme.background = (options.bg.indexOf('#') === -1 ? '#' : '') + options.bg;
|
682
|
+
}
|
683
|
+
|
684
|
+
if (options.fg) {
|
685
|
+
holder.theme.foreground = (options.fg.indexOf('#') === -1 ? '#' : '') + options.fg;
|
686
|
+
}
|
687
|
+
|
688
|
+
if (options.theme && holder.instanceOptions.themes.hasOwnProperty(options.theme)) {
|
689
|
+
holder.theme = extend(holder.instanceOptions.themes[options.theme], null);
|
690
|
+
}
|
691
|
+
|
692
|
+
// Text
|
693
|
+
|
694
|
+
if (options.text) {
|
695
|
+
holder.text = options.text;
|
696
|
+
}
|
697
|
+
|
698
|
+
if (options.textmode) {
|
699
|
+
holder.textmode = options.textmode;
|
700
|
+
}
|
701
|
+
|
702
|
+
if (options.size) {
|
703
|
+
holder.size = options.size;
|
704
|
+
}
|
705
|
+
|
706
|
+
if (options.font) {
|
707
|
+
holder.font = options.font;
|
708
|
+
}
|
709
|
+
|
710
|
+
if (options.align) {
|
711
|
+
holder.align = options.align;
|
712
|
+
}
|
713
|
+
|
714
|
+
holder.nowrap = utils.truthy(options.nowrap);
|
715
|
+
|
716
|
+
// Miscellaneous
|
717
|
+
|
718
|
+
holder.auto = utils.truthy(options.auto);
|
719
|
+
|
720
|
+
if (utils.truthy(options.random)) {
|
721
|
+
App.vars.cache.themeKeys = App.vars.cache.themeKeys || Object.keys(holder.instanceOptions.themes);
|
722
|
+
var _theme = App.vars.cache.themeKeys[0 | Math.random() * App.vars.cache.themeKeys.length];
|
723
|
+
holder.theme = extend(holder.instanceOptions.themes[_theme], null);
|
724
|
+
}
|
725
|
+
}
|
726
|
+
|
727
|
+
return holder;
|
728
|
+
}
|
729
|
+
|
730
|
+
//todo: remove in 2.8
|
731
|
+
/**
|
732
|
+
* Processes a Holder URL and extracts flags
|
733
|
+
*
|
734
|
+
* @private
|
735
|
+
* @deprecated
|
736
|
+
* @param url URL
|
737
|
+
* @param holder Staging Holder object
|
738
|
+
*/
|
739
|
+
function parseFlags(url, holder) {
|
740
|
+
var render = false;
|
741
|
+
var vtab = String.fromCharCode(11);
|
742
|
+
var flags = url.replace(/([^\\])\//g, '$1' + vtab).split(vtab);
|
743
|
+
var uriRegex = /%[0-9a-f]{2}/gi;
|
744
|
+
var options = holder.instanceOptions;
|
745
|
+
|
746
|
+
holder.holderURL = [];
|
747
|
+
|
748
|
+
for (var fl = flags.length, j = 0; j < fl; j++) {
|
749
|
+
var flag = flags[j];
|
750
|
+
if (flag.match(uriRegex)) {
|
751
|
+
try {
|
752
|
+
flag = decodeURIComponent(flag);
|
753
|
+
} catch (e) {
|
754
|
+
flag = flags[j];
|
755
|
+
}
|
756
|
+
}
|
757
|
+
|
758
|
+
var push = false;
|
759
|
+
|
760
|
+
if (App.flags.dimensions.match(flag)) {
|
761
|
+
render = true;
|
762
|
+
holder.dimensions = App.flags.dimensions.output(flag);
|
763
|
+
push = true;
|
764
|
+
} else if (App.flags.fluid.match(flag)) {
|
765
|
+
render = true;
|
766
|
+
holder.dimensions = App.flags.fluid.output(flag);
|
767
|
+
holder.fluid = true;
|
768
|
+
push = true;
|
769
|
+
} else if (App.flags.textmode.match(flag)) {
|
770
|
+
holder.textmode = App.flags.textmode.output(flag);
|
771
|
+
push = true;
|
772
|
+
} else if (App.flags.colors.match(flag)) {
|
773
|
+
var colors = App.flags.colors.output(flag);
|
774
|
+
holder.theme = extend(holder.theme, colors);
|
775
|
+
push = true;
|
776
|
+
} else if (options.themes[flag]) {
|
777
|
+
//If a theme is specified, it will override custom colors
|
778
|
+
if (options.themes.hasOwnProperty(flag)) {
|
779
|
+
holder.theme = extend(options.themes[flag], null);
|
780
|
+
}
|
781
|
+
push = true;
|
782
|
+
} else if (App.flags.font.match(flag)) {
|
783
|
+
holder.font = App.flags.font.output(flag);
|
784
|
+
push = true;
|
785
|
+
} else if (App.flags.auto.match(flag)) {
|
786
|
+
holder.auto = true;
|
787
|
+
push = true;
|
788
|
+
} else if (App.flags.text.match(flag)) {
|
789
|
+
holder.text = App.flags.text.output(flag);
|
790
|
+
push = true;
|
791
|
+
} else if (App.flags.size.match(flag)) {
|
792
|
+
holder.size = App.flags.size.output(flag);
|
793
|
+
push = true;
|
794
|
+
} else if (App.flags.random.match(flag)) {
|
795
|
+
if (App.vars.cache.themeKeys == null) {
|
796
|
+
App.vars.cache.themeKeys = Object.keys(options.themes);
|
797
|
+
}
|
798
|
+
var theme = App.vars.cache.themeKeys[0 | Math.random() * App.vars.cache.themeKeys.length];
|
799
|
+
holder.theme = extend(options.themes[theme], null);
|
800
|
+
push = true;
|
801
|
+
}
|
802
|
+
|
803
|
+
if (push) {
|
804
|
+
holder.holderURL.push(flag);
|
805
|
+
}
|
806
|
+
}
|
807
|
+
holder.holderURL.unshift(options.domain);
|
808
|
+
holder.holderURL = holder.holderURL.join('/');
|
809
|
+
return render ? holder : false;
|
810
|
+
}
|
811
|
+
|
812
|
+
/**
|
813
|
+
* Modifies the DOM to fit placeholders and sets up resizable image callbacks (for fluid and automatically sized placeholders)
|
814
|
+
*
|
815
|
+
* @private
|
816
|
+
* @param settings DOM prep settings
|
817
|
+
*/
|
818
|
+
function prepareDOMElement(prepSettings) {
|
819
|
+
var mode = prepSettings.mode;
|
820
|
+
var el = prepSettings.el;
|
821
|
+
var flags = prepSettings.flags;
|
822
|
+
var _engineSettings = prepSettings.engineSettings;
|
823
|
+
var dimensions = flags.dimensions,
|
824
|
+
theme = flags.theme;
|
825
|
+
var dimensionsCaption = dimensions.width + 'x' + dimensions.height;
|
826
|
+
mode = mode == null ? (flags.fluid ? 'fluid' : 'image') : mode;
|
827
|
+
|
828
|
+
if (flags.text != null) {
|
829
|
+
theme.text = flags.text;
|
830
|
+
|
831
|
+
//<object> SVG embedding doesn't parse Unicode properly
|
832
|
+
if (el.nodeName.toLowerCase() === 'object') {
|
833
|
+
var textLines = theme.text.split('\\n');
|
834
|
+
for (var k = 0; k < textLines.length; k++) {
|
835
|
+
textLines[k] = utils.encodeHtmlEntity(textLines[k]);
|
836
|
+
}
|
837
|
+
theme.text = textLines.join('\\n');
|
838
|
+
}
|
839
|
+
}
|
840
|
+
|
841
|
+
var holderURL = flags.holderURL;
|
842
|
+
var engineSettings = extend(_engineSettings, null);
|
843
|
+
|
844
|
+
if (flags.font) {
|
845
|
+
theme.font = flags.font;
|
846
|
+
//Only run the <canvas> webfont fallback if noFontFallback is false, if the node is not an image, and if canvas is supported
|
847
|
+
if (!engineSettings.noFontFallback && el.nodeName.toLowerCase() === 'img' && App.setup.supportsCanvas && engineSettings.renderer === 'svg') {
|
848
|
+
engineSettings = extend(engineSettings, {
|
849
|
+
renderer: 'canvas'
|
850
|
+
});
|
851
|
+
}
|
852
|
+
}
|
853
|
+
|
854
|
+
//Chrome and Opera require a quick 10ms re-render if web fonts are used with canvas
|
855
|
+
if (flags.font && engineSettings.renderer == 'canvas') {
|
856
|
+
engineSettings.reRender = true;
|
857
|
+
}
|
858
|
+
|
859
|
+
if (mode == 'background') {
|
860
|
+
if (el.getAttribute('data-background-src') == null) {
|
861
|
+
setAttr(el, {
|
862
|
+
'data-background-src': holderURL
|
863
|
+
});
|
864
|
+
}
|
865
|
+
} else {
|
866
|
+
var domProps = {};
|
867
|
+
domProps[App.vars.dataAttr] = holderURL;
|
868
|
+
setAttr(el, domProps);
|
869
|
+
}
|
870
|
+
|
871
|
+
flags.theme = theme;
|
872
|
+
|
873
|
+
//todo consider using all renderSettings in holderData
|
874
|
+
el.holderData = {
|
875
|
+
flags: flags,
|
876
|
+
engineSettings: engineSettings
|
877
|
+
};
|
878
|
+
|
879
|
+
if (mode == 'image' || mode == 'fluid') {
|
880
|
+
setAttr(el, {
|
881
|
+
'alt': (theme.text ? theme.text + ' [' + dimensionsCaption + ']' : dimensionsCaption)
|
882
|
+
});
|
883
|
+
}
|
884
|
+
|
885
|
+
var renderSettings = {
|
886
|
+
mode: mode,
|
887
|
+
el: el,
|
888
|
+
holderSettings: {
|
889
|
+
dimensions: dimensions,
|
890
|
+
theme: theme,
|
891
|
+
flags: flags
|
892
|
+
},
|
893
|
+
engineSettings: engineSettings
|
894
|
+
};
|
895
|
+
|
896
|
+
if (mode == 'image') {
|
897
|
+
if (engineSettings.renderer == 'html' || !flags.auto) {
|
898
|
+
el.style.width = dimensions.width + 'px';
|
899
|
+
el.style.height = dimensions.height + 'px';
|
900
|
+
}
|
901
|
+
if (engineSettings.renderer == 'html') {
|
902
|
+
el.style.backgroundColor = theme.background;
|
903
|
+
} else {
|
904
|
+
render(renderSettings);
|
905
|
+
|
906
|
+
if (flags.textmode == 'exact') {
|
907
|
+
el.holderData.resizeUpdate = true;
|
908
|
+
App.vars.resizableImages.push(el);
|
909
|
+
updateResizableElements(el);
|
910
|
+
}
|
911
|
+
}
|
912
|
+
} else if (mode == 'background' && engineSettings.renderer != 'html') {
|
913
|
+
render(renderSettings);
|
914
|
+
} else if (mode == 'fluid') {
|
915
|
+
el.holderData.resizeUpdate = true;
|
916
|
+
|
917
|
+
if (dimensions.height.slice(-1) == '%') {
|
918
|
+
el.style.height = dimensions.height;
|
919
|
+
} else if (flags.auto == null || !flags.auto) {
|
920
|
+
el.style.height = dimensions.height + 'px';
|
921
|
+
}
|
922
|
+
if (dimensions.width.slice(-1) == '%') {
|
923
|
+
el.style.width = dimensions.width;
|
924
|
+
} else if (flags.auto == null || !flags.auto) {
|
925
|
+
el.style.width = dimensions.width + 'px';
|
926
|
+
}
|
927
|
+
if (el.style.display == 'inline' || el.style.display === '' || el.style.display == 'none') {
|
928
|
+
el.style.display = 'block';
|
929
|
+
}
|
930
|
+
|
931
|
+
setInitialDimensions(el);
|
932
|
+
|
933
|
+
if (engineSettings.renderer == 'html') {
|
934
|
+
el.style.backgroundColor = theme.background;
|
935
|
+
} else {
|
936
|
+
App.vars.resizableImages.push(el);
|
937
|
+
updateResizableElements(el);
|
938
|
+
}
|
939
|
+
}
|
940
|
+
}
|
941
|
+
|
942
|
+
/**
|
943
|
+
* Core function that takes output from renderers and sets it as the source or background-image of the target element
|
944
|
+
*
|
945
|
+
* @private
|
946
|
+
* @param renderSettings Renderer settings
|
947
|
+
*/
|
948
|
+
function render(renderSettings) {
|
949
|
+
var image = null;
|
950
|
+
var mode = renderSettings.mode;
|
951
|
+
var holderSettings = renderSettings.holderSettings;
|
952
|
+
var el = renderSettings.el;
|
953
|
+
var engineSettings = renderSettings.engineSettings;
|
954
|
+
|
955
|
+
switch (engineSettings.renderer) {
|
956
|
+
case 'svg':
|
957
|
+
if (!App.setup.supportsSVG) return;
|
958
|
+
break;
|
959
|
+
case 'canvas':
|
960
|
+
if (!App.setup.supportsCanvas) return;
|
961
|
+
break;
|
962
|
+
default:
|
963
|
+
return;
|
964
|
+
}
|
965
|
+
|
966
|
+
//todo: move generation of scene up to flag generation to reduce extra object creation
|
967
|
+
var scene = {
|
968
|
+
width: holderSettings.dimensions.width,
|
969
|
+
height: holderSettings.dimensions.height,
|
970
|
+
theme: holderSettings.theme,
|
971
|
+
flags: holderSettings.flags
|
972
|
+
};
|
973
|
+
|
974
|
+
var sceneGraph = buildSceneGraph(scene);
|
975
|
+
|
976
|
+
function getRenderedImage() {
|
977
|
+
var image = null;
|
978
|
+
switch (engineSettings.renderer) {
|
979
|
+
case 'canvas':
|
980
|
+
image = sgCanvasRenderer(sceneGraph, renderSettings);
|
981
|
+
break;
|
982
|
+
case 'svg':
|
983
|
+
image = sgSVGRenderer(sceneGraph, renderSettings);
|
984
|
+
break;
|
985
|
+
default:
|
986
|
+
throw 'Holder: invalid renderer: ' + engineSettings.renderer;
|
987
|
+
}
|
988
|
+
|
989
|
+
return image;
|
990
|
+
}
|
991
|
+
|
992
|
+
image = getRenderedImage();
|
993
|
+
|
994
|
+
if (image == null) {
|
995
|
+
throw 'Holder: couldn\'t render placeholder';
|
996
|
+
}
|
997
|
+
|
998
|
+
//todo: add <object> canvas rendering
|
999
|
+
if (mode == 'background') {
|
1000
|
+
el.style.backgroundImage = 'url(' + image + ')';
|
1001
|
+
el.style.backgroundSize = scene.width + 'px ' + scene.height + 'px';
|
1002
|
+
} else {
|
1003
|
+
if (el.nodeName.toLowerCase() === 'img') {
|
1004
|
+
setAttr(el, {
|
1005
|
+
'src': image
|
1006
|
+
});
|
1007
|
+
} else if (el.nodeName.toLowerCase() === 'object') {
|
1008
|
+
setAttr(el, {
|
1009
|
+
'data': image
|
1010
|
+
});
|
1011
|
+
setAttr(el, {
|
1012
|
+
'type': 'image/svg+xml'
|
1013
|
+
});
|
1014
|
+
}
|
1015
|
+
if (engineSettings.reRender) {
|
1016
|
+
global.setTimeout(function() {
|
1017
|
+
var image = getRenderedImage();
|
1018
|
+
if (image == null) {
|
1019
|
+
throw 'Holder: couldn\'t render placeholder';
|
1020
|
+
}
|
1021
|
+
//todo: refactor this code into a function
|
1022
|
+
if (el.nodeName.toLowerCase() === 'img') {
|
1023
|
+
setAttr(el, {
|
1024
|
+
'src': image
|
1025
|
+
});
|
1026
|
+
} else if (el.nodeName.toLowerCase() === 'object') {
|
1027
|
+
setAttr(el, {
|
1028
|
+
'data': image
|
1029
|
+
});
|
1030
|
+
setAttr(el, {
|
1031
|
+
'type': 'image/svg+xml'
|
1032
|
+
});
|
1033
|
+
}
|
1034
|
+
}, 100);
|
1035
|
+
}
|
1036
|
+
}
|
1037
|
+
//todo: account for re-rendering
|
1038
|
+
setAttr(el, {
|
1039
|
+
'data-holder-rendered': true
|
1040
|
+
});
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
/**
|
1044
|
+
* Core function that takes a Holder scene description and builds a scene graph
|
1045
|
+
*
|
1046
|
+
* @private
|
1047
|
+
* @param scene Holder scene object
|
1048
|
+
*/
|
1049
|
+
//todo: make this function reusable
|
1050
|
+
//todo: merge app defaults and setup properties into the scene argument
|
1051
|
+
function buildSceneGraph(scene) {
|
1052
|
+
var fontSize = App.defaults.size;
|
1053
|
+
if (parseFloat(scene.theme.size)) {
|
1054
|
+
fontSize = scene.theme.size;
|
1055
|
+
} else if (parseFloat(scene.flags.size)) {
|
1056
|
+
fontSize = scene.flags.size;
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
scene.font = {
|
1060
|
+
family: scene.theme.font ? scene.theme.font : 'Arial, Helvetica, Open Sans, sans-serif',
|
1061
|
+
size: textSize(scene.width, scene.height, fontSize),
|
1062
|
+
units: scene.theme.units ? scene.theme.units : App.defaults.units,
|
1063
|
+
weight: scene.theme.fontweight ? scene.theme.fontweight : 'bold'
|
1064
|
+
};
|
1065
|
+
|
1066
|
+
scene.text = scene.theme.text || Math.floor(scene.width) + 'x' + Math.floor(scene.height);
|
1067
|
+
|
1068
|
+
scene.noWrap = scene.theme.nowrap || scene.flags.nowrap;
|
1069
|
+
|
1070
|
+
scene.align = scene.theme.align || scene.flags.align || 'center';
|
1071
|
+
|
1072
|
+
switch (scene.flags.textmode) {
|
1073
|
+
case 'literal':
|
1074
|
+
scene.text = scene.flags.dimensions.width + 'x' + scene.flags.dimensions.height;
|
1075
|
+
break;
|
1076
|
+
case 'exact':
|
1077
|
+
if (!scene.flags.exactDimensions) break;
|
1078
|
+
scene.text = Math.floor(scene.flags.exactDimensions.width) + 'x' + Math.floor(scene.flags.exactDimensions.height);
|
1079
|
+
break;
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
var sceneGraph = new SceneGraph({
|
1083
|
+
width: scene.width,
|
1084
|
+
height: scene.height
|
1085
|
+
});
|
1086
|
+
|
1087
|
+
var Shape = sceneGraph.Shape;
|
1088
|
+
|
1089
|
+
var holderBg = new Shape.Rect('holderBg', {
|
1090
|
+
fill: scene.theme.background
|
1091
|
+
});
|
1092
|
+
|
1093
|
+
holderBg.resize(scene.width, scene.height);
|
1094
|
+
sceneGraph.root.add(holderBg);
|
1095
|
+
|
1096
|
+
var holderTextGroup = new Shape.Group('holderTextGroup', {
|
1097
|
+
text: scene.text,
|
1098
|
+
align: scene.align,
|
1099
|
+
font: scene.font,
|
1100
|
+
fill: scene.theme.foreground
|
1101
|
+
});
|
1102
|
+
|
1103
|
+
holderTextGroup.moveTo(null, null, 1);
|
1104
|
+
sceneGraph.root.add(holderTextGroup);
|
1105
|
+
|
1106
|
+
var tpdata = holderTextGroup.textPositionData = stagingRenderer(sceneGraph);
|
1107
|
+
if (!tpdata) {
|
1108
|
+
throw 'Holder: staging fallback not supported yet.';
|
1109
|
+
}
|
1110
|
+
holderTextGroup.properties.leading = tpdata.boundingBox.height;
|
1111
|
+
|
1112
|
+
var textNode = null;
|
1113
|
+
var line = null;
|
1114
|
+
|
1115
|
+
function finalizeLine(parent, line, width, height) {
|
1116
|
+
line.width = width;
|
1117
|
+
line.height = height;
|
1118
|
+
parent.width = Math.max(parent.width, line.width);
|
1119
|
+
parent.height += line.height;
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
var sceneMargin = scene.width * App.setup.lineWrapRatio;
|
1123
|
+
var maxLineWidth = sceneMargin;
|
1124
|
+
|
1125
|
+
if (tpdata.lineCount > 1) {
|
1126
|
+
var offsetX = 0;
|
1127
|
+
var offsetY = 0;
|
1128
|
+
var lineIndex = 0;
|
1129
|
+
var lineKey;
|
1130
|
+
line = new Shape.Group('line' + lineIndex);
|
1131
|
+
|
1132
|
+
//Double margin so that left/right-aligned next is not flush with edge of image
|
1133
|
+
if (scene.align === 'left' || scene.align === 'right') {
|
1134
|
+
maxLineWidth = scene.width * (1 - (1 - (App.setup.lineWrapRatio)) * 2);
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
for (var i = 0; i < tpdata.words.length; i++) {
|
1138
|
+
var word = tpdata.words[i];
|
1139
|
+
textNode = new Shape.Text(word.text);
|
1140
|
+
var newline = word.text == '\\n';
|
1141
|
+
if (!scene.noWrap && (offsetX + word.width >= maxLineWidth || newline === true)) {
|
1142
|
+
finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading);
|
1143
|
+
holderTextGroup.add(line);
|
1144
|
+
offsetX = 0;
|
1145
|
+
offsetY += holderTextGroup.properties.leading;
|
1146
|
+
lineIndex += 1;
|
1147
|
+
line = new Shape.Group('line' + lineIndex);
|
1148
|
+
line.y = offsetY;
|
1149
|
+
}
|
1150
|
+
if (newline === true) {
|
1151
|
+
continue;
|
1152
|
+
}
|
1153
|
+
textNode.moveTo(offsetX, 0);
|
1154
|
+
offsetX += tpdata.spaceWidth + word.width;
|
1155
|
+
line.add(textNode);
|
1156
|
+
}
|
1157
|
+
|
1158
|
+
finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading);
|
1159
|
+
holderTextGroup.add(line);
|
1160
|
+
|
1161
|
+
if (scene.align === 'left') {
|
1162
|
+
holderTextGroup.moveTo(scene.width - sceneMargin, null, null);
|
1163
|
+
} else if (scene.align === 'right') {
|
1164
|
+
for (lineKey in holderTextGroup.children) {
|
1165
|
+
line = holderTextGroup.children[lineKey];
|
1166
|
+
line.moveTo(scene.width - line.width, null, null);
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null);
|
1170
|
+
} else {
|
1171
|
+
for (lineKey in holderTextGroup.children) {
|
1172
|
+
line = holderTextGroup.children[lineKey];
|
1173
|
+
line.moveTo((holderTextGroup.width - line.width) / 2, null, null);
|
1174
|
+
}
|
1175
|
+
|
1176
|
+
holderTextGroup.moveTo((scene.width - holderTextGroup.width) / 2, null, null);
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
holderTextGroup.moveTo(null, (scene.height - holderTextGroup.height) / 2, null);
|
1180
|
+
|
1181
|
+
//If the text exceeds vertical space, move it down so the first line is visible
|
1182
|
+
if ((scene.height - holderTextGroup.height) / 2 < 0) {
|
1183
|
+
holderTextGroup.moveTo(null, 0, null);
|
1184
|
+
}
|
1185
|
+
} else {
|
1186
|
+
textNode = new Shape.Text(scene.text);
|
1187
|
+
line = new Shape.Group('line0');
|
1188
|
+
line.add(textNode);
|
1189
|
+
holderTextGroup.add(line);
|
1190
|
+
|
1191
|
+
if (scene.align === 'left') {
|
1192
|
+
holderTextGroup.moveTo(scene.width - sceneMargin, null, null);
|
1193
|
+
} else if (scene.align === 'right') {
|
1194
|
+
holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null);
|
1195
|
+
} else {
|
1196
|
+
holderTextGroup.moveTo((scene.width - tpdata.boundingBox.width) / 2, null, null);
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
holderTextGroup.moveTo(null, (scene.height - tpdata.boundingBox.height) / 2, null);
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
//todo: renderlist
|
1203
|
+
|
1204
|
+
return sceneGraph;
|
1205
|
+
}
|
1206
|
+
|
1207
|
+
/**
|
1208
|
+
* Adaptive text sizing function
|
1209
|
+
*
|
1210
|
+
* @private
|
1211
|
+
* @param width Parent width
|
1212
|
+
* @param height Parent height
|
1213
|
+
* @param fontSize Requested text size
|
1214
|
+
*/
|
1215
|
+
function textSize(width, height, fontSize) {
|
1216
|
+
var stageWidth = parseInt(width, 10);
|
1217
|
+
var stageHeight = parseInt(height, 10);
|
1218
|
+
|
1219
|
+
var bigSide = Math.max(stageWidth, stageHeight);
|
1220
|
+
var smallSide = Math.min(stageWidth, stageHeight);
|
1221
|
+
|
1222
|
+
var newHeight = 0.8 * Math.min(smallSide, bigSide * App.defaults.scale);
|
1223
|
+
return Math.round(Math.max(fontSize, newHeight));
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
/**
|
1227
|
+
* Iterates over resizable (fluid or auto) placeholders and renders them
|
1228
|
+
*
|
1229
|
+
* @private
|
1230
|
+
* @param element Optional element selector, specified only if a specific element needs to be re-rendered
|
1231
|
+
*/
|
1232
|
+
function updateResizableElements(element) {
|
1233
|
+
var images;
|
1234
|
+
if (element == null || element.nodeType == null) {
|
1235
|
+
images = App.vars.resizableImages;
|
1236
|
+
} else {
|
1237
|
+
images = [element];
|
1238
|
+
}
|
1239
|
+
for (var i = 0, l = images.length; i < l; i++) {
|
1240
|
+
var el = images[i];
|
1241
|
+
if (el.holderData) {
|
1242
|
+
var flags = el.holderData.flags;
|
1243
|
+
var dimensions = dimensionCheck(el);
|
1244
|
+
if (dimensions) {
|
1245
|
+
if (!el.holderData.resizeUpdate) {
|
1246
|
+
continue;
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
if (flags.fluid && flags.auto) {
|
1250
|
+
var fluidConfig = el.holderData.fluidConfig;
|
1251
|
+
switch (fluidConfig.mode) {
|
1252
|
+
case 'width':
|
1253
|
+
dimensions.height = dimensions.width / fluidConfig.ratio;
|
1254
|
+
break;
|
1255
|
+
case 'height':
|
1256
|
+
dimensions.width = dimensions.height * fluidConfig.ratio;
|
1257
|
+
break;
|
1258
|
+
}
|
1259
|
+
}
|
1260
|
+
|
1261
|
+
var settings = {
|
1262
|
+
mode: 'image',
|
1263
|
+
holderSettings: {
|
1264
|
+
dimensions: dimensions,
|
1265
|
+
theme: flags.theme,
|
1266
|
+
flags: flags
|
1267
|
+
},
|
1268
|
+
el: el,
|
1269
|
+
engineSettings: el.holderData.engineSettings
|
1270
|
+
};
|
1271
|
+
|
1272
|
+
if (flags.textmode == 'exact') {
|
1273
|
+
flags.exactDimensions = dimensions;
|
1274
|
+
settings.holderSettings.dimensions = flags.dimensions;
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
render(settings);
|
1278
|
+
} else {
|
1279
|
+
setInvisible(el);
|
1280
|
+
}
|
1281
|
+
}
|
1282
|
+
}
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
/**
|
1286
|
+
* Sets up aspect ratio metadata for fluid placeholders, in order to preserve proportions when resizing
|
1287
|
+
*
|
1288
|
+
* @private
|
1289
|
+
* @param el Image DOM element
|
1290
|
+
*/
|
1291
|
+
function setInitialDimensions(el) {
|
1292
|
+
if (el.holderData) {
|
1293
|
+
var dimensions = dimensionCheck(el);
|
1294
|
+
if (dimensions) {
|
1295
|
+
var flags = el.holderData.flags;
|
1296
|
+
|
1297
|
+
var fluidConfig = {
|
1298
|
+
fluidHeight: flags.dimensions.height.slice(-1) == '%',
|
1299
|
+
fluidWidth: flags.dimensions.width.slice(-1) == '%',
|
1300
|
+
mode: null,
|
1301
|
+
initialDimensions: dimensions
|
1302
|
+
};
|
1303
|
+
|
1304
|
+
if (fluidConfig.fluidWidth && !fluidConfig.fluidHeight) {
|
1305
|
+
fluidConfig.mode = 'width';
|
1306
|
+
fluidConfig.ratio = fluidConfig.initialDimensions.width / parseFloat(flags.dimensions.height);
|
1307
|
+
} else if (!fluidConfig.fluidWidth && fluidConfig.fluidHeight) {
|
1308
|
+
fluidConfig.mode = 'height';
|
1309
|
+
fluidConfig.ratio = parseFloat(flags.dimensions.width) / fluidConfig.initialDimensions.height;
|
1310
|
+
}
|
1311
|
+
|
1312
|
+
el.holderData.fluidConfig = fluidConfig;
|
1313
|
+
} else {
|
1314
|
+
setInvisible(el);
|
1315
|
+
}
|
1316
|
+
}
|
1317
|
+
}
|
1318
|
+
|
1319
|
+
/**
|
1320
|
+
* Iterates through all current invisible images, and if they're visible, renders them and removes them from further checks. Runs every animation frame.
|
1321
|
+
*
|
1322
|
+
* @private
|
1323
|
+
*/
|
1324
|
+
function visibilityCheck() {
|
1325
|
+
var renderableImages = [];
|
1326
|
+
var keys = Object.keys(App.vars.invisibleImages);
|
1327
|
+
var el;
|
1328
|
+
for (var i = 0, l = keys.length; i < l; i++) {
|
1329
|
+
el = App.vars.invisibleImages[keys[i]];
|
1330
|
+
if (dimensionCheck(el) && el.nodeName.toLowerCase() == 'img') {
|
1331
|
+
renderableImages.push(el);
|
1332
|
+
delete App.vars.invisibleImages[keys[i]];
|
1333
|
+
}
|
1334
|
+
}
|
1335
|
+
|
1336
|
+
if (renderableImages.length) {
|
1337
|
+
Holder.run({
|
1338
|
+
images: renderableImages
|
1339
|
+
});
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
global.requestAnimationFrame(visibilityCheck);
|
1343
|
+
}
|
1344
|
+
|
1345
|
+
/**
|
1346
|
+
* Starts checking for invisible placeholders if not doing so yet. Does nothing otherwise.
|
1347
|
+
*
|
1348
|
+
* @private
|
1349
|
+
*/
|
1350
|
+
function startVisibilityCheck() {
|
1351
|
+
if (!App.vars.visibilityCheckStarted) {
|
1352
|
+
global.requestAnimationFrame(visibilityCheck);
|
1353
|
+
App.vars.visibilityCheckStarted = true;
|
1354
|
+
}
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
/**
|
1358
|
+
* Sets a unique ID for an image detected to be invisible and adds it to the map of invisible images checked by visibilityCheck
|
1359
|
+
*
|
1360
|
+
* @private
|
1361
|
+
* @param el Invisible DOM element
|
1362
|
+
*/
|
1363
|
+
function setInvisible(el) {
|
1364
|
+
if (!el.holderData.invisibleId) {
|
1365
|
+
App.vars.invisibleId += 1;
|
1366
|
+
App.vars.invisibleImages['i' + App.vars.invisibleId] = el;
|
1367
|
+
el.holderData.invisibleId = App.vars.invisibleId;
|
1368
|
+
}
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
//todo: see if possible to convert stagingRenderer to use HTML only
|
1372
|
+
var stagingRenderer = (function() {
|
1373
|
+
var svg = null,
|
1374
|
+
stagingText = null,
|
1375
|
+
stagingTextNode = null;
|
1376
|
+
return function(graph) {
|
1377
|
+
var rootNode = graph.root;
|
1378
|
+
if (App.setup.supportsSVG) {
|
1379
|
+
var firstTimeSetup = false;
|
1380
|
+
var tnode = function(text) {
|
1381
|
+
return document.createTextNode(text);
|
1382
|
+
};
|
1383
|
+
if (svg == null || svg.parentNode !== document.body) {
|
1384
|
+
firstTimeSetup = true;
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
svg = initSVG(svg, rootNode.properties.width, rootNode.properties.height);
|
1388
|
+
//Show staging element before staging
|
1389
|
+
svg.style.display = 'block';
|
1390
|
+
|
1391
|
+
if (firstTimeSetup) {
|
1392
|
+
stagingText = newEl('text', SVG_NS);
|
1393
|
+
stagingTextNode = tnode(null);
|
1394
|
+
setAttr(stagingText, {
|
1395
|
+
x: 0
|
1396
|
+
});
|
1397
|
+
stagingText.appendChild(stagingTextNode);
|
1398
|
+
svg.appendChild(stagingText);
|
1399
|
+
document.body.appendChild(svg);
|
1400
|
+
svg.style.visibility = 'hidden';
|
1401
|
+
svg.style.position = 'absolute';
|
1402
|
+
svg.style.top = '-100%';
|
1403
|
+
svg.style.left = '-100%';
|
1404
|
+
//todo: workaround for zero-dimension <svg> tag in Opera 12
|
1405
|
+
//svg.setAttribute('width', 0);
|
1406
|
+
//svg.setAttribute('height', 0);
|
1407
|
+
}
|
1408
|
+
|
1409
|
+
var holderTextGroup = rootNode.children.holderTextGroup;
|
1410
|
+
var htgProps = holderTextGroup.properties;
|
1411
|
+
setAttr(stagingText, {
|
1412
|
+
'y': htgProps.font.size,
|
1413
|
+
'style': utils.cssProps({
|
1414
|
+
'font-weight': htgProps.font.weight,
|
1415
|
+
'font-size': htgProps.font.size + htgProps.font.units,
|
1416
|
+
'font-family': htgProps.font.family
|
1417
|
+
})
|
1418
|
+
});
|
1419
|
+
|
1420
|
+
//Get bounding box for the whole string (total width and height)
|
1421
|
+
stagingTextNode.nodeValue = htgProps.text;
|
1422
|
+
var stagingTextBBox = stagingText.getBBox();
|
1423
|
+
|
1424
|
+
//Get line count and split the string into words
|
1425
|
+
var lineCount = Math.ceil(stagingTextBBox.width / (rootNode.properties.width * App.setup.lineWrapRatio));
|
1426
|
+
var words = htgProps.text.split(' ');
|
1427
|
+
var newlines = htgProps.text.match(/\\n/g);
|
1428
|
+
lineCount += newlines == null ? 0 : newlines.length;
|
1429
|
+
|
1430
|
+
//Get bounding box for the string with spaces removed
|
1431
|
+
stagingTextNode.nodeValue = htgProps.text.replace(/[ ]+/g, '');
|
1432
|
+
var computedNoSpaceLength = stagingText.getComputedTextLength();
|
1433
|
+
|
1434
|
+
//Compute average space width
|
1435
|
+
var diffLength = stagingTextBBox.width - computedNoSpaceLength;
|
1436
|
+
var spaceWidth = Math.round(diffLength / Math.max(1, words.length - 1));
|
1437
|
+
|
1438
|
+
//Get widths for every word with space only if there is more than one line
|
1439
|
+
var wordWidths = [];
|
1440
|
+
if (lineCount > 1) {
|
1441
|
+
stagingTextNode.nodeValue = '';
|
1442
|
+
for (var i = 0; i < words.length; i++) {
|
1443
|
+
if (words[i].length === 0) continue;
|
1444
|
+
stagingTextNode.nodeValue = utils.decodeHtmlEntity(words[i]);
|
1445
|
+
var bbox = stagingText.getBBox();
|
1446
|
+
wordWidths.push({
|
1447
|
+
text: words[i],
|
1448
|
+
width: bbox.width
|
1449
|
+
});
|
1450
|
+
}
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
//Hide staging element after staging
|
1454
|
+
svg.style.display = 'none';
|
1455
|
+
|
1456
|
+
return {
|
1457
|
+
spaceWidth: spaceWidth,
|
1458
|
+
lineCount: lineCount,
|
1459
|
+
boundingBox: stagingTextBBox,
|
1460
|
+
words: wordWidths
|
1461
|
+
};
|
1462
|
+
} else {
|
1463
|
+
//todo: canvas fallback for measuring text on android 2.3
|
1464
|
+
return false;
|
1465
|
+
}
|
1466
|
+
};
|
1467
|
+
})();
|
1468
|
+
|
1469
|
+
var sgCanvasRenderer = (function() {
|
1470
|
+
var canvas = newEl('canvas');
|
1471
|
+
var ctx = null;
|
1472
|
+
|
1473
|
+
return function(sceneGraph) {
|
1474
|
+
if (ctx == null) {
|
1475
|
+
ctx = canvas.getContext('2d');
|
1476
|
+
}
|
1477
|
+
var root = sceneGraph.root;
|
1478
|
+
canvas.width = App.dpr(root.properties.width);
|
1479
|
+
canvas.height = App.dpr(root.properties.height);
|
1480
|
+
ctx.textBaseline = 'middle';
|
1481
|
+
|
1482
|
+
ctx.fillStyle = root.children.holderBg.properties.fill;
|
1483
|
+
ctx.fillRect(0, 0, App.dpr(root.children.holderBg.width), App.dpr(root.children.holderBg.height));
|
1484
|
+
|
1485
|
+
var textGroup = root.children.holderTextGroup;
|
1486
|
+
var tgProps = textGroup.properties;
|
1487
|
+
ctx.font = textGroup.properties.font.weight + ' ' + App.dpr(textGroup.properties.font.size) + textGroup.properties.font.units + ' ' + textGroup.properties.font.family + ', monospace';
|
1488
|
+
ctx.fillStyle = textGroup.properties.fill;
|
1489
|
+
|
1490
|
+
for (var lineKey in textGroup.children) {
|
1491
|
+
var line = textGroup.children[lineKey];
|
1492
|
+
for (var wordKey in line.children) {
|
1493
|
+
var word = line.children[wordKey];
|
1494
|
+
var x = App.dpr(textGroup.x + line.x + word.x);
|
1495
|
+
var y = App.dpr(textGroup.y + line.y + word.y + (textGroup.properties.leading / 2));
|
1496
|
+
|
1497
|
+
ctx.fillText(word.properties.text, x, y);
|
1498
|
+
}
|
1499
|
+
}
|
1500
|
+
|
1501
|
+
return canvas.toDataURL('image/png');
|
1502
|
+
};
|
1503
|
+
})();
|
1504
|
+
|
1505
|
+
var sgSVGRenderer = (function() {
|
1506
|
+
//Prevent IE <9 from initializing SVG renderer
|
1507
|
+
if (!global.XMLSerializer) return;
|
1508
|
+
var xml = createXML();
|
1509
|
+
var svg = initSVG(null, 0, 0);
|
1510
|
+
var bgEl = newEl('rect', SVG_NS);
|
1511
|
+
svg.appendChild(bgEl);
|
1512
|
+
|
1513
|
+
//todo: create a reusable pool for textNodes, resize if more words present
|
1514
|
+
|
1515
|
+
return function(sceneGraph, renderSettings) {
|
1516
|
+
var root = sceneGraph.root;
|
1517
|
+
|
1518
|
+
initSVG(svg, root.properties.width, root.properties.height);
|
1519
|
+
|
1520
|
+
var groups = svg.querySelectorAll('g');
|
1521
|
+
|
1522
|
+
for (var i = 0; i < groups.length; i++) {
|
1523
|
+
groups[i].parentNode.removeChild(groups[i]);
|
1524
|
+
}
|
1525
|
+
|
1526
|
+
var holderURL = renderSettings.holderSettings.flags.holderURL;
|
1527
|
+
var holderId = 'holder_' + (Number(new Date()) + 32768 + (0 | Math.random() * 32768)).toString(16);
|
1528
|
+
var sceneGroupEl = newEl('g', SVG_NS);
|
1529
|
+
var textGroup = root.children.holderTextGroup;
|
1530
|
+
var tgProps = textGroup.properties;
|
1531
|
+
var textGroupEl = newEl('g', SVG_NS);
|
1532
|
+
var tpdata = textGroup.textPositionData;
|
1533
|
+
var textCSSRule = '#' + holderId + ' text { ' +
|
1534
|
+
utils.cssProps({
|
1535
|
+
'fill': tgProps.fill,
|
1536
|
+
'font-weight': tgProps.font.weight,
|
1537
|
+
'font-family': tgProps.font.family + ', monospace',
|
1538
|
+
'font-size': tgProps.font.size + tgProps.font.units
|
1539
|
+
}) + ' } ';
|
1540
|
+
var commentNode = xml.createComment('\n' + 'Source URL: ' + holderURL + generatorComment);
|
1541
|
+
var holderCSS = xml.createCDATASection(textCSSRule);
|
1542
|
+
var styleEl = svg.querySelector('style');
|
1543
|
+
|
1544
|
+
setAttr(sceneGroupEl, {
|
1545
|
+
id: holderId
|
1546
|
+
});
|
1547
|
+
|
1548
|
+
svg.insertBefore(commentNode, svg.firstChild);
|
1549
|
+
styleEl.appendChild(holderCSS);
|
1550
|
+
|
1551
|
+
sceneGroupEl.appendChild(bgEl);
|
1552
|
+
sceneGroupEl.appendChild(textGroupEl);
|
1553
|
+
svg.appendChild(sceneGroupEl);
|
1554
|
+
|
1555
|
+
setAttr(bgEl, {
|
1556
|
+
'width': root.children.holderBg.width,
|
1557
|
+
'height': root.children.holderBg.height,
|
1558
|
+
'fill': root.children.holderBg.properties.fill
|
1559
|
+
});
|
1560
|
+
|
1561
|
+
textGroup.y += tpdata.boundingBox.height * 0.8;
|
1562
|
+
|
1563
|
+
for (var lineKey in textGroup.children) {
|
1564
|
+
var line = textGroup.children[lineKey];
|
1565
|
+
for (var wordKey in line.children) {
|
1566
|
+
var word = line.children[wordKey];
|
1567
|
+
var x = textGroup.x + line.x + word.x;
|
1568
|
+
var y = textGroup.y + line.y + word.y;
|
1569
|
+
|
1570
|
+
var textEl = newEl('text', SVG_NS);
|
1571
|
+
var textNode = document.createTextNode(null);
|
1572
|
+
|
1573
|
+
setAttr(textEl, {
|
1574
|
+
'x': x,
|
1575
|
+
'y': y
|
1576
|
+
});
|
1577
|
+
|
1578
|
+
textNode.nodeValue = word.properties.text;
|
1579
|
+
textEl.appendChild(textNode);
|
1580
|
+
textGroupEl.appendChild(textEl);
|
1581
|
+
}
|
1582
|
+
}
|
1583
|
+
|
1584
|
+
//todo: factor the background check up the chain, perhaps only return reference
|
1585
|
+
var svgString = svgStringToDataURI(serializeSVG(svg, renderSettings.engineSettings), renderSettings.mode === 'background');
|
1586
|
+
return svgString;
|
1587
|
+
};
|
1588
|
+
})();
|
1589
|
+
|
1590
|
+
//Helpers
|
1591
|
+
|
1592
|
+
//todo: move svg-related helpers to a dedicated file
|
1593
|
+
|
1594
|
+
/**
|
1595
|
+
* Converts serialized SVG to a string suitable for data URI use
|
1596
|
+
* @param svgString Serialized SVG string
|
1597
|
+
* @param [base64] Use base64 encoding for data URI
|
1598
|
+
*/
|
1599
|
+
var svgStringToDataURI = function() {
|
1600
|
+
var rawPrefix = 'data:image/svg+xml;charset=UTF-8,';
|
1601
|
+
var base64Prefix = 'data:image/svg+xml;charset=UTF-8;base64,';
|
1602
|
+
|
1603
|
+
return function(svgString, base64) {
|
1604
|
+
if (base64) {
|
1605
|
+
return base64Prefix + btoa(unescape(encodeURIComponent(svgString)));
|
1606
|
+
} else {
|
1607
|
+
return rawPrefix + encodeURIComponent(svgString);
|
1608
|
+
}
|
1609
|
+
};
|
1610
|
+
}();
|
1611
|
+
|
1612
|
+
/**
|
1613
|
+
* Generic new DOM element function
|
1614
|
+
*
|
1615
|
+
* @private
|
1616
|
+
* @param tag Tag to create
|
1617
|
+
* @param namespace Optional namespace value
|
1618
|
+
*/
|
1619
|
+
function newEl(tag, namespace) {
|
1620
|
+
if (namespace == null) {
|
1621
|
+
return document.createElement(tag);
|
1622
|
+
} else {
|
1623
|
+
return document.createElementNS(namespace, tag);
|
1624
|
+
}
|
1625
|
+
}
|
1626
|
+
|
1627
|
+
/**
|
1628
|
+
* Generic setAttribute function
|
1629
|
+
*
|
1630
|
+
* @private
|
1631
|
+
* @param el Reference to DOM element
|
1632
|
+
* @param attrs Object with attribute keys and values
|
1633
|
+
*/
|
1634
|
+
function setAttr(el, attrs) {
|
1635
|
+
for (var a in attrs) {
|
1636
|
+
el.setAttribute(a, attrs[a]);
|
1637
|
+
}
|
1638
|
+
}
|
1639
|
+
|
1640
|
+
/**
|
1641
|
+
* Generic SVG element creation function
|
1642
|
+
*
|
1643
|
+
* @private
|
1644
|
+
* @param svg SVG context, set to null if new
|
1645
|
+
* @param width Document width
|
1646
|
+
* @param height Document height
|
1647
|
+
*/
|
1648
|
+
function initSVG(svg, width, height) {
|
1649
|
+
var defs, style;
|
1650
|
+
|
1651
|
+
if (svg == null) {
|
1652
|
+
svg = newEl('svg', SVG_NS);
|
1653
|
+
defs = newEl('defs', SVG_NS);
|
1654
|
+
style = newEl('style', SVG_NS);
|
1655
|
+
setAttr(style, {
|
1656
|
+
'type': 'text/css'
|
1657
|
+
});
|
1658
|
+
defs.appendChild(style);
|
1659
|
+
svg.appendChild(defs);
|
1660
|
+
} else {
|
1661
|
+
style = svg.querySelector('style');
|
1662
|
+
}
|
1663
|
+
|
1664
|
+
//IE throws an exception if this is set and Chrome requires it to be set
|
1665
|
+
if (svg.webkitMatchesSelector) {
|
1666
|
+
svg.setAttribute('xmlns', SVG_NS);
|
1667
|
+
}
|
1668
|
+
|
1669
|
+
//Remove comment nodes
|
1670
|
+
for (var i = 0; i < svg.childNodes.length; i++) {
|
1671
|
+
if (svg.childNodes[i].nodeType === NODE_TYPE_COMMENT) {
|
1672
|
+
svg.removeChild(svg.childNodes[i]);
|
1673
|
+
}
|
1674
|
+
}
|
1675
|
+
|
1676
|
+
//Remove CSS
|
1677
|
+
while (style.childNodes.length) {
|
1678
|
+
style.removeChild(style.childNodes[0]);
|
1679
|
+
}
|
1680
|
+
|
1681
|
+
setAttr(svg, {
|
1682
|
+
'width': width,
|
1683
|
+
'height': height,
|
1684
|
+
'viewBox': '0 0 ' + width + ' ' + height,
|
1685
|
+
'preserveAspectRatio': 'none'
|
1686
|
+
});
|
1687
|
+
|
1688
|
+
return svg;
|
1689
|
+
}
|
1690
|
+
|
1691
|
+
/**
|
1692
|
+
* Returns serialized SVG with XML processing instructions
|
1693
|
+
*
|
1694
|
+
* @private
|
1695
|
+
* @param svg SVG context
|
1696
|
+
* @param stylesheets CSS stylesheets to include
|
1697
|
+
*/
|
1698
|
+
function serializeSVG(svg, engineSettings) {
|
1699
|
+
if (!global.XMLSerializer) return;
|
1700
|
+
var serializer = new XMLSerializer();
|
1701
|
+
var svgCSS = '';
|
1702
|
+
var stylesheets = engineSettings.stylesheets;
|
1703
|
+
|
1704
|
+
//External stylesheets: Processing Instruction method
|
1705
|
+
if (engineSettings.svgXMLStylesheet) {
|
1706
|
+
var xml = createXML();
|
1707
|
+
//Add <?xml-stylesheet ?> directives
|
1708
|
+
for (var i = stylesheets.length - 1; i >= 0; i--) {
|
1709
|
+
var csspi = xml.createProcessingInstruction('xml-stylesheet', 'href="' + stylesheets[i] + '" rel="stylesheet"');
|
1710
|
+
xml.insertBefore(csspi, xml.firstChild);
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
xml.removeChild(xml.documentElement);
|
1714
|
+
svgCSS = serializer.serializeToString(xml);
|
1715
|
+
}
|
1716
|
+
|
1717
|
+
var svgText = serializer.serializeToString(svg);
|
1718
|
+
svgText = svgText.replace(/\&(\#[0-9]{2,}\;)/g, '&$1');
|
1719
|
+
return svgCSS + svgText;
|
1720
|
+
}
|
1721
|
+
|
1722
|
+
/**
|
1723
|
+
* Creates a XML document
|
1724
|
+
* @private
|
1725
|
+
*/
|
1726
|
+
function createXML() {
|
1727
|
+
if (!global.DOMParser) return;
|
1728
|
+
return new DOMParser().parseFromString('<xml />', 'application/xml');
|
1729
|
+
}
|
1730
|
+
|
1731
|
+
/**
|
1732
|
+
* Prevents a function from being called too often, waits until a timer elapses to call it again
|
1733
|
+
*
|
1734
|
+
* @param fn Function to call
|
1735
|
+
*/
|
1736
|
+
function debounce(fn) {
|
1737
|
+
if (!App.vars.debounceTimer) fn.call(this);
|
1738
|
+
if (App.vars.debounceTimer) global.clearTimeout(App.vars.debounceTimer);
|
1739
|
+
App.vars.debounceTimer = global.setTimeout(function() {
|
1740
|
+
App.vars.debounceTimer = null;
|
1741
|
+
fn.call(this);
|
1742
|
+
}, App.setup.debounce);
|
1743
|
+
}
|
1744
|
+
|
1745
|
+
/**
|
1746
|
+
* Holder-specific resize/orientation change callback, debounced to prevent excessive execution
|
1747
|
+
*/
|
1748
|
+
function resizeEvent() {
|
1749
|
+
debounce(function() {
|
1750
|
+
updateResizableElements(null);
|
1751
|
+
});
|
1752
|
+
}
|
1753
|
+
|
1754
|
+
//Set up flags
|
1755
|
+
|
1756
|
+
for (var flag in App.flags) {
|
1757
|
+
if (!App.flags.hasOwnProperty(flag)) continue;
|
1758
|
+
App.flags[flag].match = function(val) {
|
1759
|
+
return val.match(this.regex);
|
1760
|
+
};
|
1761
|
+
}
|
1762
|
+
|
1763
|
+
//Properties set once on setup
|
1764
|
+
|
1765
|
+
App.setup = {
|
1766
|
+
renderer: 'html',
|
1767
|
+
debounce: 100,
|
1768
|
+
ratio: 1,
|
1769
|
+
supportsCanvas: false,
|
1770
|
+
supportsSVG: false,
|
1771
|
+
lineWrapRatio: 0.9,
|
1772
|
+
renderers: ['html', 'canvas', 'svg']
|
1773
|
+
};
|
1774
|
+
|
1775
|
+
App.dpr = function(val) {
|
1776
|
+
return val * App.setup.ratio;
|
1777
|
+
};
|
1778
|
+
|
1779
|
+
//Properties modified during runtime
|
1780
|
+
|
1781
|
+
App.vars = {
|
1782
|
+
preempted: false,
|
1783
|
+
resizableImages: [],
|
1784
|
+
invisibleImages: {},
|
1785
|
+
invisibleId: 0,
|
1786
|
+
visibilityCheckStarted: false,
|
1787
|
+
debounceTimer: null,
|
1788
|
+
cache: {},
|
1789
|
+
dataAttr: 'data-src'
|
1790
|
+
};
|
1791
|
+
|
1792
|
+
//Pre-flight
|
1793
|
+
|
1794
|
+
(function() {
|
1795
|
+
var devicePixelRatio = 1,
|
1796
|
+
backingStoreRatio = 1;
|
1797
|
+
|
1798
|
+
var canvas = newEl('canvas');
|
1799
|
+
var ctx = null;
|
1800
|
+
|
1801
|
+
if (canvas.getContext) {
|
1802
|
+
if (canvas.toDataURL('image/png').indexOf('data:image/png') != -1) {
|
1803
|
+
App.setup.renderer = 'canvas';
|
1804
|
+
ctx = canvas.getContext('2d');
|
1805
|
+
App.setup.supportsCanvas = true;
|
1806
|
+
}
|
1807
|
+
}
|
1808
|
+
|
1809
|
+
if (App.setup.supportsCanvas) {
|
1810
|
+
devicePixelRatio = global.devicePixelRatio || 1;
|
1811
|
+
backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
|
1812
|
+
}
|
1813
|
+
|
1814
|
+
App.setup.ratio = devicePixelRatio / backingStoreRatio;
|
1815
|
+
|
1816
|
+
if (!!document.createElementNS && !!document.createElementNS(SVG_NS, 'svg').createSVGRect) {
|
1817
|
+
App.setup.renderer = 'svg';
|
1818
|
+
App.setup.supportsSVG = true;
|
1819
|
+
}
|
1820
|
+
})();
|
1821
|
+
|
1822
|
+
//Starts checking for invisible placeholders
|
1823
|
+
startVisibilityCheck();
|
1824
|
+
|
1825
|
+
if (onDomReady) {
|
1826
|
+
onDomReady(function() {
|
1827
|
+
if (!App.vars.preempted) {
|
1828
|
+
Holder.run();
|
1829
|
+
}
|
1830
|
+
if (global.addEventListener) {
|
1831
|
+
global.addEventListener('resize', resizeEvent, false);
|
1832
|
+
global.addEventListener('orientationchange', resizeEvent, false);
|
1833
|
+
} else {
|
1834
|
+
global.attachEvent('onresize', resizeEvent);
|
1835
|
+
}
|
1836
|
+
|
1837
|
+
if (typeof global.Turbolinks == 'object') {
|
1838
|
+
global.document.addEventListener('page:change', function() {
|
1839
|
+
Holder.run();
|
1840
|
+
});
|
1841
|
+
}
|
1842
|
+
});
|
1843
|
+
}
|
1844
|
+
|
1845
|
+
module.exports = Holder;
|
1846
|
+
|
1847
|
+
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
1848
|
+
|
1849
|
+
/***/ },
|
1850
|
+
/* 1 */
|
1851
|
+
/***/ function(module, exports, __webpack_require__) {
|
1852
|
+
|
1853
|
+
/*!
|
1854
|
+
* onDomReady.js 1.4.0 (c) 2013 Tubal Martin - MIT license
|
1855
|
+
*
|
1856
|
+
* Specially modified to work with Holder.js
|
1857
|
+
*/
|
1858
|
+
|
1859
|
+
function _onDomReady(win) {
|
1860
|
+
//Lazy loading fix for Firefox < 3.6
|
1861
|
+
//http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
|
1862
|
+
if (document.readyState == null && document.addEventListener) {
|
1863
|
+
document.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
|
1864
|
+
document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
|
1865
|
+
document.readyState = "complete";
|
1866
|
+
}, false);
|
1867
|
+
document.readyState = "loading";
|
1868
|
+
}
|
1869
|
+
|
1870
|
+
var doc = win.document,
|
1871
|
+
docElem = doc.documentElement,
|
1872
|
+
|
1873
|
+
LOAD = "load",
|
1874
|
+
FALSE = false,
|
1875
|
+
ONLOAD = "on"+LOAD,
|
1876
|
+
COMPLETE = "complete",
|
1877
|
+
READYSTATE = "readyState",
|
1878
|
+
ATTACHEVENT = "attachEvent",
|
1879
|
+
DETACHEVENT = "detachEvent",
|
1880
|
+
ADDEVENTLISTENER = "addEventListener",
|
1881
|
+
DOMCONTENTLOADED = "DOMContentLoaded",
|
1882
|
+
ONREADYSTATECHANGE = "onreadystatechange",
|
1883
|
+
REMOVEEVENTLISTENER = "removeEventListener",
|
1884
|
+
|
1885
|
+
// W3C Event model
|
1886
|
+
w3c = ADDEVENTLISTENER in doc,
|
1887
|
+
_top = FALSE,
|
1888
|
+
|
1889
|
+
// isReady: Is the DOM ready to be used? Set to true once it occurs.
|
1890
|
+
isReady = FALSE,
|
1891
|
+
|
1892
|
+
// Callbacks pending execution until DOM is ready
|
1893
|
+
callbacks = [];
|
1894
|
+
|
1895
|
+
// Handle when the DOM is ready
|
1896
|
+
function ready( fn ) {
|
1897
|
+
if ( !isReady ) {
|
1898
|
+
|
1899
|
+
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
|
1900
|
+
if ( !doc.body ) {
|
1901
|
+
return defer( ready );
|
1902
|
+
}
|
1903
|
+
|
1904
|
+
// Remember that the DOM is ready
|
1905
|
+
isReady = true;
|
1906
|
+
|
1907
|
+
// Execute all callbacks
|
1908
|
+
while ( fn = callbacks.shift() ) {
|
1909
|
+
defer( fn );
|
1910
|
+
}
|
1911
|
+
}
|
1912
|
+
}
|
1913
|
+
|
1914
|
+
// The ready event handler
|
1915
|
+
function completed( event ) {
|
1916
|
+
// readyState === "complete" is good enough for us to call the dom ready in oldIE
|
1917
|
+
if ( w3c || event.type === LOAD || doc[READYSTATE] === COMPLETE ) {
|
1918
|
+
detach();
|
1919
|
+
ready();
|
1920
|
+
}
|
1921
|
+
}
|
1922
|
+
|
1923
|
+
// Clean-up method for dom ready events
|
1924
|
+
function detach() {
|
1925
|
+
if ( w3c ) {
|
1926
|
+
doc[REMOVEEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE );
|
1927
|
+
win[REMOVEEVENTLISTENER]( LOAD, completed, FALSE );
|
1928
|
+
} else {
|
1929
|
+
doc[DETACHEVENT]( ONREADYSTATECHANGE, completed );
|
1930
|
+
win[DETACHEVENT]( ONLOAD, completed );
|
1931
|
+
}
|
1932
|
+
}
|
1933
|
+
|
1934
|
+
// Defers a function, scheduling it to run after the current call stack has cleared.
|
1935
|
+
function defer( fn, wait ) {
|
1936
|
+
// Allow 0 to be passed
|
1937
|
+
setTimeout( fn, +wait >= 0 ? wait : 1 );
|
1938
|
+
}
|
1939
|
+
|
1940
|
+
// Attach the listeners:
|
1941
|
+
|
1942
|
+
// Catch cases where onDomReady is called after the browser event has already occurred.
|
1943
|
+
// we once tried to use readyState "interactive" here, but it caused issues like the one
|
1944
|
+
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
|
1945
|
+
if ( doc[READYSTATE] === COMPLETE ) {
|
1946
|
+
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
1947
|
+
defer( ready );
|
1948
|
+
|
1949
|
+
// Standards-based browsers support DOMContentLoaded
|
1950
|
+
} else if ( w3c ) {
|
1951
|
+
// Use the handy event callback
|
1952
|
+
doc[ADDEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE );
|
1953
|
+
|
1954
|
+
// A fallback to window.onload, that will always work
|
1955
|
+
win[ADDEVENTLISTENER]( LOAD, completed, FALSE );
|
1956
|
+
|
1957
|
+
// If IE event model is used
|
1958
|
+
} else {
|
1959
|
+
// Ensure firing before onload, maybe late but safe also for iframes
|
1960
|
+
doc[ATTACHEVENT]( ONREADYSTATECHANGE, completed );
|
1961
|
+
|
1962
|
+
// A fallback to window.onload, that will always work
|
1963
|
+
win[ATTACHEVENT]( ONLOAD, completed );
|
1964
|
+
|
1965
|
+
// If IE and not a frame
|
1966
|
+
// continually check to see if the document is ready
|
1967
|
+
try {
|
1968
|
+
_top = win.frameElement == null && docElem;
|
1969
|
+
} catch(e) {}
|
1970
|
+
|
1971
|
+
if ( _top && _top.doScroll ) {
|
1972
|
+
(function doScrollCheck() {
|
1973
|
+
if ( !isReady ) {
|
1974
|
+
try {
|
1975
|
+
// Use the trick by Diego Perini
|
1976
|
+
// http://javascript.nwbox.com/IEContentLoaded/
|
1977
|
+
_top.doScroll("left");
|
1978
|
+
} catch(e) {
|
1979
|
+
return defer( doScrollCheck, 50 );
|
1980
|
+
}
|
1981
|
+
|
1982
|
+
// detach all dom ready events
|
1983
|
+
detach();
|
1984
|
+
|
1985
|
+
// and execute any waiting functions
|
1986
|
+
ready();
|
1987
|
+
}
|
1988
|
+
})();
|
1989
|
+
}
|
1990
|
+
}
|
1991
|
+
|
1992
|
+
function onDomReady( fn ) {
|
1993
|
+
// If DOM is ready, execute the function (async), otherwise wait
|
1994
|
+
isReady ? defer( fn ) : callbacks.push( fn );
|
1995
|
+
}
|
1996
|
+
|
1997
|
+
// Add version
|
1998
|
+
onDomReady.version = "1.4.0";
|
1999
|
+
// Add method to check if DOM is ready
|
2000
|
+
onDomReady.isReady = function(){
|
2001
|
+
return isReady;
|
2002
|
+
};
|
2003
|
+
|
2004
|
+
return onDomReady;
|
2005
|
+
}
|
2006
|
+
|
2007
|
+
module.exports = typeof window !== "undefined" && _onDomReady(window);
|
2008
|
+
|
2009
|
+
/***/ },
|
2010
|
+
/* 2 */
|
2011
|
+
/***/ function(module, exports, __webpack_require__) {
|
2012
|
+
|
2013
|
+
var augment = __webpack_require__(5);
|
2014
|
+
|
2015
|
+
var SceneGraph = function(sceneProperties) {
|
2016
|
+
var nodeCount = 1;
|
2017
|
+
|
2018
|
+
//todo: move merge to helpers section
|
2019
|
+
function merge(parent, child) {
|
2020
|
+
for (var prop in child) {
|
2021
|
+
parent[prop] = child[prop];
|
2022
|
+
}
|
2023
|
+
return parent;
|
2024
|
+
}
|
2025
|
+
|
2026
|
+
var SceneNode = augment.defclass({
|
2027
|
+
constructor: function(name) {
|
2028
|
+
nodeCount++;
|
2029
|
+
this.parent = null;
|
2030
|
+
this.children = {};
|
2031
|
+
this.id = nodeCount;
|
2032
|
+
this.name = 'n' + nodeCount;
|
2033
|
+
if (name != null) {
|
2034
|
+
this.name = name;
|
2035
|
+
}
|
2036
|
+
this.x = 0;
|
2037
|
+
this.y = 0;
|
2038
|
+
this.z = 0;
|
2039
|
+
this.width = 0;
|
2040
|
+
this.height = 0;
|
2041
|
+
},
|
2042
|
+
resize: function(width, height) {
|
2043
|
+
if (width != null) {
|
2044
|
+
this.width = width;
|
2045
|
+
}
|
2046
|
+
if (height != null) {
|
2047
|
+
this.height = height;
|
2048
|
+
}
|
2049
|
+
},
|
2050
|
+
moveTo: function(x, y, z) {
|
2051
|
+
this.x = x != null ? x : this.x;
|
2052
|
+
this.y = y != null ? y : this.y;
|
2053
|
+
this.z = z != null ? z : this.z;
|
2054
|
+
},
|
2055
|
+
add: function(child) {
|
2056
|
+
var name = child.name;
|
2057
|
+
if (this.children[name] == null) {
|
2058
|
+
this.children[name] = child;
|
2059
|
+
child.parent = this;
|
2060
|
+
} else {
|
2061
|
+
throw 'SceneGraph: child with that name already exists: ' + name;
|
2062
|
+
}
|
2063
|
+
}
|
2064
|
+
});
|
2065
|
+
|
2066
|
+
var RootNode = augment(SceneNode, function(uber) {
|
2067
|
+
this.constructor = function() {
|
2068
|
+
uber.constructor.call(this, 'root');
|
2069
|
+
this.properties = sceneProperties;
|
2070
|
+
};
|
2071
|
+
});
|
2072
|
+
|
2073
|
+
var Shape = augment(SceneNode, function(uber) {
|
2074
|
+
function constructor(name, props) {
|
2075
|
+
uber.constructor.call(this, name);
|
2076
|
+
this.properties = {
|
2077
|
+
fill: '#000'
|
2078
|
+
};
|
2079
|
+
if (props != null) {
|
2080
|
+
merge(this.properties, props);
|
2081
|
+
} else if (name != null && typeof name !== 'string') {
|
2082
|
+
throw 'SceneGraph: invalid node name';
|
2083
|
+
}
|
2084
|
+
}
|
2085
|
+
|
2086
|
+
this.Group = augment.extend(this, {
|
2087
|
+
constructor: constructor,
|
2088
|
+
type: 'group'
|
2089
|
+
});
|
2090
|
+
|
2091
|
+
this.Rect = augment.extend(this, {
|
2092
|
+
constructor: constructor,
|
2093
|
+
type: 'rect'
|
2094
|
+
});
|
2095
|
+
|
2096
|
+
this.Text = augment.extend(this, {
|
2097
|
+
constructor: function(text) {
|
2098
|
+
constructor.call(this);
|
2099
|
+
this.properties.text = text;
|
2100
|
+
},
|
2101
|
+
type: 'text'
|
2102
|
+
});
|
2103
|
+
});
|
2104
|
+
|
2105
|
+
var root = new RootNode();
|
2106
|
+
|
2107
|
+
this.Shape = Shape;
|
2108
|
+
this.root = root;
|
2109
|
+
|
2110
|
+
return this;
|
2111
|
+
};
|
2112
|
+
|
2113
|
+
module.exports = SceneGraph;
|
2114
|
+
|
2115
|
+
|
2116
|
+
/***/ },
|
2117
|
+
/* 3 */
|
2118
|
+
/***/ function(module, exports, __webpack_require__) {
|
2119
|
+
|
2120
|
+
/* WEBPACK VAR INJECTION */(function(global) {/**
|
2121
|
+
* Shallow object clone and merge
|
2122
|
+
*
|
2123
|
+
* @param a Object A
|
2124
|
+
* @param b Object B
|
2125
|
+
* @returns {Object} New object with all of A's properties, and all of B's properties, overwriting A's properties
|
2126
|
+
*/
|
2127
|
+
exports.extend = function(a, b) {
|
2128
|
+
var c = {};
|
2129
|
+
for (var x in a) {
|
2130
|
+
if (a.hasOwnProperty(x)) {
|
2131
|
+
c[x] = a[x];
|
2132
|
+
}
|
2133
|
+
}
|
2134
|
+
if (b != null) {
|
2135
|
+
for (var y in b) {
|
2136
|
+
if (b.hasOwnProperty(y)) {
|
2137
|
+
c[y] = b[y];
|
2138
|
+
}
|
2139
|
+
}
|
2140
|
+
}
|
2141
|
+
return c;
|
2142
|
+
};
|
2143
|
+
|
2144
|
+
/**
|
2145
|
+
* Takes a k/v list of CSS properties and returns a rule
|
2146
|
+
*
|
2147
|
+
* @param props CSS properties object
|
2148
|
+
*/
|
2149
|
+
exports.cssProps = function(props) {
|
2150
|
+
var ret = [];
|
2151
|
+
for (var p in props) {
|
2152
|
+
if (props.hasOwnProperty(p)) {
|
2153
|
+
ret.push(p + ':' + props[p]);
|
2154
|
+
}
|
2155
|
+
}
|
2156
|
+
return ret.join(';');
|
2157
|
+
};
|
2158
|
+
|
2159
|
+
/**
|
2160
|
+
* Encodes HTML entities in a string
|
2161
|
+
*
|
2162
|
+
* @param str Input string
|
2163
|
+
*/
|
2164
|
+
exports.encodeHtmlEntity = function(str) {
|
2165
|
+
var buf = [];
|
2166
|
+
var charCode = 0;
|
2167
|
+
for (var i = str.length - 1; i >= 0; i--) {
|
2168
|
+
charCode = str.charCodeAt(i);
|
2169
|
+
if (charCode > 128) {
|
2170
|
+
buf.unshift(['&#', charCode, ';'].join(''));
|
2171
|
+
} else {
|
2172
|
+
buf.unshift(str[i]);
|
2173
|
+
}
|
2174
|
+
}
|
2175
|
+
return buf.join('');
|
2176
|
+
};
|
2177
|
+
|
2178
|
+
|
2179
|
+
/**
|
2180
|
+
* Converts a value into an array of DOM nodes
|
2181
|
+
*
|
2182
|
+
* @param val A string, a NodeList, a Node, or an HTMLCollection
|
2183
|
+
*/
|
2184
|
+
exports.getNodeArray = function(val) {
|
2185
|
+
var retval = null;
|
2186
|
+
if (typeof(val) == 'string') {
|
2187
|
+
retval = document.querySelectorAll(val);
|
2188
|
+
} else if (global.NodeList && val instanceof global.NodeList) {
|
2189
|
+
retval = val;
|
2190
|
+
} else if (global.Node && val instanceof global.Node) {
|
2191
|
+
retval = [val];
|
2192
|
+
} else if (global.HTMLCollection && val instanceof global.HTMLCollection) {
|
2193
|
+
retval = val;
|
2194
|
+
} else if (val instanceof Array) {
|
2195
|
+
retval = val;
|
2196
|
+
} else if (val === null) {
|
2197
|
+
retval = [];
|
2198
|
+
}
|
2199
|
+
return retval;
|
2200
|
+
};
|
2201
|
+
|
2202
|
+
/**
|
2203
|
+
* Checks if an image exists
|
2204
|
+
*
|
2205
|
+
* @param src URL of image
|
2206
|
+
* @param callback Callback to call once image status has been found
|
2207
|
+
*/
|
2208
|
+
exports.imageExists = function(src, callback) {
|
2209
|
+
var image = new Image();
|
2210
|
+
image.onerror = function() {
|
2211
|
+
callback.call(this, false);
|
2212
|
+
};
|
2213
|
+
image.onload = function() {
|
2214
|
+
callback.call(this, true);
|
2215
|
+
};
|
2216
|
+
image.src = src;
|
2217
|
+
};
|
2218
|
+
|
2219
|
+
/**
|
2220
|
+
* Decodes HTML entities in a string
|
2221
|
+
*
|
2222
|
+
* @param str Input string
|
2223
|
+
*/
|
2224
|
+
exports.decodeHtmlEntity = function(str) {
|
2225
|
+
return str.replace(/&#(\d+);/g, function(match, dec) {
|
2226
|
+
return String.fromCharCode(dec);
|
2227
|
+
});
|
2228
|
+
};
|
2229
|
+
|
2230
|
+
|
2231
|
+
/**
|
2232
|
+
* Returns an element's dimensions if it's visible, `false` otherwise.
|
2233
|
+
*
|
2234
|
+
* @param el DOM element
|
2235
|
+
*/
|
2236
|
+
exports.dimensionCheck = function(el) {
|
2237
|
+
var dimensions = {
|
2238
|
+
height: el.clientHeight,
|
2239
|
+
width: el.clientWidth
|
2240
|
+
};
|
2241
|
+
|
2242
|
+
if (dimensions.height && dimensions.width) {
|
2243
|
+
return dimensions;
|
2244
|
+
} else {
|
2245
|
+
return false;
|
2246
|
+
}
|
2247
|
+
};
|
2248
|
+
|
2249
|
+
|
2250
|
+
/**
|
2251
|
+
* Returns true if value is truthy or if it is "semantically truthy"
|
2252
|
+
* @param val
|
2253
|
+
*/
|
2254
|
+
exports.truthy = function(val) {
|
2255
|
+
if (typeof val === 'string') {
|
2256
|
+
return val === 'true' || val === 'yes' || val === '1' || val === 'on' || val === '✓';
|
2257
|
+
}
|
2258
|
+
return !!val;
|
2259
|
+
};
|
2260
|
+
|
2261
|
+
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
2262
|
+
|
2263
|
+
/***/ },
|
2264
|
+
/* 4 */
|
2265
|
+
/***/ function(module, exports, __webpack_require__) {
|
2266
|
+
|
2267
|
+
//Modified version of component/querystring
|
2268
|
+
//Changes: updated dependencies, dot notation parsing, JSHint fixes
|
2269
|
+
//Fork at https://github.com/imsky/querystring
|
2270
|
+
|
2271
|
+
/**
|
2272
|
+
* Module dependencies.
|
2273
|
+
*/
|
2274
|
+
|
2275
|
+
var encode = encodeURIComponent;
|
2276
|
+
var decode = decodeURIComponent;
|
2277
|
+
var trim = __webpack_require__(6);
|
2278
|
+
var type = __webpack_require__(7);
|
2279
|
+
|
2280
|
+
var arrayRegex = /(\w+)\[(\d+)\]/;
|
2281
|
+
var objectRegex = /\w+\.\w+/;
|
2282
|
+
|
2283
|
+
/**
|
2284
|
+
* Parse the given query `str`.
|
2285
|
+
*
|
2286
|
+
* @param {String} str
|
2287
|
+
* @return {Object}
|
2288
|
+
* @api public
|
2289
|
+
*/
|
2290
|
+
|
2291
|
+
exports.parse = function(str){
|
2292
|
+
if ('string' !== typeof str) return {};
|
2293
|
+
|
2294
|
+
str = trim(str);
|
2295
|
+
if ('' === str) return {};
|
2296
|
+
if ('?' === str.charAt(0)) str = str.slice(1);
|
2297
|
+
|
2298
|
+
var obj = {};
|
2299
|
+
var pairs = str.split('&');
|
2300
|
+
for (var i = 0; i < pairs.length; i++) {
|
2301
|
+
var parts = pairs[i].split('=');
|
2302
|
+
var key = decode(parts[0]);
|
2303
|
+
var m, ctx, prop;
|
2304
|
+
|
2305
|
+
if (m = arrayRegex.exec(key)) {
|
2306
|
+
obj[m[1]] = obj[m[1]] || [];
|
2307
|
+
obj[m[1]][m[2]] = decode(parts[1]);
|
2308
|
+
continue;
|
2309
|
+
}
|
2310
|
+
|
2311
|
+
if (m = objectRegex.test(key)) {
|
2312
|
+
m = key.split('.');
|
2313
|
+
ctx = obj;
|
2314
|
+
|
2315
|
+
while (m.length) {
|
2316
|
+
prop = m.shift();
|
2317
|
+
|
2318
|
+
if (!prop.length) continue;
|
2319
|
+
|
2320
|
+
if (!ctx[prop]) {
|
2321
|
+
ctx[prop] = {};
|
2322
|
+
} else if (ctx[prop] && typeof ctx[prop] !== 'object') {
|
2323
|
+
break;
|
2324
|
+
}
|
2325
|
+
|
2326
|
+
if (!m.length) {
|
2327
|
+
ctx[prop] = decode(parts[1]);
|
2328
|
+
}
|
2329
|
+
|
2330
|
+
ctx = ctx[prop];
|
2331
|
+
}
|
2332
|
+
|
2333
|
+
continue;
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
obj[parts[0]] = null == parts[1] ? '' : decode(parts[1]);
|
2337
|
+
}
|
2338
|
+
|
2339
|
+
return obj;
|
2340
|
+
};
|
2341
|
+
|
2342
|
+
/**
|
2343
|
+
* Stringify the given `obj`.
|
2344
|
+
*
|
2345
|
+
* @param {Object} obj
|
2346
|
+
* @return {String}
|
2347
|
+
* @api public
|
2348
|
+
*/
|
2349
|
+
|
2350
|
+
exports.stringify = function(obj){
|
2351
|
+
if (!obj) return '';
|
2352
|
+
var pairs = [];
|
2353
|
+
|
2354
|
+
for (var key in obj) {
|
2355
|
+
var value = obj[key];
|
2356
|
+
|
2357
|
+
if ('array' == type(value)) {
|
2358
|
+
for (var i = 0; i < value.length; ++i) {
|
2359
|
+
pairs.push(encode(key + '[' + i + ']') + '=' + encode(value[i]));
|
2360
|
+
}
|
2361
|
+
continue;
|
2362
|
+
}
|
2363
|
+
|
2364
|
+
pairs.push(encode(key) + '=' + encode(obj[key]));
|
2365
|
+
}
|
2366
|
+
|
2367
|
+
return pairs.join('&');
|
2368
|
+
};
|
2369
|
+
|
2370
|
+
|
2371
|
+
/***/ },
|
2372
|
+
/* 5 */
|
2373
|
+
/***/ function(module, exports, __webpack_require__) {
|
2374
|
+
|
2375
|
+
var Factory = function () {};
|
2376
|
+
var slice = Array.prototype.slice;
|
2377
|
+
|
2378
|
+
var augment = function (base, body) {
|
2379
|
+
var uber = Factory.prototype = typeof base === "function" ? base.prototype : base;
|
2380
|
+
var prototype = new Factory(), properties = body.apply(prototype, slice.call(arguments, 2).concat(uber));
|
2381
|
+
if (typeof properties === "object") for (var key in properties) prototype[key] = properties[key];
|
2382
|
+
if (!prototype.hasOwnProperty("constructor")) return prototype;
|
2383
|
+
var constructor = prototype.constructor;
|
2384
|
+
constructor.prototype = prototype;
|
2385
|
+
return constructor;
|
2386
|
+
};
|
2387
|
+
|
2388
|
+
augment.defclass = function (prototype) {
|
2389
|
+
var constructor = prototype.constructor;
|
2390
|
+
constructor.prototype = prototype;
|
2391
|
+
return constructor;
|
2392
|
+
};
|
2393
|
+
|
2394
|
+
augment.extend = function (base, body) {
|
2395
|
+
return augment(base, function (uber) {
|
2396
|
+
this.uber = uber;
|
2397
|
+
return body;
|
2398
|
+
});
|
2399
|
+
};
|
2400
|
+
|
2401
|
+
module.exports = augment;
|
2402
|
+
|
2403
|
+
/***/ },
|
2404
|
+
/* 6 */
|
2405
|
+
/***/ function(module, exports, __webpack_require__) {
|
2406
|
+
|
2407
|
+
|
2408
|
+
exports = module.exports = trim;
|
2409
|
+
|
2410
|
+
function trim(str){
|
2411
|
+
return str.replace(/^\s*|\s*$/g, '');
|
2412
|
+
}
|
2413
|
+
|
2414
|
+
exports.left = function(str){
|
2415
|
+
return str.replace(/^\s*/, '');
|
2416
|
+
};
|
2417
|
+
|
2418
|
+
exports.right = function(str){
|
2419
|
+
return str.replace(/\s*$/, '');
|
2420
|
+
};
|
2421
|
+
|
2422
|
+
|
2423
|
+
/***/ },
|
2424
|
+
/* 7 */
|
2425
|
+
/***/ function(module, exports, __webpack_require__) {
|
2426
|
+
|
2427
|
+
/**
|
2428
|
+
* toString ref.
|
2429
|
+
*/
|
2430
|
+
|
2431
|
+
var toString = Object.prototype.toString;
|
2432
|
+
|
2433
|
+
/**
|
2434
|
+
* Return the type of `val`.
|
2435
|
+
*
|
2436
|
+
* @param {Mixed} val
|
2437
|
+
* @return {String}
|
2438
|
+
* @api public
|
2439
|
+
*/
|
2440
|
+
|
2441
|
+
module.exports = function(val){
|
2442
|
+
switch (toString.call(val)) {
|
2443
|
+
case '[object Date]': return 'date';
|
2444
|
+
case '[object RegExp]': return 'regexp';
|
2445
|
+
case '[object Arguments]': return 'arguments';
|
2446
|
+
case '[object Array]': return 'array';
|
2447
|
+
case '[object Error]': return 'error';
|
2448
|
+
}
|
2449
|
+
|
2450
|
+
if (val === null) return 'null';
|
2451
|
+
if (val === undefined) return 'undefined';
|
2452
|
+
if (val !== val) return 'nan';
|
2453
|
+
if (val && val.nodeType === 1) return 'element';
|
2454
|
+
|
2455
|
+
val = val.valueOf
|
2456
|
+
? val.valueOf()
|
2457
|
+
: Object.prototype.valueOf.apply(val)
|
2458
|
+
|
2459
|
+
return typeof val;
|
2460
|
+
};
|
2461
|
+
|
2462
|
+
|
2463
|
+
/***/ }
|
2464
|
+
/******/ ])
|
2465
|
+
});
|
2466
|
+
;
|
2467
|
+
(function(ctx, isMeteorPackage) {
|
2468
|
+
if (isMeteorPackage) {
|
2469
|
+
Holder = ctx.Holder;
|
2470
|
+
}
|
2471
|
+
})(this, typeof Meteor !== 'undefined' && typeof Package !== 'undefined');
|