      1 /*
      2     Copyright 2008-2017
      3         Matthias Ehmann,
      4         Michael Gerhaeuser,
      5         Carsten Miller,
      6         Bianca Valentin,
      7         Alfred Wassermann,
      8         Peter Wilfahrt
      9
     10     This file is part of JSXGraph and JSXCompressor.
     11
     12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
     13     JSXCompressor is free software dual licensed under the GNU LGPL or Apache 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       OR
     23       * Apache License Version 2.0
     24
     25     JSXGraph is distributed in the hope that it will be useful,
     26     but WITHOUT ANY WARRANTY; without even the implied warranty of
     27     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     28     GNU Lesser General Public License for more details.
     29
     30     You should have received a copy of the GNU Lesser General Public License, Apache
     31     License, and the MIT License along with JSXGraph. If not, see
     32     <http://www.gnu.org/licenses/>, <https://www.apache.org/licenses/LICENSE-2.0.html>,
     33     and <http://opensource.org/licenses/MIT/>.
     34
     35  */
     36
     37
     38 /*global JXG: true, define: true, jQuery: true, window: true, document: true, navigator: true, require: true, module: true, console: true */
     39 /*jslint nomen:true, plusplus:true, forin:true*/
     40
     41 /* depends:
     42  */
     43
     44 /**
     45  * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards.
     46  * It has methods to create, save, load and free boards. Additionally some helper functions are
     47  * defined in this file directly in the JXG namespace.
     48  */
     49
     50 define([], function () {
     51
     52     "use strict";
     53
     54     /**
     55      * JXG is the top object of JSXGraph and defines the namespace
     56      */
     57     var jxg = {};
     58
     59     // Make sure JXG.extend is not defined
     60     // If jsxgraph is loaded via loadjsxgraph.js, this is required, but JXG.extend will be undefined
     61     // If jsxgraph is compiled as an amd module, it is possible that another jsxgraph version is already loaded and we
     62     // therefore must not re-use the global JXG variable. But in this case JXG.extend will already be defined.
     63     // This is the reason for this check.
     64     if (typeof JXG === 'object' && !JXG.extend) {
     65         jxg = JXG;
     66     }
     67
     68     // We need the following two methods "extend" and "shortcut" to create the JXG object via JXG.extend.
     69
     70     /**
     71      * Copy all properties of the <tt>extension</tt> object to <tt>object</tt>.
     72      * @param {Object} object
     73      * @param {Object} extension
     74      * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties.
     75      * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes
     76      */
     77     jxg.extend = function (object, extension, onlyOwn, toLower) {
     78         var e, e2;
     79
     80         onlyOwn = onlyOwn || false;
     81         toLower = toLower || false;
     82
     83         // the purpose of this for...in loop is indeed to use hasOwnProperty only if the caller
     84         // explicitly wishes so.
     85         for (e in extension) {
     86             if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) {
     87                 if (toLower) {
     88                     e2 = e.toLowerCase();
     89                 } else {
     90                     e2 = e;
     91                 }
     92
     93                 object[e2] = extension[e];
     94             }
     95         }
     96     };
     97
     98     jxg.extend(jxg, /** @lends JXG */ {
     99         /**
    100          * Store a reference to every board in this central list. This will at some point
    101          * replace JXG.JSXGraph.boards.
    102          * @type Object
    103          */
    104         boards: {},
    105
    106         /**
    107          * Store the available file readers in this structure.
    108          * @type Object
    109          */
    110         readers: {},
    111
    112         /**
    113          * Associative array that keeps track of all constructable elements registered
    114          * via {@link JXG.JSXGraph.registerElement}.
    115          * @type Object
    116          */
    117         elements: {},
    118
    119         /**
    120          * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create}
    121          * interface.
    122          * @param {String} element The elements name. This is case-insensitive, existing elements with the same name
    123          * will be overwritten.
    124          * @param {Function} creator A reference to a function taking three parameters: First the board, the element is
    125          * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other
    126          * <tt>JXG.create...</tt> function for an example.
    127          */
    128         registerElement: function (element, creator) {
    129             element = element.toLowerCase();
    130             this.elements[element] = creator;
    131         },
    132
    133         /**
    134          * Register a file reader.
    135          * @param {function} reader A file reader. This object has to provide two methods: <tt>prepareString()</tt>
    136          * and <tt>read()</tt>.
    137          * @param {Array} ext
    138          */
    139         registerReader: function (reader, ext) {
    140             var i, e;
    141
    142             for (i = 0; i < ext.length; i++) {
    143                 e = ext[i].toLowerCase();
    144
    145                 if (typeof this.readers[e] !== 'function') {
    146                     this.readers[e] = reader;
    147                 }
    148             }
    149         },
    150
    151         /**
    152          * Creates a shortcut to a method, e.g. {@link JXG.Board#createElement} is a shortcut to {@link JXG.Board#create}.
    153          * Sometimes the target is undefined by the time you want to define the shortcut so we need this little helper.
    154          * @param {Object} object The object the method we want to create a shortcut for belongs to.
    155          * @param {String} fun The method we want to create a shortcut for.
    156          * @returns {Function} A function that calls the given method.
    157          */
    158         shortcut: function (object, fun) {
    159             return function () {
    160                 return object[fun].apply(this, arguments);
    161             };
    162         },
    163
    164         /**
    165          * s may be a string containing the name or id of an element or even a reference
    166          * to the element itself. This function returns a reference to the element. Search order: id, name.
    167          * @param {JXG.Board} board Reference to the board the element belongs to.
    168          * @param {String} s String or reference to a JSXGraph element.
    169          * @returns {Object} Reference to the object given in parameter object
    170          * @deprecated Use {@link JXG.Board#select}
    171          */
    172         getRef: function (board, s) {
    173             jxg.deprecated('JXG.getRef()', 'Board.select()');
    174             return board.select(s);
    175         },
    176
    177         /**
    178          * This is just a shortcut to {@link JXG.getRef}.
    179          * @deprecated Use {@link JXG.Board#select}.
    180          */
    181         getReference: function (board, s) {
    182             jxg.deprecated('JXG.getReference()', 'Board.select()');
    183             return board.select(s);
    184         },
    185
    186         /**
    187          * s may be the string containing the id of an HTML tag that hosts a JSXGraph board.
    188          * This function returns the reference to the board.
    189          * @param  {String} s String of an HTML tag that hosts a JSXGraph board
    190          * @returns {Object} Reference to the board or null.
    191          */
    192         getBoardByContainerId: function(s) {
    193             var b;
    194             for (b in JXG.boards) {
    195                 if (JXG.boards.hasOwnProperty(b) &&
    196                     JXG.boards[b].container === s) {
    197                         return JXG.boards[b];
    198                 }
    199             }
    200
    201             return null;
    202         },
    203
    204         /**
    205          * This method issues a warning to the developer that the given function is deprecated
    206          * and, if available, offers an alternative to the deprecated function.
    207          * @param {String} what Describes the function that is deprecated
    208          * @param {String} [replacement] The replacement that should be used instead.
    209          */
    210         deprecated: function (what, replacement) {
    211             var warning = what + ' is deprecated.';
    212
    213             if (replacement) {
    214                 warning += ' Please use ' + replacement + ' instead.';
    215             }
    216
    217             jxg.warn(warning);
    218         },
    219
    220         /**
    221          * Outputs a warning via console.warn(), if available. If console.warn() is
    222          * unavailable this function will look for an HTML element with the id 'warning'
    223          * and append the warning to this element's innerHTML.
    224          * @param {String} warning The warning text
    225          */
    226         warn: function (warning) {
    227             if (typeof window === 'object' && window.console && console.warn) {
    228                 console.warn('WARNING:', warning);
    229             } else if (typeof document === 'object' && document.getElementById('warning')) {
    230                 document.getElementById('debug').innerHTML += 'WARNING: ' + warning + '<br />';
    231             }
    232         },
    233
    234         /**
    235          * Add something to the debug log. If available a JavaScript debug console is used. Otherwise
    236          * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted.
    237          * @param s An arbitrary number of parameters.
    238          * @see JXG#debugWST
    239          */
    240         debugInt: function (s) {
    241             var i, p;
    242
    243             for (i = 0; i < arguments.length; i++) {
    244                 p = arguments[i];
    245                 if (typeof window === 'object' && window.console && console.log) {
    246                     console.log(p);
    247                 } else if (typeof document === 'object' && document.getElementById('debug')) {
    248                     document.getElementById('debug').innerHTML += p + "<br/>";
    249                 }
    250             }
    251         },
    252
    253         /**
    254          * Add something to the debug log. If available a JavaScript debug console is used. Otherwise
    255          * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted.
    256          * This method adds a stack trace (if available).
    257          * @param s An arbitrary number of parameters.
    258          * @see JXG#debug
    259          */
    260         debugWST: function (s) {
    261             var e = new Error();
    262
    263             jxg.debugInt.apply(this, arguments);
    264
    265             if (e && e.stack) {
    266                 jxg.debugInt('stacktrace');
    267                 jxg.debugInt(e.stack.split('\n').slice(1).join('\n'));
    268             }
    269         },
    270
    271         debugLine: function (s) {
    272             var e = new Error();
    273
    274             jxg.debugInt.apply(this, arguments);
    275
    276             if (e && e.stack) {
    277                 jxg.debugInt('Called from', e.stack.split('\n').slice(2, 3).join('\n'));
    278             }
    279         },
    280
    281         /**
    282          * Add something to the debug log. If available a JavaScript debug console is used. Otherwise
    283          * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted.
    284          * @param s An arbitrary number of parameters.
    285          * @see JXG#debugWST
    286          * @see JXG#debugLine
    287          * @see JXG#debugInt
    288          */
    289         debug: function (s) {
    290             jxg.debugInt.apply(this, arguments);
    291         }
    292     });
    293
    294     return jxg;
    295 });
    296