web.nocache.mjs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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.web = 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.web=') != -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: 'web',
  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.web.__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.web.__moduleName = 'web';
  51. window.web.__errFn = null;
  52. window.web.__moduleBase = 'DUMMY';
  53. window.web.__softPermutationId = 0;
  54. // Exposed for devmode.js
  55. window.web.__computePropValue = null;
  56. // Exposed for super dev mode
  57. window.web.__getPropMap = null;
  58. // Exposed for runAsync
  59. window.web.__installRunAsyncCode = function() {};
  60. window.web.__gwtStartLoadingFragment = function() { return null; };
  61. // Exposed for property provider code
  62. window.web.__gwt_isKnownPropertyValue = function() { return false; };
  63. window.web.__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["web"] = {moduleName: "web"};
  72. window.web.__moduleStartupDone = function(permProps) {
  73. // Make embedded properties available to Super Dev Mode.
  74. // (They override any properties already exported.)
  75. var oldBindings = activeModules["web"].bindings;
  76. activeModules["web"].bindings = function() {
  77. var props = oldBindings ? oldBindings() : {};
  78. var embeddedProps = permProps[window.web.__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 = 'web';
  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.web.__errFn) {
  200. script.onerror = function() {
  201. window.web.__errFn('web', 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.web.__startLoadingFragment = function(fragmentFile) {
  216. return computeUrlForResource(fragmentFile);
  217. };
  218. window.web.__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.web.__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 = '03AC6A979CF3ACBAEC7A4498AE960BB9';// __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.web.__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.web.__moduleBase = computeScriptBase();
  284. activeModules["web"].moduleBase = window.web.__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.web.submodules = {};
  291. window.web.onReady = function(submodule, userRender) {
  292. function beforeRender(options, onload) {
  293. return new Promise(resolve => {
  294. resolve(options)
  295. });
  296. }
  297. const render = (options, onload) => {
  298. beforeRender(options, onload).then(opts => userRender(opts, onload))
  299. }
  300. for (let callback of window.web.submodules[submodule].callbacks) {
  301. callback(render);
  302. }
  303. window.web.submodules[submodule].render = render;
  304. }
  305. window.web.succeeded = window.web();
  306. function Widget(options, submodule, baseTag) {
  307. const self = this;
  308. self.loading = false;
  309. this.apiCallbacks = [api => self.api = api];
  310. function runCallbacks(api) {
  311. for (const callback of self.apiCallbacks) {
  312. callback(api);
  313. }
  314. if (options.removePreview) {
  315. options.removePreview();
  316. }
  317. }
  318. function load() {
  319. self.loading = true;
  320. if (submodule.render) {
  321. submodule.render(options, runCallbacks);
  322. } else {
  323. submodule.callbacks.push(render => render(options, runCallbacks));
  324. }
  325. }
  326. this.inject = function(element) {
  327. const target = document.createElement(baseTag);
  328. options.element = target;
  329. element.appendChild(target);
  330. load();
  331. return this;
  332. }
  333. this.getAPI = function() {
  334. return new Promise(resolve => {
  335. if (self.api) {
  336. resolve(self.api);
  337. } else if (self.loading) {
  338. self.apiCallbacks.push(resolve);
  339. } else {
  340. load(resolve);
  341. }
  342. });
  343. }
  344. if (options.tagName || options.element) {
  345. load();
  346. }
  347. }
  348. const createSubmoduleAPI = (submodule, baseTag) => {
  349. window.web.submodules[submodule] = {callbacks:[]};
  350. return {
  351. create: (options) => {
  352. return new Widget(options || {}, window.web.submodules[submodule], baseTag);
  353. }
  354. }
  355. };
  356. // add export statements
  357. export const mathApps = createSubmoduleAPI("mathApps", "div");