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