forked from processing-js/processing-js
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfinalizeProcessing.js
More file actions
executable file
·334 lines (302 loc) · 11 KB
/
Copy pathfinalizeProcessing.js
File metadata and controls
executable file
·334 lines (302 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/**
* Finalise the Processing.js object.
*/
module.exports = function finalizeProcessing(Processing, options) {
// unpack options
var window = options.window,
document = options.document,
XMLHttpRequest = window.XMLHttpRequest,
noop = options.noop,
isDOMPresent = options.isDOMPresent,
version = options.version,
undef;
// versioning
Processing.version = (version ? version : "@DEV-VERSION@");
// Share lib space
Processing.lib = {};
/**
* External libraries can be added to the global Processing
* objects with the `registerLibrary` function.
*/
Processing.registerLibrary = function(name, library) {
Processing.lib[name] = library;
if(library.hasOwnProperty("init")) {
library.init(defaultScope);
}
};
/**
* This is the object that acts as our version of PApplet.
* This can be called as Processing.Sketch() or as
* Processing.Sketch(function) in which case the function
* must be an already-compiled-to-JS sketch function.
*/
Processing.Sketch = function(attachFunction) {
this.attachFunction = attachFunction;
this.options = {
pauseOnBlur: false,
globalKeyEvents: false
};
/* Optional Sketch event hooks:
* onLoad - parsing/preloading is done, before sketch starts
* onSetup - setup() has been called, before first draw()
* onPause - noLoop() has been called, pausing draw loop
* onLoop - loop() has been called, resuming draw loop
* onFrameStart - draw() loop about to begin
* onFrameEnd - draw() loop finished
* onExit - exit() done being called
*/
this.onLoad = noop;
this.onSetup = noop;
this.onPause = noop;
this.onLoop = noop;
this.onFrameStart = noop;
this.onFrameEnd = noop;
this.onExit = noop;
this.params = {};
this.imageCache = {
pending: 0,
images: {},
// Opera requires special administration for preloading
operaCache: {},
// Specify an optional img arg if the image is already loaded in the DOM,
// otherwise href will get loaded.
add: function(href, img) {
// Prevent muliple loads for an image, in case it gets
// preloaded more than once, or is added via JS and then preloaded.
if (this.images[href]) {
return;
}
if (!isDOMPresent) {
this.images[href] = null;
}
// No image in the DOM, kick-off a background load
if (!img) {
img = new Image();
img.onload = (function(owner) {
return function() {
owner.pending--;
};
}(this));
this.pending++;
img.src = href;
}
this.images[href] = img;
// Opera will not load images until they are inserted into the DOM.
if (window.opera) {
var div = document.createElement("div");
div.appendChild(img);
// we can't use "display: none", since that makes it invisible, and thus not load
div.style.position = "absolute";
div.style.opacity = 0;
div.style.width = "1px";
div.style.height= "1px";
if (!this.operaCache[href]) {
document.body.appendChild(div);
this.operaCache[href] = div;
}
}
}
};
this.sourceCode = undefined;
this.attach = function(processing) {
// either attachFunction or sourceCode must be present on attach
if(typeof this.attachFunction === "function") {
this.attachFunction(processing);
} else if(this.sourceCode) {
var func = ((new Function("return (" + this.sourceCode + ");"))());
func(processing);
this.attachFunction = func;
} else {
throw "Unable to attach sketch to the processing instance";
}
};
this.toString = function() {
var i;
var code = "((function(Sketch) {\n";
code += "var sketch = new Sketch(\n" + this.sourceCode + ");\n";
for(i in this.options) {
if(this.options.hasOwnProperty(i)) {
var value = this.options[i];
code += "sketch.options." + i + " = " +
(typeof value === 'string' ? '\"' + value + '\"' : "" + value) + ";\n";
}
}
for(i in this.imageCache) {
if(this.options.hasOwnProperty(i)) {
code += "sketch.imageCache.add(\"" + i + "\");\n";
}
}
// TODO serialize fonts
code += "return sketch;\n})(Processing.Sketch))";
return code;
};
};
/**
* aggregate all source code into a single file, then rewrite that
* source and bind to canvas via new Processing(canvas, sourcestring).
* @param {CANVAS} canvas The html canvas element to bind to
* @param {String[]} source The array of files that must be loaded
*/
var loadSketchFromSources = Processing.loadSketchFromSources = function(canvas, sources) {
var code = [], errors = [], sourcesCount = sources.length, loaded = 0;
function ajaxAsync(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var error;
if (xhr.status !== 200 && xhr.status !== 0) {
error = "Invalid XHR status " + xhr.status;
} else if (xhr.responseText === "") {
// Give a hint when loading fails due to same-origin issues on file:/// urls
if ( ("withCredentials" in new XMLHttpRequest()) &&
(new XMLHttpRequest()).withCredentials === false &&
window.location.protocol === "file:" ) {
error = "XMLHttpRequest failure, possibly due to a same-origin policy violation. You can try loading this page in another browser, or load it from http://localhost using a local webserver. See the Processing.js README for a more detailed explanation of this problem and solutions.";
} else {
error = "File is empty.";
}
}
callback(xhr.responseText, error);
}
};
xhr.open("GET", url, true);
if (xhr.overrideMimeType) {
xhr.overrideMimeType("application/json");
}
xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); // no cache
xhr.send(null);
}
function loadBlock(index, filename) {
function callback(block, error) {
code[index] = block;
++loaded;
if (error) {
errors.push(filename + " ==> " + error);
}
if (loaded === sourcesCount) {
if (errors.length === 0) {
// This used to throw, but it was constantly getting in the way of debugging where things go wrong!
return new Processing(canvas, code.join("\n"));
} else {
throw "Processing.js: Unable to load pjs sketch files: " + errors.join("\n");
}
}
}
if (filename.charAt(0) === '#') {
// trying to get script from the element
var scriptElement = document.getElementById(filename.substring(1));
if (scriptElement) {
callback(scriptElement.text || scriptElement.textContent);
} else {
callback("", "Unable to load pjs sketch: element with id \'" + filename.substring(1) + "\' was not found");
}
return;
}
ajaxAsync(filename, callback);
}
for (var i = 0; i < sourcesCount; ++i) {
loadBlock(i, sources[i]);
}
};
/**
* Automatic initialization function.
*/
var init = function() {
document.removeEventListener('DOMContentLoaded', init, false);
var i;
// before running through init, clear the instances list, to prevent
// sketch duplication when page content is dynamically swapped without
// swapping out processing.js
while (Processing.instances.length > 0) {
for (i = Processing.instances.length - 1; i >= 0; i--) {
if (Processing.instances[i]) {
Processing.instances[i].exit();
}
}
}
var canvas = document.getElementsByTagName('canvas'),
filenames;
for (i = 0, l = canvas.length; i < l; i++) {
// datasrc and data-src are deprecated.
var processingSources = canvas[i].getAttribute('data-processing-sources');
if (processingSources === null) {
// Temporary fallback for datasrc and data-src
processingSources = canvas[i].getAttribute('data-src');
if (processingSources === null) {
processingSources = canvas[i].getAttribute('datasrc');
}
}
if (processingSources) {
filenames = processingSources.split(/\s+/g);
for (var j = 0; j < filenames.length;) {
if (filenames[j]) {
j++;
} else {
filenames.splice(j, 1);
}
}
loadSketchFromSources(canvas[i], filenames);
}
}
// also process all <script>-indicated sketches, if there are any
var s, last, source, instance,
nodelist = document.getElementsByTagName('script'),
scripts=[];
// snapshot the DOM, as the nodelist is only a DOM view, and is
// updated instantly when a script element is added or removed.
for (s = nodelist.length - 1; s >= 0; s--) {
scripts.push(nodelist[s]);
}
// iterate over all script elements to see if they contain Processing code
for (s = 0, last = scripts.length; s < last; s++) {
var script = scripts[s];
if (!script.getAttribute) {
continue;
}
var type = script.getAttribute("type");
if (type && (type.toLowerCase() === "text/processing" || type.toLowerCase() === "application/processing")) {
var target = script.getAttribute("data-processing-target");
canvas = undef;
if (target) {
canvas = document.getElementById(target);
} else {
var nextSibling = script.nextSibling;
while (nextSibling && nextSibling.nodeType !== 1) {
nextSibling = nextSibling.nextSibling;
}
if (nextSibling && nextSibling.nodeName.toLowerCase() === "canvas") {
canvas = nextSibling;
}
}
if (canvas) {
if (script.getAttribute("src")) {
filenames = script.getAttribute("src").split(/\s+/);
loadSketchFromSources(canvas, filenames);
continue;
}
source = script.textContent || script.text;
instance = new Processing(canvas, source);
}
}
}
};
/**
* automatic loading of all sketches on the page
*/
document.addEventListener('DOMContentLoaded', init, false);
/**
* Make Processing run through init after already having
* been set up for a page. This function exists mostly for pages
* that swap content in/out without reloading a page.
*/
Processing.reload = init;
/**
* Disable the automatic loading of all sketches on the page.
* This will work as long as it's issued before DOMContentLoaded.
*/
Processing.disableInit = function() {
document.removeEventListener('DOMContentLoaded', init, false);
};
// done.
return Processing;
};