middleman-wizard-template 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. checksums.yaml +7 -0
  2. data/lib/middleman-wizard-template/template/source/index.html.erb +1 -89
  3. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/Matrix.js +449 -0
  4. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/PxLoader/PxLoader.js +395 -0
  5. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/PxLoader/PxLoaderImage.js +96 -0
  6. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/PxLoader/PxLoaderSwiffy.js +68 -0
  7. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/RouteRecognizer.js +506 -0
  8. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/Slides.js +846 -0
  9. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/Transform.js +312 -0
  10. data/lib/middleman-wizard-template/template/source/javascripts/_lib/{Tween.js → ww/Tween.js} +26 -11
  11. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/base.js +8 -0
  12. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/raf.js +131 -0
  13. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/statemachine.js +1024 -0
  14. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/useragent.js +1244 -0
  15. data/lib/middleman-wizard-template/template/source/javascripts/_lib/{util.js → ww/util.js} +48 -50
  16. data/lib/middleman-wizard-template/template/source/javascripts/_lib/ww/viewport.js +89 -0
  17. data/lib/middleman-wizard-template/template/source/javascripts/{app.js → site.js} +5 -5
  18. data/lib/middleman-wizard-template/template/source/layouts/layout.erb +85 -0
  19. data/lib/middleman-wizard-template/template/source/stylesheets/default.css +2 -1
  20. data/lib/middleman-wizard-template/template/source/stylesheets/site.css.scss +11 -3
  21. data/lib/middleman-wizard-template/version.rb +1 -1
  22. metadata +23 -23
  23. data/lib/middleman-wizard-template/template/source/javascripts/_lib/Transform.js +0 -401
  24. data/lib/middleman-wizard-template/template/source/javascripts/_lib/raf.js +0 -26
  25. data/lib/middleman-wizard-template/template/source/javascripts/_lib/router.js +0 -679
