1 /*
  2     Copyright 2008-2022
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Andreas Walter,
  8         Alfred Wassermann,
  9         Peter Wilfahrt
 10 
 11     This file is part of JSXGraph.
 12 
 13     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 14 
 15     You can redistribute it and/or modify it under the terms of the
 16 
 17       * GNU Lesser General Public License as published by
 18         the Free Software Foundation, either version 3 of the License, or
 19         (at your option) any later version
 20       OR
 21       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 22 
 23     JSXGraph is distributed in the hope that it will be useful,
 24     but WITHOUT ANY WARRANTY; without even the implied warranty of
 25     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 26     GNU Lesser General Public License for more details.
 27 
 28     You should have received a copy of the GNU Lesser General Public License and
 29     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 30     and <http://opensource.org/licenses/MIT/>.
 31  */
 32 
 33 /*global JXG: true, document: true*/
 34 /*jslint nomen: true, plusplus: true, regexp: true*/
 35 
 36 /**
 37  * JSXGraph namespace. Holds all classes, objects, functions and variables belonging to JSXGraph
 38  * to reduce the risk of interfering with other JavaScript code.
 39  * @namespace
 40  */
 41 var JXG = {},
 42   define;
 43 
 44 (function () {
 45   "use strict";
 46 
 47   //////////////////////////////////////////////////////////////////////////
 48   //// Set this constant to 'true' to add an timestamp to each imported ////
 49   //// file. This ensures that the most up-to-date files are always     ////
 50   //// used during development.                                         ////
 51   ////                                                                  ////
 52   ////             Attention! Slows down the loading time!              ////
 53   //////////////////////////////////////////////////////////////////////////
 54   var preventCachingFiles = true,
 55     // check and table are initialized at the end of the life
 56     table,
 57     waitlist = [],
 58     checkwaitlist = true,
 59     checkJXG = function () {
 60       return JXG;
 61     },
 62     makeCheck = function (s) {
 63       var a = s.split(".");
 64 
 65       return function () {
 66         var i,
 67           r = JXG;
 68 
 69         if (!r) {
 70           return r;
 71         }
 72 
 73         for (i = 0; i < a.length; i++) {
 74           r = r[a[i]];
 75           if (!r) {
 76             break;
 77           }
 78         }
 79 
 80         return r;
 81       };
 82     };
 83 
 84   define = function (deps, factory) {
 85     var i,
 86       oldlength,
 87       undef,
 88       resDeps = [],
 89       inc = true;
 90 
 91     if (deps === undef) {
 92       deps = [];
 93     }
 94 
 95     window.wait = waitlist;
 96 
 97     if (factory === undef) {
 98       factory = function () {};
 99     }
100 
101     for (i = 0; i < deps.length; i++) {
102       resDeps.push(table[deps[i]]());
103       if (!resDeps[i]) {
104         inc = false;
105         break;
106       }
107     }
108 
109     if (inc) {
110       factory.apply(this, resDeps);
111     } else if (checkwaitlist) {
112       waitlist.push([deps, factory]);
113     }
114 
115     if (checkwaitlist) {
116       // don't go through the waitlist while we're going through the waitlist
117       checkwaitlist = false;
118       oldlength = 0;
119 
120       // go through the waitlist until no more modules can be loaded
121       while (oldlength !== waitlist.length) {
122         oldlength = waitlist.length;
123 
124         // go through the waitlist, look if another module can be initialized
125         for (i = 0; i < waitlist.length; i++) {
126           if (define.apply(this, waitlist[i])) {
127             waitlist.splice(i, 1);
128           }
129         }
130       }
131 
132       checkwaitlist = true;
133     }
134 
135     return inc;
136   };
137 
138   JXG.isMetroApp = function () {
139     return (
140       typeof window === "object" &&
141       window.clientInformation &&
142       window.clientInformation.appVersion &&
143       window.clientInformation.appVersion.indexOf("MSAppHost") > -1
144     );
145   };
146 
147   ////////////////////////////////////////////////////////////////////////////////
148   /////////////////////// this exists also in sketchometry ///////////////////////
149   ////////////////////////////////////////////////////////////////////////////////
150 
151   JXG.Load = (function () {
152     var requirePathLocation = "href",
153       allowDocumentWrite = true;
154 
155     function createHTMLElement(tagName, attr) {
156       var el = document.createElement(tagName),
157         i,
158         a_name,
159         a_value,
160         a_object;
161 
162       for (i = 0; i < Object.keys(attr).length; i++) {
163         a_name = Object.keys(attr)[i];
164         a_value = attr[a_name];
165 
166         a_object = document.createAttribute(a_name);
167         a_object.nodeValue = a_value;
168         el.setAttributeNode(a_object);
169       }
170 
171       return el;
172     }
173 
174     window.onload = function () {
175       allowDocumentWrite = false;
176     };
177 
178     return {
179       requirePath: window.location.href,
180 
181       getPathOfScriptFile: function (filename) {
182         var scripts,
183           reg,
184           i,
185           s,
186           requirePath = "";
187 
188         scripts = document.getElementsByTagName("script");
189         reg = new RegExp(filename + "(\\?.*)?$");
190 
191         for (i = 0; i < scripts.length; i++) {
192           s = scripts[i];
193           if (s.src && s.src.match(reg)) {
194             requirePath = s.src.replace(reg, "");
195             break;
196           }
197         }
198 
199         return requirePath;
200       },
201 
202       setRequirePathToScriptFile: function (filename) {
203         if (requirePathLocation === filename) {
204           return;
205         }
206 
207         JXG.Load.requirePath = JXG.Load.getPathOfScriptFile(filename);
208         requirePathLocation = filename;
209       },
210 
211       setRequirePathToHref: function () {
212         JXG.Load.requirePath = window.location.href;
213         requirePathLocation = "href";
214       },
215 
216       JSfiles: function (fileArray, preventCaching, root, strictOrder) {
217         var postfix = "",
218           i,
219           file;
220 
221         preventCaching = preventCaching || false;
222         if (preventCaching) {
223           postfix = "?v=" + new Date().getTime();
224         }
225         root = root || JXG.Load.requirePath;
226         if (root.substr(-1) !== "/") {
227           root += "/";
228         }
229         strictOrder = strictOrder || false;
230 
231         for (i = 0; i < fileArray.length; i++) {
232           file = fileArray[i];
233 
234           if (file.substr(-2) !== "js") {
235             file += ".js";
236           }
237           (function (include) {
238             var src = root + include + postfix,
239               el,
240               head;
241             if (JXG.isMetroApp() || !allowDocumentWrite) {
242               el = createHTMLElement("script", {
243                 type: "text/javascript",
244                 src: src
245               });
246               if(strictOrder) {
247                 el.defer = true;
248                 el.async = false;
249               }
250               head = document.getElementsByTagName("head")[0];
251               head.appendChild(el);
252             } else {
253               // avoid inline code manipulation
254               document.write(
255                 '<script type="text/javascript" src="' + src + '"></script>'
256               );
257             }
258           })(file);
259         }
260       },
261 
262       CSSfiles: function (fileArray, preventCaching, root) {
263         var postfix = "",
264           i,
265           file;
266 
267         preventCaching = preventCaching || false;
268         if (preventCaching) {
269           postfix = "?v=" + new Date().getTime();
270         }
271         root = root || JXG.Load.requirePath;
272         if (root.substr(-1) !== "/") {
273           root += "/";
274         }
275 
276         for (i = 0; i < fileArray.length; i++) {
277           file = fileArray[i];
278 
279           if (file.substr(-3) !== "css") {
280             file += ".css";
281           }
282           (function (include) {
283             var href = root + include + postfix,
284               el = createHTMLElement("link", {
285                 rel: "stylesheet",
286                 type: "text/javascript",
287                 href: href,
288               }),
289               head = document.getElementsByTagName("head")[0];
290             head.appendChild(el);
291           })(file);
292         }
293       },
294 
295       HTMLfileASYNC: function (
296         file,
297         innerHTMLof,
298         doAfter,
299         preventCaching,
300         root
301       ) {
302         var postfix = "";
303 
304         doAfter = doAfter || function () {};
305         preventCaching = preventCaching || false;
306         if (preventCaching) {
307           postfix = "?v=" + new Date().getTime();
308         }
309         root = root || JXG.Load.requirePath;
310         if (root.substr(-1) !== "/") {
311           root += "/";
312         }
313 
314         if (file.substr(-4) !== "html") {
315           file += ".html";
316         }
317         (function (include) {
318           var url = root + include + postfix;
319 
320           var xhr = new XMLHttpRequest();
321           xhr.onreadystatechange = function () {
322             if (xhr.readyState === 4) {
323               if (xhr.status === 200) {
324                 innerHTMLof.innerHTML = xhr.responseText;
325                 doAfter();
326               }
327             }
328           };
329 
330           xhr.open("POST", url, true);
331           xhr.send();
332         })(file);
333       },
334     };
335   })();
336 
337   ////////////////////////////////////////////////////////////////////////////////
338   ///////////////////////////////////// end //////////////////////////////////////
339   ////////////////////////////////////////////////////////////////////////////////
340 
341   // Has to be a String for Makefile!
342   JXG.Load.baseFiles = 'jxg,base/constants,utils/type,utils/xml,utils/env,utils/event,utils/expect,utils/color,math/probfuncs,math/math,math/ia,math/extrapolate,math/numerics,math/nlp,math/plot,math/metapost,math/statistics,math/symbolic,math/geometry,math/clip,math/poly,math/complex,renderer/abstract,renderer/no,reader/file,parser/geonext,base/board,options,jsxgraph,base/element,base/coordselement,base/coords,base/point,base/line,base/group,base/circle,element/conic,base/polygon,base/curve,element/arc,element/sector,base/composition,element/composition,base/text,base/image,element/slider,element/measure,base/chart,base/transformation,base/turtle,base/ticks,utils/zip,utils/base64,utils/uuid,utils/encoding,server/server,element/locus,parser/datasource,parser/ca,parser/jessiecode,utils/dump,renderer/svg,renderer/vml,renderer/canvas,renderer/no,element/comb,element/slopetriangle,math/qdt,element/checkbox,element/input,element/button,base/foreignobject,options3d,3d/view3d,3d/element3d,3d/point3d,3d/curve3d,3d/surface3d,3d/linspace3d,3d/box3d';
343   JXG.Load.setRequirePathToScriptFile("loadjsxgraph.js");
344   JXG.Load.JSfiles(JXG.Load.baseFiles.split(","), preventCachingFiles);
345   JXG.Load.baseFiles = null;
346   JXG.serverBase = JXG.Load.requirePath + "server/";
347 
348   // This is a table with functions which check the availability
349   // of certain namespaces, functions and classes. With this structure
350   // we are able to get a rough check if a specific dependency is available.
351   table = {
352     jsxgraph: checkJXG,
353     jxg: checkJXG,
354     options: makeCheck("Options"),
355 
356     "base/board": makeCheck("Board"),
357     "base/chart": checkJXG,
358     "base/circle": checkJXG,
359     "base/composition": makeCheck("Composition"),
360     "base/constants": checkJXG,
361     "base/coords": makeCheck("Coords"),
362     "base/coordselement": makeCheck("CoordsElement"),
363     "base/curve": checkJXG,
364     "base/element": makeCheck("GeometryElement"),
365     "base/group": checkJXG,
366     "base/image": checkJXG,
367     "base/line": checkJXG,
368     "base/point": checkJXG,
369     "base/polygon": checkJXG,
370     "base/text": checkJXG,
371     "base/ticks": checkJXG,
372     "base/transformation": checkJXG,
373     "base/turtle": checkJXG,
374 
375     "element/arc": checkJXG,
376     "element/centroid": checkJXG,
377     "element/composition": checkJXG,
378     "element/conic": checkJXG,
379     "element/locus": checkJXG,
380     "element/measure": checkJXG,
381     "element/sector": checkJXG,
382     "element/slider": checkJXG,
383     "element/square": checkJXG,
384     "element/triangle": checkJXG,
385     "element/checkbox": checkJXG,
386     "element/input": checkJXG,
387     "element/button": checkJXG,
388     "element/foreignobject": checkJXG,
389 
390     "math/bst": makeCheck("Math.BST"),
391     "math/qdt": makeCheck("Math.Quadtree"),
392     "math/complex": makeCheck("Complex"),
393     "math/geometry": makeCheck("Math.Geometry"),
394     "math/math": makeCheck("Math"),
395     "math/probfuncs": makeCheck("Math.ProbFuncs"),
396     "math/ia": makeCheck("Math.IntervalArithmetic"),
397     "math/extrapolate": makeCheck("Math.Extrapolate"),
398     "math/metapost": makeCheck("Math.Metapost"),
399     "math/numerics": makeCheck("Math.Numerics"),
400     "math/nlp": makeCheck("Math.Nlp"),
401     "math/plot": makeCheck("Math.Plot"),
402     "math/poly": makeCheck("Math.Poly"),
403     "math/statistics": makeCheck("Math.Statistics"),
404     "math/symbolic": makeCheck("Math.Symbolic"),
405 
406     "parser/datasource": makeCheck("DataSource"),
407     "parser/geonext": makeCheck("GeonextParser"),
408     "parser/ca": makeCheck("CA"),
409     "parser/jessiecode": makeCheck("JessieCode"),
410 
411     "reader/cinderella": makeCheck("CinderellaReader"),
412     "reader/file": makeCheck("FileReader"),
413     "reader/geogebra": makeCheck("GeogebraReader"),
414     "reader/geonext": makeCheck("GeonextReader"),
415     "reader/graph": makeCheck("GraphReader"),
416     "reader/intergeo": makeCheck("IntergeoReader"),
417     "reader/sketch": makeCheck("SketchReader"),
418     "reader/tracenpoche": makeCheck("TracenpocheReader"),
419 
420     "renderer/abstract": makeCheck("AbstractRenderer"),
421     "renderer/canvas": makeCheck("CanvasRenderer"),
422     "renderer/no": makeCheck("NoRenderer"),
423     "renderer/svg": makeCheck("SVGRenderer"),
424     "renderer/vml": makeCheck("VMLRenderer"),
425 
426     "server/server": makeCheck("Server"),
427 
428     "utils/base64": makeCheck("Util.Base64"),
429     "utils/color": checkJXG,
430     "utils/dump": makeCheck("Dump"),
431     "utils/encoding": makeCheck("Util.UTF8"),
432     "utils/env": checkJXG,
433     "utils/event": makeCheck("EventEmitter"),
434     "utils/expect": makeCheck("Expect"),
435     "utils/type": checkJXG,
436     "utils/uuid": makeCheck("Util"),
437     "utils/xml": makeCheck("XML"),
438     "utils/zip": makeCheck("Util"),
439 
440     "3d/threed": checkJXG,
441     "3d/view3d": checkJXG,
442     "3d/point3d": checkJXG,
443     "3d/curve3d": checkJXG,
444     "3d/surface3d": checkJXG,
445     "3d/linspace3d": checkJXG,
446   };
447 })();
448