1 /*
  2     Copyright 2008-2016
  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