PageSourceSearch

https://bitsbox.com/js/sandbox.js

js bitsbox.com collected 2026-09-24 09:50:47 UTC 10,121 bytes, 349 lines download raw bytes

1//  Copyright: Copyright 2015 Codepops Inc.
2//  License: All Rights Reserved.
3
4/**
5 * @fileoverview  Provide the Sandbox class.
6 * @author: Scott Lininger ([email protected])
7 */
8
9 /**
10 * Namespace where we'll hang everything off of.
11 * @namespace
12 * @expose
13 * @export
14 */
15var codepops = codepops || {};
16
17/**
18 * Provides an iframe-hosted Bitsbox library sandbox. We run code inside the
19 * the iframe so it is cross-domain isolated and so its variable space can
20 * be destroyed between runs.
21 * @param {EditorPage} page The page we're running within.
22 * @param {Element} renderDiv The div to render the iframe within.
23 * @param {Object=} opt_settings Optional hash of settings.
24 * @constructor
25 * @export
26 * @expose
27 */
28codepops.Sandbox = function(page, renderDiv, opt_settings) {
29  var settings = opt_settings || {};
30
31  /**
32   * Contains a reference to the window. Useful for dependency injection.
33   * @type {window}
34   * @private
35   */
36  this.window_ = settings['window'] || window;
37
38  /**
39   * Contains a reference to the document. Useful for dependency injection.
40   * @type {document}
41   * @private
42   */
43  this.document_ = settings['document'] || window.document;
44
45  /**
46   * Contains a reference to the parent Page.
47   * @type {codepops.EditorPage}
48   * @private
49   */
50  this.page_ = page;
51
52  /**
53   * The div we'll render the control into.
54   * @type {Element}
55   * @private
56   */
57  this.renderDiv_ = renderDiv;
58
59  /**
60   * A datastore path to be used for send/get exchanges.
61   * @type {string}
62   * @private
63   */
64  this.collabPath_ = null;
65
66  /**
67   * Functions that will be called on various iframe mouse events.
68   * @type {function}
69   * @private
70   */
71  this.onMouseMove_ = null;
72  this.onMouseOver_ = null;
73  this.onMouseOut_ = null;
74
75  /**
76   * Functions that will be called on various iframe touch events.
77   * @type {function}
78   * @private
79   */
80  this.onTouchMove_ = null;
81  this.onTouchStart_ = null;
82
83  /**
84   * Preload an iframe that is ready to run code within.
85   * @private
86   */
87  this.iframe_ = this.document_.createElement('iframe');
88  this.iframe_.style.visibility = 'hidden';
89  this.iframe_.title = 'Sandbox iframe';
90  this.iframe_.src = '/sandbox.html';
91  this.renderDiv_.appendChild(this.iframe_);
92
93  /**
94   * Figure out if we're running inside Interet Explorer.
95   * @type {boolean}
96   * @private
97   */
98  this.isIE_ = c123.isIE();
99
100  /**
101   * Figure out if we're running inside Firefox.
102   * @type {boolean}
103   * @private
104   */
105  this.isFirefox_ = c123.isFirefox();
106};
107
108
109/**
110 * Runs the passed code inside the next available iframe.
111 * @param {Object} code The code that we want to run.
112 * @param {?Object} opt_customAssetHash A hash of custom assets, reflecting
113 *     the customAssets collection in the user preferences.
114 */
115codepops.Sandbox.prototype.run = function(code, opt_customAssetHash) {
116  // If there is no iframe to run in, let's wait just a bit.
117  if (!this.iframe_ || !this.iframe_.contentWindow ||
118      !this.iframe_.contentWindow.run) {
119    setTimeout(codepops.bind(function() {
120      this.run(code, opt_customAssetHash);
121    }, this), 200);
122    return;
123  }
124
125  // IE is *really slow* to load iframes, so once we have a running iframe, just
126  // use that one and return.
127  if (this.isIE_ && this.currentlyRunningIFrame_) {
128    this.currentlyRunningIFrame_.contentWindow.setCollabPath(this.collabPath_);
129    this.currentlyRunningIFrame_.contentWindow.run(code || '',
130      opt_customAssetHash);
131    return;
132  }
133
134  // If we have a currently running app, destroy that iframe. (Unless the
135  // user has IE.)
136  if (!this.isIE_ && this.currentlyRunningIFrame_) {
137    this.renderDiv_.removeChild(this.currentlyRunningIFrame_);
138  }
139
140  // Attach the various error and event handlers to the iframe.
141  this.iframe_.contentWindow.setCollabPath(this.collabPath_);
142  this.iframe_.contentWindow.setOnErrorHandler(this.onError_);
143  this.iframe_.contentWindow.setOnSuccessHandler(this.onSuccess_);
144  this.iframe_.contentWindow.setOnAssetLoadErrorHandler(this.onAssetLoadError_);
145
146  var globalErrorHandler = function() {};
147  if (this.onError_) {
148    globalErrorHandler = this.onError_;
149  }
150
151  this.iframe_.contentWindow.onerror = function(message, url, lineNumber) {
152    globalErrorHandler(message);
153  };
154
155  var canvas = this.iframe_.contentWindow.getCanvas();
156  canvas.addEventListener('mousemove', this.onMouseMove_);
157  canvas.addEventListener('mouseover', this.onMouseOver_);
158  canvas.addEventListener('mouseout', this.onMouseOut_);
159  canvas.addEventListener('touchstart', this.onTouchStart_);
160  canvas.addEventListener('touchmove', this.onTouchMove_);
161
162  // Now run the code and record this iframe as the currently running one.
163  this.iframe_.contentWindow.run(code || '', opt_customAssetHash);
164  this.iframe_.style.visibility = 'visible';
165  this.currentlyRunningIFrame_ = this.iframe_;
166
167  // Create a new iframe so we're ready to run within it next time around.
168  // But only do this if we're in a real browser. If it's IE, we never
169  // destroy and create new iframes.
170  if (!this.isIE_) {
171    this.iframe_ = this.document_.createElement('iframe');
172    this.iframe_.style.visibility = 'hidden';
173    this.iframe_.title = 'Sandbox iframe';
174    this.iframe_.src = '/sandbox.html';
175    this.renderDiv_.appendChild(this.iframe_);
176  }
177};
178
179
180/**
181 * Attaches an event handler for mouse move.
182 * @param {Function} handler Function to be called in order to handle 
183 *     mouse move events.
184 */
185codepops.Sandbox.prototype.setOnMouseMoveHandler = function(handler) {
186  this.onMouseMove_ = handler;
187};
188
189
190/**
191 * Attaches an event handler for mouse out.
192 * @param {Function} handler Function to be called in order to handle 
193 *     mouse out events.
194 */
195codepops.Sandbox.prototype.setOnMouseOutHandler = function(handler) {
196  this.onMouseOut_ = handler;
197};
198
199
200/**
201 * Attaches an event handler for mouse over.
202 * @param {Function} handler Function to be called in order to handle 
203 *     mouse over events.
204 */
205codepops.Sandbox.prototype.setOnMouseOverHandler = function(handler) {
206  this.onMouseOver_ = handler;
207};
208
209
210/**
211 * Attaches an event handler for touch move.
212 * @param {Function} handler Function to be called in order to handle 
213 *     touch move events.
214 */
215codepops.Sandbox.prototype.setOnTouchMoveHandler = function(handler) {
216  this.onTouchMove_ = handler;
217};
218
219
220/**
221 * Attaches an event handler for touch start.
222 * @param {Function} handler Function to be called in order to handle 
223 *     touch start events.
224 */
225codepops.Sandbox.prototype.setOnTouchStartHandler = function(handler) {
226  this.onTouchStart_ = handler;
227};
228
229
230/**
231 * Attaches a javascript error handler for the sandbox.
232 * @param {Object} onError Function to be called if there is a javascript
233 *     error of any kind.
234 */
235codepops.Sandbox.prototype.setOnErrorHandler = function(onError) {
236  this.onError_ = onError;
237};
238
239
240/**
241 * Attaches a javascript "run success" handler for the sandbox.
242 * @param {Object} onSuccess Function to be called if there is a javascript
243 *     run without errors.
244 */
245codepops.Sandbox.prototype.setOnSuccessHandler = function(onSuccess) {
246  this.onSuccess_ = onSuccess;
247};
248
249
250/**
251 * Attaches an asset load failure handler for the sandbox.
252 * @param {Object} onAssetLoadError Function to be called if there is failure
253 *     when the system loads an asset.
254 */
255codepops.Sandbox.prototype.setOnAssetLoadErrorHandler =
256    function(onAssetLoadError) {
257
258  this.onAssetLoadError_ = onAssetLoadError;
259};
260
261
262/**
263 * Make all sounds stop.
264 */
265codepops.Sandbox.prototype.silence = function() {
266  if (this.iframe_ && this.iframe_.contentWindow.silence) {
267    this.iframe_.contentWindow.silence();
268  }
269  if (this.currentlyRunningIFrame_ &&
270      this.currentlyRunningIFrame_.contentWindow.silence) {
271    this.currentlyRunningIFrame_.contentWindow.silence();
272  }
273};
274
275
276/**
277 * Reset the library and clear all error handlers and intervals.
278 * This stops any animations.
279 */
280codepops.Sandbox.prototype.resetLibrary = function() {
281  if (this.isIE_) {
282    if (this.currentlyRunningIFrame_ &&
283        this.currentlyRunningIFrame_.contentWindow.resetLibrary) {
284      this.currentlyRunningIFrame_.contentWindow.resetLibrary();
285    }
286  } else {
287    // By running a neutral bit of javascript, the sandbox will
288    // wipe out the currently running iframe, which clears everything.
289    this.run('reset()');
290  }
291};
292
293
294/**
295 * Clear out any loop functions that may be running.
296 * This stops any loops.
297 */
298codepops.Sandbox.prototype.resetLoop = function() {
299  if (this.currentlyRunningIFrame_ &&
300     this.currentlyRunningIFrame_.contentWindow &&
301      this.currentlyRunningIFrame_.contentWindow.loop) {
302    this.currentlyRunningIFrame_.contentWindow.loop = function() {};
303  }
304};
305
306
307
308/**
309 * Get a reference to the currently running library object, or null
310 * is nothing is running.
311 * @return {?Library} Either the library, or null.
312 */
313codepops.Sandbox.prototype.getRunningLibrary = function() {
314  if (this.currentlyRunningIFrame_ &&
315      this.currentlyRunningIFrame_.contentWindow &&
316      this.currentlyRunningIFrame_.contentWindow.library) {
317    return this.currentlyRunningIFrame_.contentWindow.library;
318  }
319  return null;
320};
321
322
323/**
324 * Returns a string data URL representing the canvas at its native resolution.
325 * @param {string} type Optional DOMString indicating the image format. The
326 *     default type is 'image/png'.
327 * @param {number} encoderOptions A Number between 0 and 1 indicating image
328 *     quality if the requested type is image/jpeg or image/webp.
329 * @return {string} The URL.
330 */
331codepops.Sandbox.prototype.toDataURL = function(type, encoderOptions) {
332  if (this.currentlyRunningIFrame_ &&
333      this.currentlyRunningIFrame_.contentWindow &&
334      this.currentlyRunningIFrame_.contentWindow.library) {
335    return this.currentlyRunningIFrame_.contentWindow.library.toDataURL(
336        type, encoderOptions);
337  }
338  return null;
339};
340
341
342/**
343 * Tells the sandbox what datastore path should be used for exch
343anging set/get
344 * calls between multiple users of the same app.
345 * @param {string} path The datastore path.
346 */
347codepops.Sandbox.prototype.setCollabPath = function(path) {
348  this.collabPath_ = path;
349};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.