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