@@ -0,0 +1,395 @@
1
+ /**
2
+ * Loads resources while providing progress updates.
3
+ * @constructor
4
+ * @param {Object} settings Config vars.
5
+ */
6
+ ww.Loader = function Loader(settings) {
7
+
8
+ // merge settings with defaults
9
+ settings = settings || {};
10
+
11
+ // how frequently we poll resources for progress
12
+ if (settings.statusInterval == null) {
13
+ settings.statusInterval = 5000; // every 5 seconds by default
14
+ }
15
+
16
+ // delay before logging since last progress change
17
+ if (settings.loggingDelay == null) {
18
+ settings.loggingDelay = 20 * 1000; // log stragglers after 20 secs
19
+ }
20
+
21
+ // stop waiting if no progress has been made in the moving time window
22
+ if (settings.noProgressTimeout == null) {
23
+ settings.noProgressTimeout = Infinity; // do not stop waiting by default
24
+ }
25
+
26
+ var entries = [],
27
+ // holds resources to be loaded with their status
28
+ progressListeners = [],
29
+ timeStarted, progressChanged = +new Date;
30
+
31
+ /**
32
+ * The status of a resource
33
+ * @enum {number}
34
+ */
35
+ var ResourceState = {
36
+ QUEUED: 0,
37
+ WAITING: 1,
38
+ LOADED: 2,
39
+ ERROR: 3,
40
+ TIMEOUT: 4
41
+ };
42
+
43
+ // places non-array values into an array.
44
+ var ensureArray = function(val) {
45
+ if (val == null) {
46
+ return [];
47
+ }
48
+
49
+ if (Array.isArray(val)) {
50
+ return val;
51
+ }
52
+
53
+ return [val];
54
+ };
55
+
56
+ // add an entry to the list of resources to be loaded
57
+ this.add = function(resource) {
58
+
59
+ // ensure tags are in an object
60
+ resource.tags = new ww.LoaderTags(resource.tags);
61
+
62
+ // ensure priority is set
63
+ if (resource.priority == null) {
64
+ resource.priority = Infinity;
65
+ }
66
+
67
+ entries.push({
68
+ resource: resource,
69
+ status: ResourceState.QUEUED
70
+ });
71
+ };
72
+
73
+ this.addProgressListener = function(callback, tags) {
74
+ progressListeners.push({
75
+ callback: callback,
76
+ tags: new ww.LoaderTags(tags)
77
+ });
78
+ };
79
+
80
+ this.addCompletionListener = function(callback, tags) {
81
+ progressListeners.push({
82
+ tags: new ww.LoaderTags(tags),
83
+ callback: function(e) {
84
+ if (e.completedCount === e.totalCount) {
85
+ callback();
86
+ }
87
+ }
88
+ });
89
+ };
90
+
91
+ // creates a comparison function for resources
92
+ var getResourceSort = function(orderedTags) {
93
+
94
+ // helper to get the top tag's order for a resource
95
+ orderedTags = ensureArray(orderedTags);
96
+ var getTagOrder = function(entry) {
97
+ var resource = entry.resource,
98
+ bestIndex = Infinity;
99
+ for (var i = 0; i < resource.tags.length; i++) {
100
+ for (var j = 0; j < Math.min(orderedTags.length, bestIndex); j++) {
101
+ if (resource.tags[i] == orderedTags[j] && j < bestIndex) {
102
+ bestIndex = j;
103
+ if (bestIndex === 0) break;
104
+ }
105
+ if (bestIndex === 0) break;
106
+ }
107
+ }
108
+ return bestIndex;
109
+ };
110
+ return function(a, b) {
111
+ // check tag order first
112
+ var aOrder = getTagOrder(a),
113
+ bOrder = getTagOrder(b);
114
+ if (aOrder < bOrder) return -1;
115
+ if (aOrder > bOrder) return 1;
116
+
117
+ // now check priority
118
+ if (a.priority < b.priority) return -1;
119
+ if (a.priority > b.priority) return 1;
120
+ return 0;
121
+ }
122
+ };
123
+
124
+ this.start = function(orderedTags) {
125
+ timeStarted = +new Date;
126
+
127
+ // first order the resources
128
+ var compareResources = getResourceSort(orderedTags);
129
+ entries.sort(compareResources);
130
+
131
+ // trigger requests for each resource
132
+ for (var i = 0, len = entries.length; i < len; i++) {
133
+ var entry = entries[i];
134
+ entry.status = ResourceState.WAITING;
135
+ entry.resource.start(this);
136
+ }
137
+
138
+ // do an initial status check soon since items may be loaded from the cache
139
+ setTimeout(statusCheck, 100);
140
+ };
141
+
142
+ var statusCheck = function() {
143
+ var checkAgain = false,
144
+ noProgressTime = (+new Date) - progressChanged,
145
+ timedOut = (noProgressTime >= settings.noProgressTimeout),
146
+ shouldLog = (noProgressTime >= settings.loggingDelay);
147
+
148
+ for (var i = 0, len = entries.length; i < len; i++) {
149
+ var entry = entries[i];
150
+ if (entry.status !== ResourceState.WAITING) {
151
+ continue;
152
+ }
153
+
154
+ // see if the resource has loaded
155
+ if (entry.resource.checkStatus) {
156
+ entry.resource.checkStatus();
157
+ }
158
+
159
+ // if still waiting, mark as timed out or make sure we check again
160
+ if (entry.status === ResourceState.WAITING) {
161
+ if (timedOut) {
162
+ entry.resource.onTimeout();
163
+ } else {
164
+ checkAgain = true;
165
+ }
166
+ }
167
+ }
168
+
169
+ // log any resources that are still pending
170
+ if (shouldLog && checkAgain) {
171
+ log();
172
+ }
173
+
174
+ if (checkAgain) {
175
+ setTimeout(statusCheck, settings.statusInterval);
176
+ }
177
+ };
178
+
179
+ this.isBusy = function() {
180
+ for (var i = 0, len = entries.length; i < len; i++) {
181
+ if ((entries[i].status === ResourceState.QUEUED) ||
182
+ (entries[i].status === ResourceState.WAITING)) {
183
+ return true;
184
+ }
185
+ }
186
+ return false;
187
+ };
188
+
189
+ var onProgress = function(resource, statusType) {
190
+ // find the entry for the resource
191
+ var entry = null;
192
+ for (var i = 0, len = entries.length; i < len; i++) {
193
+ if (entries[i].resource === resource) {
194
+ entry = entries[i];
195
+ break;
196
+ }
197
+ }
198
+
199
+ // we have already updated the status of the resource
200
+ if (entry == null || entry.status !== ResourceState.WAITING) {
201
+ return;
202
+ }
203
+ entry.status = statusType;
204
+ progressChanged = +new Date;
205
+
206
+ var numResourceTags = resource.tags.length;
207
+
208
+ // fire callbacks for interested listeners
209
+ var numListeners = progressListeners.length;
210
+ for (var i = 0; i < numListeners; i++) {
211
+ var listener = progressListeners[i],
212
+ shouldCall;
213
+
214
+ if (listener.tags.length === 0) {
215
+ // no tags specified so always tell the listener
216
+ shouldCall = true;
217
+ } else {
218
+ // listener only wants to hear about certain tags
219
+ shouldCall = resource.tags.contains(listener.tags);
220
+ }
221
+
222
+ if (shouldCall) {
223
+ sendProgress(entry, listener);
224
+ }
225
+ }
226
+ };
227
+
228
+ this.onLoad = function(resource) {
229
+ onProgress(resource, ResourceState.LOADED);
230
+ };
231
+ this.onError = function(resource) {
232
+ onProgress(resource, ResourceState.ERROR);
233
+ };
234
+ this.onTimeout = function(resource) {
235
+ onProgress(resource, ResourceState.TIMEOUT);
236
+ };
237
+
238
+ // sends a progress report to a listener
239
+ var sendProgress = function(updatedEntry, listener) {
240
+ // find stats for all the resources the caller is interested in
241
+ var completed = 0,
242
+ total = 0;
243
+ for (var i = 0, len = entries.length; i < len; i++) {
244
+ var entry = entries[i],
245
+ includeResource = false;
246
+
247
+ if (listener.tags.length === 0) {
248
+ // no tags specified so always tell the listener
249
+ includeResource = true;
250
+ } else {
251
+ includeResource = entry.resource.tags.contains(listener.tags);
252
+ }
253
+
254
+ if (includeResource) {
255
+ total++;
256
+ if ((entry.status === ResourceState.LOADED) ||
257
+ (entry.status === ResourceState.ERROR) ||
258
+ (entry.status === ResourceState.TIMEOUT)) {
259
+ completed++;
260
+ }
261
+ }
262
+ }
263
+
264
+ listener.callback({
265
+ // info about the resource that changed
266
+ resource: updatedEntry.resource,
267
+
268
+ // should we expose StatusType instead?
269
+ loaded: (updatedEntry.status === ResourceState.LOADED),
270
+ error: (updatedEntry.status === ResourceState.ERROR),
271
+ timeout: (updatedEntry.status === ResourceState.TIMEOUT),
272
+
273
+ // updated stats for all resources
274
+ completedCount: completed,
275
+ totalCount: total
276
+ });
277
+ };
278
+
279
+ // prints the status of each resource to the console
280
+ var log = this.log = function(showAll) {
281
+ if (!window.console) {
282
+ return;
283
+ }
284
+
285
+ var elapsedSeconds = Math.round((+new Date - timeStarted) / 1000);
286
+ window.console.log('ww.Loader elapsed: ' + elapsedSeconds + ' sec');
287
+
288
+ for (var i = 0, len = entries.length; i < len; i++) {
289
+ var entry = entries[i];
290
+ if (!showAll && entry.status !== ResourceState.WAITING) {
291
+ continue;
292
+ }
293
+
294
+ var message = 'ww.Loader: #' + i + ' ' + entry.resource.getName();
295
+ switch (entry.status) {
296
+ case ResourceState.QUEUED:
297
+ message += ' (Not Started)';
298
+ break;
299
+ case ResourceState.WAITING:
300
+ message += ' (Waiting)';
301
+ break;
302
+ case ResourceState.LOADED:
303
+ message += ' (Loaded)';
304
+ break;
305
+ case ResourceState.ERROR:
306
+ message += ' (Error)';
307
+ break;
308
+ case ResourceState.TIMEOUT:
309
+ message += ' (Timeout)';
310
+ break;
311
+ }
312
+
313
+ if (entry.resource.tags.length > 0) {
314
+ message += ' Tags: [' + entry.resource.tags.join(',') + ']';
315
+ }
316
+
317
+ window.console.log(message);
318
+ }
319
+ };
320
+ };
321
+
322
+ goog.exportSymbol('ww.Loader', ww.Loader);
323
+
324
+ // Tag object to handle tag intersection; once created not meant to be changed
325
+ // Performance rationale: http://jsperf.com/lists-indexof-vs-in-operator/3
326
+ /**
327
+ * Tags.
328
+ * @constructor
329
+ * @param {Object} values Tag values.
330
+ */
331
+ ww.LoaderTags = function LoaderTags(values) {
332
+
333
+ this.array = [];
334
+ this.object = {};
335
+ this.value = null; // single value
336
+ this.length = 0;
337
+
338
+ if (values !== null && values !== undefined) {
339
+ if (Array.isArray(values)) {
340
+ this.array = values;
341
+ } else if (typeof values === 'object') {
342
+ for (var key in values) {
343
+ this.array.push(key);
344
+ }
345
+ } else {
346
+ this.array.push(values);
347
+ this.value = values;
348
+ }
349
+
350
+ this.length = this.array.length;
351
+
352
+ // convert array values to object with truthy values, used by contains
353
+ // function below
354
+ for (var i = 0; i < this.length; i++) {
355
+ this.object[this.array[i]] = true;
356
+ }
357
+ }
358
+
359
+ // compare this object with another; return true if they share at least
360
+ // one value
361
+ this.contains = function(other) {
362
+ if (this.length === 0 || other.length === 0) {
363
+ return false;
364
+ } else if (this.length === 1 && this.value !== null) {
365
+ if (other.length === 1) {
366
+ return this.value === other.value;
367
+ } else {
368
+ return other.object.hasOwnProperty(this.value);
369
+ }
370
+ } else if (other.length < this.length) {
371
+ return other.contains(this); // better to loop through the smaller object
372
+ } else {
373
+ for (var key in this.object) {
374
+ if (other.object[key]) {
375
+ return true;
376
+ }
377
+ }
378
+ return false;
379
+ }
380
+ }
381
+ };
382
+
383
+ // shims to ensure we have newer Array utility methods
384
+ if (!Array.isArray) {
385
+ /**
386
+ * Polyfill for isArray
387
+ * @param {Array} arg The array.
388
+ * @return {Boolean} Whether it is an array.
389
+ */
390
+ Array.isArray = function(arg) {
391
+ return Object.prototype.toString.call(arg) == '[object Array]';
392
+ };
393
+ }
394
+
395
+ goog.exportSymbol('ww.LoaderTags', ww.LoaderTags);
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Loader plugin to load images.
3
+ * @constructor
4
+ * @param {String} url Url of the Swiffy.
5
+ * @param {Array} tags Array of tag names.
6
+ * @param {Number} priority Load order.
7
+ */
8
+ ww.LoaderImage = function LoaderImage(url, tags, priority) {
9
+ var self = this,
10
+ loader = null;
11
+
12
+ this.img = new Image();
13
+ this.tags = tags;
14
+ this.priority = priority;
15
+
16
+ var onReadyStateChange = function() {
17
+ if (self.img.readyState == 'complete') {
18
+ removeEventHandlers();
19
+ loader.onLoad(self);
20
+ }
21
+ };
22
+
23
+ var onLoad = function() {
24
+ removeEventHandlers();
25
+ loader.onLoad(self);
26
+ };
27
+
28
+ var onError = function() {
29
+ removeEventHandlers();
30
+ loader.onError(self);
31
+ };
32
+
33
+ var removeEventHandlers = function() {
34
+ self.unbind('load', onLoad);
35
+ self.unbind('readystatechange', onReadyStateChange);
36
+ self.unbind('error', onError);
37
+ };
38
+
39
+ this.start = function(pxloader) {
40
+ // we need the loader ref so we can notify upon completion
41
+ loader = pxloader;
42
+
43
+ // NOTE: Must add event listeners before the src is set. We
44
+ // also need to use the readystatechange because sometimes
45
+ // load doesn't fire when an image is in the cache.
46
+ self.bind('load', onLoad);
47
+ self.bind('readystatechange', onReadyStateChange);
48
+ self.bind('error', onError);
49
+
50
+ self.img.src = url;
51
+ };
52
+
53
+ // called by ww.Loader to check status of image (fallback in case
54
+ // the event listeners are not triggered).
55
+ this.checkStatus = function() {
56
+ if (self.img.complete) {
57
+ removeEventHandlers();
58
+ loader.onLoad(self);
59
+ }
60
+ };
61
+
62
+ // called by ww.Loader when it is no longer waiting
63
+ this.onTimeout = function() {
64
+ removeEventHandlers();
65
+ if (self.img.complete) {
66
+ loader.onLoad(self);
67
+ } else {
68
+ loader.onTimeout(self);
69
+ }
70
+ };
71
+
72
+ // returns a name for the resource that can be used in logging
73
+ this.getName = function() {
74
+ return url;
75
+ };
76
+
77
+ // cross-browser event binding
78
+ this.bind = function(eventName, eventHandler) {
79
+ if (self.img.addEventListener) {
80
+ self.img.addEventListener(eventName, eventHandler, false);
81
+ } else if (self.img.attachEvent) {
82
+ self.img.attachEvent('on' + eventName, eventHandler);
83
+ }
84
+ };
85
+
86
+ // cross-browser event un-binding
87
+ this.unbind = function(eventName, eventHandler) {
88
+ if (self.img.removeEventListener) {
89
+ self.img.removeEventListener(eventName, eventHandler, false);
90
+ } else if (self.img.detachEvent) {
91
+ self.img.detachEvent('on' + eventName, eventHandler);
92
+ }
93
+ };
94
+ };
95
+
96
+ goog.exportSymbol('ww.LoaderImage', ww.LoaderImage);