      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
     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,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';
    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         'element/foreignobject': checkJXG,
    357
    358         'math/bst': makeCheck('Math.BST'),
    359         'math/qdt': makeCheck('Math.Quadtree'),
    360         'math/complex': makeCheck('Complex'),
    361         'math/geometry': makeCheck('Math.Geometry'),
    362         'math/math': makeCheck('Math'),
    363         'math/probfuncs': makeCheck('Math.ProbFuncs'),
    364         'math/ia': makeCheck('Math.IntervalArithmetic'),
    365         'math/extrapolate': makeCheck('Math.Extrapolate'),
    366         'math/metapost': makeCheck('Math.Metapost'),
    367         'math/numerics': makeCheck('Math.Numerics'),
    368         'math/nlp': makeCheck('Math.Nlp'),
    369         'math/plot': makeCheck('Math.Plot'),
    370         'math/poly': makeCheck('Math.Poly'),
    371         'math/statistics': makeCheck('Math.Statistics'),
    372         'math/symbolic': makeCheck('Math.Symbolic'),
    373
    374         'parser/datasource': makeCheck('DataSource'),
    375         'parser/geonext': makeCheck('GeonextParser'),
    376         'parser/ca': makeCheck('CA'),
    377         'parser/jessiecode': makeCheck('JessieCode'),
    378
    379         'reader/cinderella': makeCheck('CinderellaReader'),
    380         'reader/file': makeCheck('FileReader'),
    381         'reader/geogebra': makeCheck('GeogebraReader'),
    382         'reader/geonext': makeCheck('GeonextReader'),
    383         'reader/graph': makeCheck('GraphReader'),
    384         'reader/intergeo': makeCheck('IntergeoReader'),
    385         'reader/sketch': makeCheck('SketchReader'),
    386         'reader/tracenpoche': makeCheck('TracenpocheReader'),
    387
    388         'renderer/abstract': makeCheck('AbstractRenderer'),
    389         'renderer/canvas': makeCheck('CanvasRenderer'),
    390         'renderer/no': makeCheck('NoRenderer'),
    391         'renderer/svg': makeCheck('SVGRenderer'),
    392         'renderer/vml': makeCheck('VMLRenderer'),
    393
    394         'server/server': makeCheck('Server'),
    395
    396         'utils/base64': makeCheck('Util.Base64'),
    397         'utils/color': checkJXG,
    398         'utils/dump': makeCheck('Dump'),
    399         'utils/encoding': makeCheck('Util.UTF8'),
    400         'utils/env': checkJXG,
    401         'utils/event': makeCheck('EventEmitter'),
    402         'utils/expect': makeCheck('Expect'),
    403         'utils/type': checkJXG,
    404         'utils/uuid': makeCheck('Util'),
    405         'utils/xml': makeCheck('XML'),
    406         'utils/zip': makeCheck('Util')
    407     };
    408 }());
    409