not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

662 lines
24 KiB

  1. // Copyright (C) 2015 Sam Parkinson
  2. // Copyright (C) 2016-17 Walter Bender
  3. // This program is free software; you can redistribute it and/or
  4. // modify it under the terms of the The GNU Affero General Public
  5. // License as published by the Free Software Foundation; either
  6. // version 3 of the License, or (at your option) any later version.
  7. //
  8. // You should have received a copy of the GNU Affero General Public
  9. // License along with this library; if not, write to the Free Software
  10. // Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
  11. const MUSICBLOCKSPREFIX = 'MusicBlocks_';
  12. const APIKEY = '3tgTzMXbbw6xEKX7';
  13. const EMPTYIMAGE = 'data:image/svg+xml;base64,' + btoa('<svg \
  14. xmlns="http://www.w3.org/2000/svg" width="320" height="240" \
  15. viewBox="0 0 320 240"></svg>')
  16. const SERVER = 'https://turtle.sugarlabs.org/server/';
  17. window.server = SERVER; 'https://turtle.sugarlabs.org/server/'; // '/server/';
  18. //{NAME} will be replaced with project name
  19. if (_THIS_IS_MUSIC_BLOCKS_) {
  20. var SHAREURL = 'https://walterbender.github.io/musicblocks/index.html?file={name}&run=True';
  21. } else {
  22. var SHAREURL = 'https://walterbender.github.io/turtleblocksjs/index.html?file={name}&run=True';
  23. }
  24. const NAMESUBTEXT = '{name}';
  25. const LOCAL_PROJECT_STYLE ='\
  26. <style> \
  27. .shareurlspan { \
  28. position: relative; \
  29. } \
  30. .shareurlspan .shareurltext { \
  31. visibility: hidden; \
  32. background-color: black; \
  33. color: #fff; \
  34. text-align: center; \
  35. padding: 10px; \
  36. margin-top; 5px; \
  37. border-radius: 6px; \
  38. position: absolute; \
  39. z-index: 1; \
  40. text-align: left; \
  41. } \
  42. .shareurltext{ \
  43. top: 25px; \
  44. left: -200px; \
  45. visibility: hidden; \
  46. } \
  47. .tooltiptriangle{ \
  48. position: absolute; \
  49. visibility: hidden; \
  50. top: 15px; \
  51. left: 0px; \
  52. width: 0; \
  53. height: 0; \
  54. border-style: solid; \
  55. border-width: 0 15px 15px 15px; \
  56. border-color: transparent transparent black transparent; \
  57. } \
  58. </style>';
  59. //style block is for the tooltip. _NUM_ will be replaced with a unique number
  60. const LOCAL_PROJECT_TEMPLATE ='\
  61. <li data=\'{data}\' title="{title}" current="{current}"> \
  62. <img class="thumbnail" src="{img}" /> \
  63. <div class="options"> \
  64. <input type="text" value="{title}"/><br/> \
  65. <img class="open icon" title="' + _('Open') + '" alt="' + _('Open') + '" src="header-icons/edit.svg" /> \
  66. <img class="delete icon" title="' + _('Delete') + '" alt="' + _('Delete') + '" src="header-icons/delete.svg" /> \
  67. <img class="publish icon" title="' + _('Publish') + '" alt="' + _('Publish') + '" src="header-icons/publish.svg" /> \
  68. <span class="shareurlspan"> \
  69. <img class="share icon" title="' + _('Share') + '" alt="' + _('Share') + '" src="header-icons/share.svg" /> \
  70. <div class="tooltiptriangle" id="shareurltri_NUM_"></div> \
  71. <div class="shareurltext" id="shareurldiv_NUM_"> \
  72. Copy the link to share your project:\
  73. <input type="text" name="shareurl" id="shareurlbox_NUM_" value="url here" style="margin-top:5px;width: 350px;text-align:left;" onblur="document.getElementById(\'shareurldiv_NUM_\').style.visibility = \'hidden\';document.getElementById(\'shareurlbox_NUM_\').style.visibility = \'hidden\';document.getElementById(\'shareurltri_NUM_\').style.visibility = \'hidden\';"/> \
  74. </div> \
  75. </span> \
  76. <img class="download icon" title="' + _('Download') + '" alt="' + _('Download') + '" src="header-icons/download.svg" /> \
  77. </div> \
  78. </li>'
  79. const GLOBAL_PROJECT_TEMPLATE = '\
  80. <img class="thumbnail" src="{img}" /> \
  81. <div class="options"> \
  82. <span>{title}</span><br/> \
  83. <span class="shareurlspan"> \
  84. <img class="share icon" title="' + _('Share') + '" alt="' + _('Share') + '" src="header-icons/share.svg" /> \
  85. <div class="tooltiptriangle" id="plshareurltri_NUM_"></div> \
  86. <div class="shareurltext" id="plshareurldiv_NUM_"> \
  87. Copy the link to share your project:\
  88. <input type="text" name="shareurl" id="plshareurlbox_NUM_" value="url here" style="margin-top:5px;width: 350px;text-align:left;" onblur="document.getElementById(\'plshareurldiv_NUM_\').style.visibility = \'hidden\';document.getElementById(\'plshareurlbox_NUM_\').style.visibility = \'hidden\';document.getElementById(\'plshareurltri_NUM_\').style.visibility = \'hidden\';"/> \
  89. </div> \
  90. </span> \
  91. <img class="download icon" title="' + _('Download') + '" alt="' + _('Download') + '" src="header-icons/download.svg" /> \
  92. </div>';
  93. function PlanetModel(controller) {
  94. this.controller = controller;
  95. this.localProjects = [];
  96. this.globalProjects = [];
  97. this.localChanged = false;
  98. this.globalImagesCache = {};
  99. this.updated = function () {};
  100. this.addGlobalElement = function () {};
  101. this.stop = false;
  102. this.count = 0;
  103. var model = this;
  104. if (sugarizerCompatibility.isInsideSugarizer()) {
  105. storage = sugarizerCompatibility.data;
  106. } else {
  107. storage = localStorage;
  108. }
  109. this.start = function (cb,glo) {
  110. model.updated = cb;
  111. model.addGlobalElement = glo;
  112. model.stop = false;
  113. var myNode = document.querySelector('.planet .content.w');
  114. while (myNode.firstChild) {
  115. myNode.removeChild(myNode.firstChild);
  116. }
  117. this.redoLocalStorageData();
  118. model.updated();
  119. this.downloadWorldWideProjects();
  120. };
  121. this.downloadWorldWideProjects = function () {
  122. jQuery.ajax({
  123. url: SERVER,
  124. headers: {
  125. 'x-api-key': APIKEY
  126. }
  127. }).done(function (l) {
  128. model.globalProjects = [];
  129. model.stop = false;
  130. var todo = [];
  131. l.forEach(function (name, i) {
  132. if (name.indexOf('.b64') !== -1) {
  133. if (_THIS_IS_MUSIC_BLOCKS_) {
  134. todo.push(name);
  135. } else if (!(name.slice(0, MUSICBLOCKSPREFIX.length) == MUSICBLOCKSPREFIX)) {
  136. todo.push(name);
  137. }
  138. }
  139. });
  140. model.count = 0;
  141. model.getImages(todo);
  142. });
  143. };
  144. this.getImages = function (todo) {
  145. if (model.stop === true) {
  146. return;
  147. }
  148. var image = todo.pop();
  149. if (image === undefined) {
  150. return;
  151. }
  152. var name = image.replace('.b64', '');
  153. var mbcheck = false;
  154. if (_THIS_IS_MUSIC_BLOCKS_) {
  155. if (name.slice(0, MUSICBLOCKSPREFIX.length) === MUSICBLOCKSPREFIX){
  156. name = name.substring(MUSICBLOCKSPREFIX.length);
  157. mbcheck = true;
  158. }
  159. }
  160. if (model.globalImagesCache[image] !== undefined) {
  161. model.globalProjects.push({title: name, img: model.globalImagesCache[image]});
  162. model.addGlobalElement(model.globalProjects[model.globalProjects.length-1], model.count);
  163. model.count++;
  164. model.getImages(todo);
  165. } else {
  166. jQuery.ajax({
  167. url: SERVER + image,
  168. headers: {
  169. 'x-api-key' : '3tgTzMXbbw6xEKX7'
  170. },
  171. dataType: 'text'
  172. }).done(function (d) {
  173. if (!validateImageData(d)) {
  174. d = 'images/planetgraphic.png'; // EMPTYIMAGE;
  175. }
  176. if (mbcheck) {
  177. d = 'images/planetgraphic.png';
  178. }
  179. model.globalImagesCache[image] = d;
  180. model.globalProjects.push({title: name, img: d, url: image});
  181. model.addGlobalElement(model.globalProjects[model.globalProjects.length-1], model.count);
  182. model.count++;
  183. model.getImages(todo);
  184. });
  185. }
  186. };
  187. this.redoLocalStorageData = function () {
  188. this.localProjects = [];
  189. s = JSON.stringify(localStorage);
  190. s = s.replace(/\\n/g, "\\n")
  191. .replace(/\\'/g, "\\'")
  192. .replace(/\\"/g, '\\"')
  193. .replace(/\\&/g, "\\&")
  194. .replace(/\\r/g, "\\r")
  195. .replace(/\\t/g, "\\t")
  196. .replace(/\\b/g, "\\b")
  197. .replace(/\\f/g, "\\f");
  198. s = s.replace(/[\u0000-\u0019]+/g,"");
  199. var l = JSON.parse(s);
  200. Object.keys(l).forEach(function (p, i) {
  201. var img = localStorage['SESSIONIMAGE' + p];
  202. if (img === 'undefined') {
  203. img = 'images/planetgraphic.png'; // EMPTYIMAGE;
  204. }
  205. var e = {
  206. title: p,
  207. img: img,
  208. data: localStorage['SESSION' + p],
  209. current: p === localStorage.currentProject
  210. }
  211. if (e.current) {
  212. model.localProjects.unshift(e);
  213. } else {
  214. model.localProjects.push(e);
  215. }
  216. });
  217. this.localChanged = true;
  218. };
  219. this.uniqueName = function (base) {
  220. var l = JSON.parse(localStorage.allProjects);
  221. if (l.indexOf(base) === -1) {
  222. return base;
  223. }
  224. var i = 1;
  225. while (true) {
  226. var name = base + ' ' + i;
  227. if (l.indexOf(name) === -1) {
  228. return name;
  229. }
  230. i++;
  231. }
  232. };
  233. this.newProject = function () {
  234. var name = this.uniqueName('My Project');
  235. model.prepLoadingProject(name);
  236. this.controller.sendAllToTrash(true, true);
  237. model.stop = true;
  238. };
  239. this.renameProject = function (oldName, newName, current) {
  240. if (current) {
  241. localStorage.currentProject = newName;
  242. }
  243. var l = JSON.parse(localStorage.allProjects);
  244. l[l.indexOf(oldName)] = newName;
  245. localStorage.allProjects = JSON.stringify(l);
  246. localStorage['SESSIONIMAGE' + newName] = localStorage['SESSIONIMAGE' + oldName];
  247. localStorage['SESSION' + newName] = localStorage['SESSION' + oldName];
  248. localStorage['SESSIONIMAGE' + oldName] = undefined;
  249. localStorage['SESSION' + oldName] = undefined;
  250. model.redoLocalStorageData();
  251. };
  252. this.delete = function (name) {
  253. var l = JSON.parse(localStorage.allProjects);
  254. l.splice(l.indexOf(name), 1);
  255. localStorage.allProjects = JSON.stringify(l);
  256. localStorage['SESSIONIMAGE' + name] = undefined;
  257. localStorage['SESSION' + name] = undefined;
  258. model.redoLocalStorageData();
  259. model.updated();
  260. };
  261. //Opens up projects in the "On my device" section
  262. this.open = function (name, data) {
  263. localStorage.currentProject = name;
  264. model.controller.sendAllToTrash(false, true);
  265. model.controller.loadRawProject(data);
  266. model.stop = true;
  267. };
  268. //Adds the project from "Worldwide" to the "On my deivce"
  269. //section when download button is clicked
  270. this.prepLoadingProject = function (name) {
  271. localStorage.currentProject = name;
  272. var l = JSON.parse(localStorage.allProjects);
  273. l.push(name);
  274. localStorage.allProjects = JSON.stringify(l);
  275. };
  276. this.load = function (name) {
  277. model.prepLoadingProject(name);
  278. model.controller.sendAllToTrash(false, false);
  279. jQuery.ajax({
  280. url: SERVER + name + '.tb',
  281. headers: {
  282. 'x-api-key' : '3tgTzMXbbw6xEKX7'
  283. },
  284. dataType: 'text',
  285. error: function (XMLHttpRequest, textStatus, errorThrown) {
  286. jQuery.ajax({
  287. url: SERVER + MUSICBLOCKSPREFIX + name + '.tb',
  288. headers: {
  289. 'x-api-key' : '3tgTzMXbbw6xEKX7'
  290. },
  291. dataType: 'text',
  292. }).done(function (d) {
  293. model.controller.loadRawProject(d);
  294. model.stop = true;
  295. });
  296. }
  297. }).done(function (d) {
  298. model.controller.loadRawProject(d);
  299. model.stop = true;
  300. });
  301. };
  302. this.getPublishableName = function (name) {
  303. return name.replace(/['!"#$%&\\'()\*+,\-\.\/:;<=>?@\[\\\]\^`{|}~']/g, '').replace(/ /g, '_');
  304. };
  305. this.publish = function (name, data, image) {
  306. // Show busy cursor.
  307. document.body.style.cursor = 'wait';
  308. setTimeout(function () {
  309. name = model.getPublishableName(name);
  310. if (_THIS_IS_MUSIC_BLOCKS_) {
  311. name = MUSICBLOCKSPREFIX + name;
  312. }
  313. httpPost(name + '.tb', data);
  314. httpPost(name + '.b64', image);
  315. //TODO: append project at beginning
  316. //model.downloadWorldWideProjects();
  317. // Restore default cursor.
  318. document.body.style.cursor = 'default';
  319. }, 250);
  320. };
  321. };
  322. function PlanetView(model, controller) {
  323. this.model = model;
  324. this.controller = controller;
  325. var planet = this; // for future reference
  326. document.querySelector('.planet .new')
  327. .addEventListener('click', function () {
  328. planet.model.newProject();
  329. planet.controller.hide();
  330. });
  331. document.querySelector('#myOpenFile')
  332. .addEventListener('change', function(event) {
  333. planet.controller.hide();
  334. });
  335. document.querySelector('.planet .open')
  336. .addEventListener('click', function () {
  337. document.querySelector('#myOpenFile').focus();
  338. document.querySelector('#myOpenFile').click();
  339. window.scroll(0, 0);
  340. });
  341. document.querySelector('.planet .back')
  342. .addEventListener('click', function () {
  343. planet.controller.hide();
  344. });
  345. this.update = function () {
  346. // This is werid
  347. var model = this;
  348. // console.log('update');
  349. if (model.localChanged) {
  350. html = '';
  351. html = html + LOCAL_PROJECT_STYLE;
  352. model.localProjects.forEach(function (project, i) {
  353. html = html + format(LOCAL_PROJECT_TEMPLATE, project).replace(new RegExp('_NUM_', 'g'), i.toString());
  354. // console.log(i);
  355. // console.log(project);
  356. });
  357. document.querySelector('.planet .content.l').innerHTML = html;
  358. var eles = document.querySelectorAll('.planet .content.l li');
  359. Array.prototype.forEach.call(eles, function (ele, i) {
  360. // console.log(i);
  361. // console.log(ele);
  362. ele.querySelector('.open')
  363. .addEventListener('click', planet.open(ele));
  364. ele.querySelector('.publish')
  365. .addEventListener('click', planet.publish(ele));
  366. ele.querySelector('.share')
  367. .addEventListener('click', planet.share(ele,i));
  368. ele.querySelector('.download')
  369. .addEventListener('click', planet.download(ele));
  370. ele.querySelector('.delete')
  371. .addEventListener('click', planet.delete(ele));
  372. ele.querySelector('input')
  373. .addEventListener('change', planet.input(ele));
  374. ele.querySelector('.thumbnail')
  375. .addEventListener('click', planet.open(ele));
  376. });
  377. model.localChanged = false;
  378. }
  379. };
  380. this.addGlobalElement = function (glob, i){
  381. var d = document.createElement('li');
  382. d.setAttribute('url', glob.url);
  383. d.setAttribute('title', glob.title);
  384. html = '';
  385. html += format(GLOBAL_PROJECT_TEMPLATE, glob).replace(new RegExp('_NUM_', 'g'), i.toString());
  386. d.innerHTML = html;
  387. var htmldata = d;
  388. // console.log(htmldata);
  389. htmldata.querySelector('.thumbnail')
  390. .addEventListener('click', planet.load(htmldata));
  391. htmldata.querySelector('.download')
  392. .addEventListener('click', planet.load(htmldata));
  393. htmldata.querySelector('.share')
  394. .addEventListener('click', planet.planetshare(htmldata,i));
  395. document.querySelector('.planet .content.w').appendChild(htmldata);
  396. }
  397. this.load = function (ele) {
  398. return function () {
  399. planet.model.load(ele.attributes.title.value);
  400. planet.controller.hide();
  401. }
  402. };
  403. this.publish = function (ele) {
  404. return function () {
  405. planet.model.publish(ele.attributes.title.value,
  406. ele.attributes.data.value,
  407. ele.querySelector('img').src);
  408. }
  409. };
  410. this.share = function (ele, i) {
  411. return function () {
  412. planet.model.publish(ele.attributes.title.value, ele.attributes.data.value, ele.querySelector('img').src);
  413. if (_THIS_IS_MUSIC_BLOCKS_) {
  414. var url = SHAREURL.replace(NAMESUBTEXT, MUSICBLOCKSPREFIX + planet.model.getPublishableName(ele.attributes.title.value) + '.tb');
  415. } else {
  416. var url = SHAREURL.replace(NAMESUBTEXT, planet.model.getPublishableName(ele.attributes.title.value) + '.tb');
  417. }
  418. var n = i.toString();
  419. docById('shareurldiv'+n).style.visibility = 'visible';
  420. docById('shareurlbox'+n).style.visibility = 'visible';
  421. docById('shareurltri'+n).style.visibility = 'visible';
  422. docById('shareurlbox'+n).value = url;
  423. docById('shareurlbox'+n).focus();
  424. docById('shareurlbox'+n).select();
  425. };
  426. };
  427. this.planetshare = function (ele, i) {
  428. return function () {
  429. if (_THIS_IS_MUSIC_BLOCKS_) {
  430. var url = SHAREURL.replace(NAMESUBTEXT, MUSICBLOCKSPREFIX + planet.model.getPublishableName(ele.attributes.title.value) + '.tb');
  431. } else {
  432. var url = SHAREURL.replace(NAMESUBTEXT, planet.model.getPublishableName(ele.attributes.title.value) + '.tb');
  433. }
  434. var n = i.toString();
  435. docById('plshareurldiv'+n).style.visibility = 'visible';
  436. docById('plshareurlbox'+n).style.visibility = 'visible';
  437. docById('plshareurltri'+n).style.visibility = 'visible';
  438. docById('plshareurlbox'+n).value = url;
  439. docById('plshareurlbox'+n).focus();
  440. docById('plshareurlbox'+n).select();
  441. };
  442. };
  443. this.download = function (ele) {
  444. return function () {
  445. download(ele.attributes.title.value + '.tb',
  446. 'data:text/plain;charset=utf-8,' + ele.attributes.data.value);
  447. }
  448. };
  449. this.open = function (ele) {
  450. return function () {
  451. docById('statusDiv').style.visibility = localStorage.getItem('isStatusHidden');
  452. docById('statusButtonsDiv').style.visibility = localStorage.getItem('isStatusHidden');
  453. docById('statusTableDiv').style.visibility = localStorage.getItem('isStatusHidden');
  454. if (_THIS_IS_MUSIC_BLOCKS_) {
  455. docById('ptmDiv').style.visibility = localStorage.getItem('isMatrixHidden');
  456. docById('ptmButtonsDiv').style.visibility = localStorage.getItem('isMatrixHidden');
  457. docById('ptmTableDiv').style.visibility = localStorage.getItem('isMatrixHidden');
  458. docById('pscDiv').style.visibility = localStorage.getItem('isStaircaseHidden');
  459. docById('pscButtonsDiv').style.visibility = localStorage.getItem('isStaircaseHidden');
  460. docById('pscTableDiv').style.visibility = localStorage.getItem('isStaircaseHidden');
  461. docById('sliderDiv').style.visibility = localStorage.getItem('isSliderHidden');
  462. docById('sliderButtonsDiv').style.visibility = localStorage.getItem('isSliderHidden');
  463. docById('sliderTableDiv').style.visibility = localStorage.getItem('isSliderHidden');
  464. docById('pdmDiv').style.visibility = localStorage.getItem('isPitchDrumMatrixHidden');
  465. docById('pdmButtonsDiv').style.visibility = localStorage.getItem('isPitchDrumMatrixHidden');
  466. docById('pdmTableDiv').style.visibility = localStorage.getItem('isPitchDrumMatrixHidden');
  467. docById('rulerDiv').style.visibility = localStorage.getItem('isRhythmRulerHidden');
  468. docById('rulerButtonsDiv').style.visibility = localStorage.getItem('isRhythmRulerHidden');
  469. docById('rulerTableDiv').style.visibility = localStorage.getItem('isRhythmRulerHidden');
  470. docById('modeDiv').style.visibility = localStorage.getItem('isModeWidgetHidden');
  471. docById('modeButtonsDiv').style.visibility = localStorage.getItem('isModeWidgetHidden');
  472. docById('modeTableDiv').style.visibility = localStorage.getItem('isModeWidgetHidden');
  473. // Don't reopen the tempo widget since we didn't just hide it, but also closed it.
  474. // docById('tempoDiv').style.visibility = localStorage.getItem('isTempoHidden');
  475. // docById('tempoButtonsDiv').style.visibility = localStorage.getItem('isTempoHidden');
  476. }
  477. if (ele.attributes.current.value === 'true') {
  478. planet.controller.hide();
  479. return;
  480. }
  481. planet.model.open(ele.attributes.title.value, ele.attributes.data.value);
  482. planet.controller.hide();
  483. }
  484. };
  485. this.delete = function (ele) {
  486. return function () {
  487. var title = ele.attributes.title.value;
  488. planet.model.delete(title);
  489. }
  490. };
  491. this.input = function (ele) {
  492. return function () {
  493. var newName = ele.querySelector('input').value;
  494. var oldName = ele.attributes.title.value;
  495. var current = ele.attributes.current.value === 'true';
  496. planet.model.renameProject(oldName, newName, current);
  497. ele.attributes.title.value = newName;
  498. }
  499. };
  500. };
  501. // A viewer for sample projects
  502. function SamplesViewer () {
  503. this.stage = null;
  504. this.sendAllToTrash = null;
  505. this.loadProject = null;
  506. this.loadRawProject = null;
  507. this.init = function () {
  508. this.samples = this; // for future reference
  509. // i18n for section titles
  510. document.querySelector('#planetTitle').innerHTML = _('Planet');
  511. document.querySelector('#planetMyDevice').innerHTML = _('On my device');
  512. document.querySelector('#planetWorldwide').innerHTML = _('Worldwide');
  513. this.model = new PlanetModel(this);
  514. this.view = new PlanetView(this.model, this);
  515. }
  516. this.setClear = function (trash) {
  517. this.sendAllToTrash = trash;
  518. return this;
  519. }
  520. this.setLoad = function (load) {
  521. this.loadProject = load;
  522. return this;
  523. };
  524. this.setStage = function (stage) {
  525. this._stage = stage;
  526. return this;
  527. };
  528. this.setLoadRaw = function (loadRawProject) {
  529. this.loadRawProject = loadRawProject;
  530. return this;
  531. };
  532. this.setRefreshCanvas = function (refreshCanvas) {
  533. this._refreshCanvas = refreshCanvas;
  534. return this;
  535. };
  536. this.setServer = function (server) {
  537. this.server = server;
  538. };
  539. this.hide = function () {
  540. document.querySelector('.planet').style.display = 'none';
  541. document.querySelector('body').classList.remove('samples-shown');
  542. document.querySelector('.canvasHolder').classList.remove('hide');
  543. document.querySelector('#theme-color').content = platformColor.header;
  544. this.samples._stage.enableDOMEvents(true);
  545. window.scroll(0, 0);
  546. };
  547. this.show = function () {
  548. document.querySelector('.planet').style.display = '';
  549. document.querySelector('body').classList.add('samples-shown');
  550. document.querySelector('.canvasHolder').classList.add('hide');
  551. document.querySelector('#theme-color').content = '#8bc34a';
  552. var that = this;
  553. setTimeout(function () {
  554. // Time to release the mouse
  555. that.samples._stage.enableDOMEvents(false);
  556. }, 250);
  557. window.scroll(0, 0);
  558. this.model.start(this.view.update,this.view.addGlobalElement);
  559. return true;
  560. };
  561. };
  562. function validateImageData(d) {
  563. if(d === undefined) {
  564. return false;
  565. }
  566. if(d.indexOf('data:image') !== 0){
  567. return false;
  568. } else {
  569. var data = d.split(',');
  570. if(data[1].length == 0){
  571. return false;
  572. }
  573. }
  574. return true;
  575. };