web3d.nocache.mjs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /*
  2. * Copyright 2010 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. window.web3d = function() {
  17. var $wnd = window;
  18. var $doc = document;
  19. /****************************************************************************
  20. * Internal Helper Functions
  21. ***************************************************************************/
  22. function isHostedMode() {
  23. var query = $wnd.location.search;
  24. return ((query.indexOf('gwt.codesvr.web3d=') != -1) ||
  25. (query.indexOf('gwt.codesvr=') != -1));
  26. }
  27. // Helper function to send statistics to the __gwtStatsEvent function if it
  28. // exists.
  29. function sendStats(evtGroupString, typeString) {
  30. if ($wnd.__gwtStatsEvent) {
  31. $wnd.__gwtStatsEvent({
  32. moduleName: 'web3d',
  33. sessionId: $wnd.__gwtStatsSessionId,
  34. subSystem: 'startup',
  35. evtGroup: evtGroupString,
  36. millis:(new Date()).getTime(),
  37. type: typeString,
  38. });
  39. }
  40. }
  41. /****************************************************************************
  42. * Exposed Functions and Variables
  43. ***************************************************************************/
  44. // These are set by various parts of the bootstrapping code, but they always
  45. // need to exist, so give them all default values here.
  46. // Exposed for the convenience of the devmode.js and md5.js files
  47. window.web3d.__sendStats = sendStats;
  48. // Exposed for the call made to gwtOnLoad. Some are not figured out yet, so
  49. // assign them later, once the values are known.
  50. window.web3d.__moduleName = 'web3d';
  51. window.web3d.__errFn = null;
  52. window.web3d.__moduleBase = 'DUMMY';
  53. window.web3d.__softPermutationId = 0;
  54. // Exposed for devmode.js
  55. window.web3d.__computePropValue = null;
  56. // Exposed for super dev mode
  57. window.web3d.__getPropMap = null;
  58. // Exposed for runAsync
  59. window.web3d.__installRunAsyncCode = function() {};
  60. window.web3d.__gwtStartLoadingFragment = function() { return null; };
  61. // Exposed for property provider code
  62. window.web3d.__gwt_isKnownPropertyValue = function() { return false; };
  63. window.web3d.__gwt_getMetaProperty = function() { return null; };
  64. // Exposed for permutations code
  65. var __propertyErrorFunction = null;
  66. // Set up our entry in the page-wide registry of active modules.
  67. // It must be set up before calling computeScriptBase() and
  68. // getCompiledCodeFilename().
  69. var activeModules =
  70. ($wnd.__gwt_activeModules = ($wnd.__gwt_activeModules || {}));
  71. activeModules["web3d"] = {moduleName: "web3d"};
  72. window.web3d.__moduleStartupDone = function(permProps) {
  73. // Make embedded properties available to Super Dev Mode.
  74. // (They override any properties already exported.)
  75. var oldBindings = activeModules["web3d"].bindings;
  76. activeModules["web3d"].bindings = function() {
  77. var props = oldBindings ? oldBindings() : {};
  78. var embeddedProps = permProps[window.web3d.__softPermutationId];
  79. for (var i = 0; i < embeddedProps.length; i++) {
  80. var pair = embeddedProps[i];
  81. props[pair[0]] = pair[1];
  82. }
  83. return props;
  84. };
  85. };
  86. /****************************************************************************
  87. * Internal Helper functions that have been broken out into their own .js
  88. * files for readability and for easy sharing between linkers. The linker
  89. * code will inject these functions in these placeholders.
  90. ***************************************************************************/
  91. // Provides getInstallLocationDoc() function.
  92. // GWT code can be installed anywhere, but an iFrame is the best place if you
  93. // want both variable isolation and runAsync support. Variable isolation is
  94. // useful for avoiding conflicts with JavaScript libraries and critical if
  95. // you want more than one GWT module on your page. The runAsync implementation
  96. // will need to install additional chunks of code into the same iFrame later.
  97. //
  98. // By default, CrossSiteIFrameLinker will use this script to create the iFrame.
  99. // It may be replaced by overriding CrossSiteIframeLinker.getJsInstallLocation()
  100. // to return the name of a different resource file. The replacement script may
  101. // optionally set this variable inside the iframe:
  102. //
  103. // $wnd - the location where the bootstrap module is defined. It should also
  104. // be the location where the __gwtStatsEvent function is defined.
  105. // If not set, the module will set $wnd to window.parent.
  106. var frameDoc;
  107. function getInstallLocationDoc() {
  108. setupInstallLocation();
  109. return frameDoc;
  110. }
  111. // This function is left for compatibility
  112. // and may be used by custom linkers
  113. function getInstallLocation() {
  114. return getInstallLocationDoc().body;
  115. }
  116. function setupInstallLocation() {
  117. if (frameDoc) { return; }
  118. // Create the script frame, making sure it's invisible, but not
  119. // "display:none", which keeps some browsers from running code in it.
  120. var scriptFrame = $doc.createElement('iframe');
  121. scriptFrame.id = 'web3d';
  122. scriptFrame.style.cssText = 'position:absolute; width:0; height:0; border:none; left: -1000px;'
  123. + ' top: -1000px;';
  124. scriptFrame.tabIndex = -1;
  125. $doc.body.appendChild(scriptFrame);
  126. frameDoc = scriptFrame.contentWindow.document;
  127. // The following code is needed for proper operation in Firefox, Safari, and
  128. // Internet Explorer.
  129. //
  130. // In Firefox, this prevents the frame from re-loading asynchronously and
  131. // throwing away the current document.
  132. //
  133. // In IE, it ensures that the <body> element is immediately available.
  134. if (navigator.userAgent.indexOf("Chrome") == -1) {
  135. frameDoc.open();
  136. var doctype = (document.compatMode == 'CSS1Compat') ? '<!doctype html>' : '';
  137. frameDoc.write(doctype + '<html><head></head><body></body></html>');
  138. frameDoc.close();
  139. }
  140. }
  141. // Installs the script directly, by simply appending a script tag with the
  142. // src set to the correct location to the install location.
  143. function installScript(filename) {
  144. // Provides the setupWaitForBodyLoad()function
  145. // Setup code which waits for the body to be loaded and then calls the
  146. // callback function
  147. function setupWaitForBodyLoad(callback) {
  148. // Provides the isBodyLoaded() function
  149. function isBodyLoaded() {
  150. if (typeof $doc.readyState == "undefined") {
  151. // FF 3.5 and below does not have readyState, but it does allow us to
  152. // append to the body before it has finished loading, so we return whether
  153. // the body element exists. Note that for very few apps, this may cause
  154. // problems because they do something in onModuleLoad that assumes the body
  155. // is loaded. For those apps, we provide an alternative implementation
  156. // in isBodyLoadedFf35Fix.js
  157. return (typeof $doc.body != "undefined" && $doc.body != null);
  158. }
  159. return (/loaded|complete/.test($doc.readyState));
  160. }
  161. var bodyDone = isBodyLoaded();
  162. if (bodyDone) {
  163. callback();
  164. return;
  165. }
  166. // If the page is not already loaded, setup some listeners and timers to
  167. // detect when it is done.
  168. function checkBodyDone() {
  169. if (!bodyDone) {
  170. if (!isBodyLoaded()) {
  171. return;
  172. }
  173. bodyDone = true;
  174. callback();
  175. if ($doc.removeEventListener) {
  176. $doc.removeEventListener("readystatechange", checkBodyDone, false);
  177. }
  178. if (onBodyDoneTimerId) {
  179. clearInterval(onBodyDoneTimerId);
  180. }
  181. }
  182. }
  183. // For everyone that supports readystatechange.
  184. if ($doc.addEventListener) {
  185. $doc.addEventListener("readystatechange", checkBodyDone, false);
  186. }
  187. // Fallback. If onBodyDone() gets fired twice, it's not a big deal.
  188. var onBodyDoneTimerId = setInterval(function() {
  189. checkBodyDone();
  190. }, 10);
  191. }
  192. function installCode(code) {
  193. var doc = getInstallLocationDoc();
  194. var docbody = doc.body;
  195. var script = doc.createElement('script');
  196. script.language='javascript';
  197. script.crossOrigin='';
  198. script.src = code;
  199. if (window.web3d.__errFn) {
  200. script.onerror = function() {
  201. window.web3d.__errFn('web3d', new Error("Failed to load " + code));
  202. }
  203. }
  204. docbody.appendChild(script);
  205. }
  206. // Just pass along the filename so that a script tag can be installed in the
  207. // iframe to download it. Since we will be adding the iframe to the body,
  208. // we still need to wait for the body to load before going forward.
  209. setupWaitForBodyLoad(function() {
  210. installCode(filename);
  211. });
  212. }
  213. // Sets the *.__installRunAsyncCode and
  214. // *.__startLoadingFragment functions
  215. window.web3d.__startLoadingFragment = function(fragmentFile) {
  216. return computeUrlForResource(fragmentFile);
  217. };
  218. window.web3d.__installRunAsyncCode = function(code) {
  219. var doc = getInstallLocationDoc();
  220. var docbody = doc.body;
  221. var script = doc.createElement('script');
  222. script.text = code;
  223. docbody.appendChild(script);
  224. // Unless we're in pretty mode, remove the tags to shrink the DOM a little.
  225. // It should have installed its code immediately after being added.
  226. docbody.removeChild(script);
  227. }
  228. // Provides the computeScriptBase() function
  229. function computeScriptBase() {
  230. function getDirectoryOfFile(path) {
  231. // Truncate starting at the first '?' or '#', whichever comes first.
  232. var hashIndex = path.lastIndexOf('#');
  233. if (hashIndex == -1) {
  234. hashIndex = path.length;
  235. }
  236. var queryIndex = path.indexOf('?');
  237. if (queryIndex == -1) {
  238. queryIndex = path.length;
  239. }
  240. var slashIndex = path.lastIndexOf('/', Math.min(queryIndex, hashIndex));
  241. return (slashIndex >= 0) ? path.substring(0, slashIndex + 1) : '';
  242. }
  243. return getDirectoryOfFile(import.meta.url);
  244. }
  245. // Provides the computeUrlForResource() function
  246. function computeUrlForResource(resource) {
  247. /* return an absolute path unmodified */
  248. if (resource.match(/^\//)) {
  249. return resource;
  250. }
  251. /* return a fully qualified URL unmodified */
  252. if (resource.match(/^[a-zA-Z]+:\/\//)) {
  253. return resource;
  254. }
  255. return window.web3d.__moduleBase + resource;
  256. }
  257. // Provides the getCompiledCodeFilename() function
  258. function getCompiledCodeFilename() {
  259. // Default to 0, as the strongName for permutation 0 does not include a ":0" suffix
  260. // for backwards compatibility purposes (@see PermutationsUtil::addPermutationsJs).
  261. var softPermutationId = 0;
  262. var strongName;
  263. try {
  264. // __PERMUTATIONS_BEGIN__
  265. // Permutation logic is injected here. this code populates the
  266. // answers variable.
  267. strongName = '721A8DD6DD3711C964309C520BB22954';// __PERMUTATIONS_END__
  268. var idx = strongName.indexOf(':');
  269. if (idx != -1) {
  270. softPermutationId = parseInt(strongName.substring(idx + 1), 10);
  271. strongName = strongName.substring(0, idx);
  272. }
  273. } catch (e) {
  274. // intentionally silent on property failure
  275. }
  276. window.web3d.__softPermutationId = softPermutationId;
  277. return computeUrlForResource(strongName + '.cache.js');
  278. }
  279. /****************************************************************************
  280. * Bootstrap startup code
  281. ***************************************************************************/
  282. // Must be set before getCompiledFilename() is called
  283. window.web3d.__moduleBase = computeScriptBase();
  284. activeModules["web3d"].moduleBase = window.web3d.__moduleBase;
  285. // Must be done right before the "bootstrap" "end" stat is sent
  286. var filename = getCompiledCodeFilename();
  287. installScript(filename);
  288. return true; // success
  289. }
  290. window.web3d.submodules = {};
  291. window.web3d.onReady = function(submodule, userRender) {
  292. function beforeRender(options, onload) {
  293. return new Promise(resolve => {
  294. var previewImagePath = null;
  295. var previewLoadingPath = null;
  296. var previewPlayPath = null;
  297. var setPreviewImage = function(previewFilePath, loadingFilePath, playFilePath) {
  298. previewImagePath = previewFilePath;
  299. previewLoadingPath = loadingFilePath;
  300. previewPlayPath = playFilePath;
  301. };
  302. var createScreenShotDiv = function(oriWidth, oriHeight, borderColor, showPlayButton) {
  303. var previewContainer = document.createElement("div");
  304. previewContainer.className = "ggb_preview";
  305. previewContainer.style.position = "absolute";
  306. previewContainer.style.zIndex = "90";
  307. previewContainer.style.width = oriWidth-2+'px'; // Remove 2 pixel for the border
  308. previewContainer.style.height = oriHeight-2+'px'; // Remove 2 pixel for the border
  309. previewContainer.style.top = "0px";
  310. previewContainer.style.left = "0px";
  311. previewContainer.style.overflow = "hidden";
  312. previewContainer.style.backgroundColor = "white";
  313. var bc = 'lightgrey';
  314. if (borderColor !== undefined) {
  315. if (borderColor === "none") {
  316. bc = "transparent";
  317. } else {
  318. bc = borderColor;
  319. }
  320. }
  321. previewContainer.style.border = "1px solid " + bc;
  322. var preview = document.createElement("img");
  323. preview.style.position = "relative";
  324. preview.style.zIndex = "1000";
  325. preview.style.top = "-1px"; // Move up/left to hide the border on the image
  326. preview.style.left = "-1px";
  327. if (previewImagePath !== null) {
  328. preview.setAttribute("src", previewImagePath);
  329. }
  330. preview.style.opacity = 0.7;
  331. if (previewLoadingPath !== null) {
  332. var previewOverlay;
  333. var pWidth, pHeight;
  334. if (!showPlayButton) {
  335. previewOverlay = document.createElement("img");
  336. previewOverlay.style.position = "absolute";
  337. previewOverlay.style.zIndex = "1001";
  338. previewOverlay.style.opacity = 1.0;
  339. preview.style.opacity = 0.3;
  340. pWidth = 360;
  341. if (pWidth > (oriWidth/4*3)) {
  342. pWidth = oriWidth/4*3;
  343. }
  344. pHeight = pWidth/5.8;
  345. previewOverlay.setAttribute("src", previewLoadingPath);
  346. previewOverlay.setAttribute("width", pWidth);
  347. previewOverlay.setAttribute("height", pHeight);
  348. var pX = (oriWidth - pWidth) / 2;
  349. var pY = (oriHeight - pHeight) / 2;
  350. previewOverlay.style.left = pX + "px";
  351. previewOverlay.style.top = pY + "px";
  352. previewContainer.appendChild(previewOverlay);
  353. }
  354. }
  355. previewContainer.appendChild(preview);
  356. return previewContainer;
  357. };
  358. var fetchParametersFromApi = function() {
  359. var onSuccess = function(text) {
  360. var jsonData= JSON.parse(text);
  361. // handle either worksheet or single element format
  362. var isGeoGebra = function(element) {return element.type == 'G' || element.type == 'E'};
  363. var item = jsonData.elements ? jsonData.elements.filter(isGeoGebra)[0] : jsonData;
  364. if (!item || !item.url) {
  365. onError();
  366. return;
  367. }
  368. options.filename = item.url;
  369. updateAppletSettings(item.settings || {});
  370. // user setting of preview URL has precedence
  371. var imageDir = 'https://www.geogebra.org/images/';
  372. setPreviewImage(previewImagePath || item.previewUrl,
  373. imageDir + 'GeoGebra_loading.png', imageDir + 'applet_play.png');
  374. buildPreview();
  375. resolve(options);
  376. };
  377. var onError = function() {
  378. options.onError && options.onError();
  379. log('Error: Fetching material (id ' + options.material_id + ') failed.', parameters);
  380. };
  381. sendCorsRequest(
  382. 'https://api.geogebra.org/v1.0/materials/' + options.material_id + '?scope=basic',
  383. onSuccess,
  384. onError
  385. );
  386. };
  387. function buildPreview() {
  388. var oriWidth=options.width;
  389. var oriHeight=options.height;
  390. var previewContainer = createScreenShotDiv(oriWidth, oriHeight, options.borderColor, false);
  391. // This div is needed to have an element with position relative as origin for the absolute positioned image
  392. var previewPositioner = document.createElement("div");
  393. previewPositioner.className = "applet_scaler";
  394. previewPositioner.style.position = "relative";
  395. previewPositioner.style.display = 'block';
  396. previewPositioner.style.width = oriWidth+'px';
  397. previewPositioner.style.height = oriHeight+'px';
  398. previewPositioner.appendChild(previewContainer);
  399. var parentElement = options.element.parentElement;
  400. previewPositioner.appendChild(options.element);
  401. parentElement.appendChild(previewPositioner);
  402. options.removePreview = function() {
  403. var preview = document.querySelector(".ggb_preview");
  404. if (preview) {
  405. preview.parentNode.removeChild(preview);
  406. }
  407. }
  408. GGBAppletUtils.responsiveResize(parentElement, options);
  409. }
  410. function updateAppletSettings(settings) {
  411. var optionNames = ['width', 'height', 'showToolBar', 'showMenuBar',
  412. 'showAlgebraInput', 'allowStyleBar', 'showResetIcon', 'enableLabelDrags',
  413. 'enableShiftDragZoom', 'enableRightClick', 'appName'];
  414. // different defaults in API and web3d
  415. ['enableLabelDrags', 'enableShiftDragZoom', 'enableRightClick'].forEach(function(name) {
  416. settings[name] = !!settings[name];
  417. });
  418. optionNames.forEach(function(name) {
  419. if (options[name] === undefined && settings[name] !== undefined) {
  420. options[name] = settings[name];
  421. }
  422. });
  423. if (options.showToolBarHelp === undefined) {
  424. options.showToolBarHelp = options.showToolBar;
  425. }
  426. }
  427. // Create the XHR object.
  428. function sendCorsRequest(url, onSuccess, onError) {
  429. var xhr = new XMLHttpRequest();
  430. xhr.open('GET', url);
  431. // Response handlers.
  432. xhr.onload = function() {
  433. onSuccess(xhr.responseText);
  434. }
  435. xhr.onerror = onError;
  436. xhr.send();
  437. }
  438. if (options.material_id) {
  439. fetchParametersFromApi();
  440. } else {
  441. resolve(options);
  442. }
  443. var GGBAppletUtils = (function() {
  444. "use strict";
  445. function scaleElement(el, scale) {
  446. if (scale != 1) {
  447. el.style.transformOrigin = "0% 0% 0px";
  448. el.style.webkitTransformOrigin = "0% 0% 0px";
  449. el.style.transform = "scale(" + scale + "," + scale + ")";
  450. el.style.webkitTransform = "scale(" + scale + "," + scale + ")";
  451. el.style.maxWidth = "initial";
  452. // Remove the max width from the image and the div
  453. if (el.querySelector(".ggb_preview") !== null) {
  454. el.querySelector(".ggb_preview").style.maxWidth = "initial";
  455. }
  456. if (el.querySelectorAll('.ggb_preview img')[0] !== undefined) {
  457. el.querySelectorAll('.ggb_preview img')[0].style.maxWidth = "initial";
  458. }
  459. if (el.querySelectorAll('.ggb_preview img')[1] !== undefined) {
  460. el.querySelectorAll('.ggb_preview img')[1].style.maxWidth = "initial"
  461. }
  462. } else {
  463. el.style.transform = "none";
  464. el.style.webkitTransform = "none";
  465. }
  466. }
  467. function getWidthHeight(appletElem, appletWidth, allowUpscale, autoHeight, noBorder, scaleContainerClass) {
  468. // Find the container class
  469. var container = null;
  470. if (scaleContainerClass != undefined && scaleContainerClass != '') {
  471. var parent = appletElem.parentNode;
  472. while(parent != null) {
  473. if ((' ' + parent.className + ' ').indexOf(' ' + scaleContainerClass + ' ') > -1) {
  474. container = parent;
  475. break;
  476. } else {
  477. parent = parent.parentNode;
  478. }
  479. }
  480. }
  481. var myWidth = 0, myHeight = 0, windowWidth = 0, border = 0, borderRight = 0, borderLeft = 0, borderTop = 0;
  482. if (container) {
  483. myWidth = container.offsetWidth;
  484. myHeight = Math.max(autoHeight ? container.offsetWidth : 0, container.offsetHeight);
  485. } else {
  486. if (window.innerWidth && document.documentElement.clientWidth) {
  487. myWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
  488. myHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
  489. // Using mywith instead of innerWidth because after rotating a mobile device the innerWidth is sometimes wrong (e.g. on Galaxy Note III)
  490. // windowWidth = window.innerWidth
  491. windowWidth = myWidth;
  492. } else {
  493. //Non-IE
  494. myWidth = window.innerWidth;
  495. myHeight = window.innerHeight;
  496. windowWidth = window.innerWidth;
  497. }
  498. if (appletElem) {
  499. var rect = appletElem.getBoundingClientRect();
  500. if (rect.left > 0) {
  501. if (rect.left <= myWidth && (noBorder === undefined || !noBorder)) {
  502. if (document.dir === 'rtl') {
  503. borderRight = myWidth - rect.width - rect.left;
  504. borderLeft = (windowWidth <= 480 ? 10 : 30);
  505. } else {
  506. borderLeft = rect.left;
  507. borderRight = (windowWidth <= 480 ? 10 : 30);
  508. }
  509. border = borderLeft + borderRight;
  510. }
  511. }
  512. }
  513. }
  514. if (appletElem) {
  515. if ((allowUpscale === undefined || !allowUpscale) && appletWidth > 0 && appletWidth + border < myWidth) {
  516. myWidth = appletWidth;
  517. } else {
  518. myWidth -= border;
  519. }
  520. }
  521. return {width: myWidth, height: myHeight};
  522. }
  523. function calcScale(parameters, appletElem, allowUpscale, showPlayButton, scaleContainerClass){
  524. if (parameters.isScreenshoGenerator) {
  525. return 1;
  526. }
  527. var ignoreHeight = (showPlayButton !== undefined && showPlayButton);
  528. var noScaleMargin = parameters.noScaleMargin != undefined && parameters.noScaleMargin;
  529. var valBoolean = function(value) {
  530. return (value && value !== "false");
  531. };
  532. var autoHeight = valBoolean(parameters.autoHeight);
  533. var windowSize = getWidthHeight(appletElem, parameters.width, allowUpscale, autoHeight, noScaleMargin, scaleContainerClass);
  534. var windowWidth = parseInt(windowSize.width);
  535. var appletWidth = parameters.width;
  536. var appletHeight = parameters.height;
  537. if (appletWidth === undefined) {
  538. var article = appletElem.querySelector('.appletParameters');
  539. if (article) {
  540. appletWidth = article.offsetWidth;
  541. appletHeight = article.offsetHeight;
  542. }
  543. }
  544. var xscale = windowWidth / appletWidth;
  545. var yscale = (ignoreHeight ? 1 : windowSize.height / appletHeight);
  546. if (allowUpscale !== undefined && !allowUpscale) {
  547. xscale = Math.min(1, xscale);
  548. yscale = Math.min(1, yscale);
  549. }
  550. return Math.min(xscale, yscale);
  551. }
  552. function getScale(parameters, appletElem, showPlayButton) {
  553. var scale = 1,
  554. autoScale,
  555. allowUpscale = false;
  556. if (parameters.hasOwnProperty('allowUpscale')) {
  557. allowUpscale = parameters.allowUpscale;
  558. }
  559. if (parameters.hasOwnProperty('scale')) {
  560. scale = parseFloat(parameters.scale);
  561. if (isNaN(scale) || scale === null || scale === 0) {
  562. scale = 1;
  563. }
  564. if (scale > 1) {
  565. allowUpscale = true;
  566. }
  567. }
  568. if (!(parameters.hasOwnProperty('disableAutoScale') && parameters.disableAutoScale)) {
  569. autoScale = calcScale(parameters, appletElem, allowUpscale, showPlayButton, parameters.scaleContainerClass);
  570. } else {
  571. return scale;
  572. }
  573. if (allowUpscale && (!parameters.hasOwnProperty('scale') || scale === 1)) {
  574. return autoScale;
  575. } else {
  576. return Math.min(scale, autoScale);
  577. }
  578. }
  579. function responsiveResize(appletElem, parameters) {
  580. var article = appletElem.querySelector(".ggb_preview");
  581. if (article) {
  582. if(article.parentElement && (/fullscreen/).test(article.parentElement.className)){
  583. return; //fullscreen button inside applet pressed
  584. }
  585. var scale = getScale(parameters, appletElem);
  586. var scaleElem = null;
  587. for (var i = 0; i < appletElem.childNodes.length; i++) {
  588. if (appletElem.childNodes[i].className !== undefined && appletElem.childNodes[i].className.match(/^applet_scaler/)) {
  589. scaleElem = appletElem.childNodes[i];
  590. break;
  591. }
  592. }
  593. if (scaleElem !== null && scaleElem.querySelector(".noscale") !== null) {
  594. return;
  595. }
  596. var appName = (parameters.id !== undefined ? parameters.id : "ggbApplet");
  597. var app = window[appName];
  598. if ((app == null || !app.recalculateEnvironments) && scaleElem !== null && !scaleElem.className.match(/fullscreen/)) {
  599. scaleElem.parentNode.style.transform = "";
  600. if (!isNaN(scale) && scale !== 1) {
  601. // Set the scale factor for the applet
  602. scaleElem.parentNode.style.width = (parameters.width * scale) + 'px';
  603. scaleElem.parentNode.style.height = (parameters.height * scale) + 'px';
  604. scaleElement(scaleElem, scale);
  605. } else {
  606. // Remove scaling
  607. scaleElement(scaleElem, 1);
  608. scaleElem.parentNode.style.width = (parameters.width) + 'px';
  609. scaleElem.parentNode.style.height = (parameters.height) + 'px';
  610. }
  611. }
  612. }
  613. }
  614. return {
  615. responsiveResize: responsiveResize,
  616. getScale: getScale,
  617. scaleElement: scaleElement
  618. };
  619. })();
  620. });
  621. }
  622. const render = (options, onload) => {
  623. beforeRender(options, onload).then(opts => userRender(opts, onload))
  624. }
  625. for (let callback of window.web3d.submodules[submodule].callbacks) {
  626. callback(render);
  627. }
  628. window.web3d.submodules[submodule].render = render;
  629. }
  630. window.web3d.succeeded = window.web3d();
  631. function Widget(options, submodule, baseTag) {
  632. const self = this;
  633. self.loading = false;
  634. this.apiCallbacks = [api => self.api = api];
  635. function runCallbacks(api) {
  636. for (const callback of self.apiCallbacks) {
  637. callback(api);
  638. }
  639. if (options.removePreview) {
  640. options.removePreview();
  641. }
  642. }
  643. function load() {
  644. self.loading = true;
  645. if (submodule.render) {
  646. submodule.render(options, runCallbacks);
  647. } else {
  648. submodule.callbacks.push(render => render(options, runCallbacks));
  649. }
  650. }
  651. this.inject = function(element) {
  652. const target = document.createElement(baseTag);
  653. options.element = target;
  654. element.appendChild(target);
  655. load();
  656. return this;
  657. }
  658. this.getAPI = function() {
  659. return new Promise(resolve => {
  660. if (self.api) {
  661. resolve(self.api);
  662. } else if (self.loading) {
  663. self.apiCallbacks.push(resolve);
  664. } else {
  665. load(resolve);
  666. }
  667. });
  668. }
  669. if (options.tagName || options.element) {
  670. load();
  671. }
  672. }
  673. const createSubmoduleAPI = (submodule, baseTag) => {
  674. window.web3d.submodules[submodule] = {callbacks:[]};
  675. return {
  676. create: (options) => {
  677. return new Widget(options || {}, window.web3d.submodules[submodule], baseTag);
  678. }
  679. }
  680. };
  681. // add export statements
  682. export const mathApps = createSubmoduleAPI("mathApps", "div");