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 and JSXCompressor. 12 13 JSXGraph is free software dual licensed under the GNU LGPL or MIT License. 14 JSXCompressor is free software dual licensed under the GNU LGPL or Apache License. 15 16 You can redistribute it and/or modify it under the terms of the 17 18 * GNU Lesser General Public License as published by 19 the Free Software Foundation, either version 3 of the License, or 20 (at your option) any later version 21 OR 22 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 23 OR 24 * Apache License Version 2.0 25 26 JSXGraph is distributed in the hope that it will be useful, 27 but WITHOUT ANY WARRANTY; without even the implied warranty of 28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 GNU Lesser General Public License for more details. 30 31 You should have received a copy of the GNU Lesser General Public License, Apache 32 License, and the MIT License along with JSXGraph. If not, see 33 <http://www.gnu.org/licenses/>, <https://www.apache.org/licenses/LICENSE-2.0.html>, 34 and <http://opensource.org/licenses/MIT/>. 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 * @exports jxg as JXG 57 */ 58 var jxg = {}; 59 60 // Make sure JXG.extend is not defined 61 // If jsxgraph is loaded via loadjsxgraph.js, this is required, but JXG.extend will be undefined 62 // If jsxgraph is compiled as an amd module, it is possible that another jsxgraph version is already loaded and we 63 // therefore must not re-use the global JXG variable. But in this case JXG.extend will already be defined. 64 // This is the reason for this check. 65 if (typeof JXG === 'object' && !JXG.extend) { 66 jxg = JXG; 67 } 68 69 // We need the following two methods "extend" and "shortcut" to create the JXG object via JXG.extend. 70 71 /** 72 * Copy all properties of the <tt>extension</tt> object to <tt>object</tt>. 73 * @param {Object} object 74 * @param {Object} extension 75 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties. 76 * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes 77 */ 78 jxg.extend = function (object, extension, onlyOwn, toLower) { 79 var e, e2; 80 81 onlyOwn = onlyOwn || false; 82 toLower = toLower || false; 83 84 // the purpose of this for...in loop is indeed to use hasOwnProperty only if the caller 85 // explicitly wishes so. 86 for (e in extension) { 87 if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) { 88 if (toLower) { 89 e2 = e.toLowerCase(); 90 } else { 91 e2 = e; 92 } 93 94 object[e2] = extension[e]; 95 } 96 } 97 }; 98 99 /** 100 * Set a constant <tt>name</tt> in <tt>object</tt> to <tt>value</tt>. The value can't be changed after declaration. 101 * @param {Object} object 102 * @param {String} name 103 * @param {Number|String|Boolean} value 104 * @param {Boolean} ignoreRedefine This should be left at its default: false. 105 */ 106 jxg.defineConstant = function (object, name, value, ignoreRedefine) { 107 ignoreRedefine = ignoreRedefine || false; 108 109 if (ignoreRedefine && jxg.exists(object[name])) { 110 return; 111 } 112 113 Object.defineProperty(object, name, { 114 value: value, 115 writable: false, 116 enumerable: true, 117 configurable: false, 118 }); 119 }; 120 121 /** 122 * Copy all properties of the <tt>constants</tt> object in <tt>object</tt> as a constant. 123 * @param {Object} object 124 * @param {Object} constants 125 * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties. 126 * @param {Boolean} [toUpper=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes 127 */ 128 jxg.extendConstants = function (object, constants, onlyOwn, toUpper) { 129 var e, e2; 130 131 onlyOwn = onlyOwn || false; 132 toUpper = toUpper || false; 133 134 // The purpose of this for...in loop is indeed to use hasOwnProperty only if the caller explicitly wishes so. 135 for (e in constants) { 136 if (!onlyOwn || (onlyOwn && constants.hasOwnProperty(e))) { 137 if (toUpper) { 138 e2 = e.toUpperCase(); 139 } else { 140 e2 = e; 141 } 142 143 this.defineConstant(object, e2, constants[e]); 144 } 145 } 146 }; 147 148 jxg.extend(jxg, /** @lends JXG */ { 149 /** 150 * Store a reference to every board in this central list. This will at some point 151 * replace JXG.JSXGraph.boards. 152 * @type Object 153 */ 154 boards: {}, 155 156 /** 157 * Store the available file readers in this structure. 158 * @type Object 159 */ 160 readers: {}, 161 162 /** 163 * Associative array that keeps track of all constructable elements registered 164 * via {@link JXG.registerElement}. 165 * @type Object 166 */ 167 elements: {}, 168 169 /** 170 * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create} 171 * interface. 172 * @param {String} element The elements name. This is case-insensitive, existing elements with the same name 173 * will be overwritten. 174 * @param {Function} creator A reference to a function taking three parameters: First the board, the element is 175 * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other 176 * <tt>JXG.create...</tt> function for an example. 177 */ 178 registerElement: function (element, creator) { 179 element = element.toLowerCase(); 180 this.elements[element] = creator; 181 }, 182 183 /** 184 * Register a file reader. 185 * @param {function} reader A file reader. This object has to provide two methods: <tt>prepareString()</tt> 186 * and <tt>read()</tt>. 187 * @param {Array} ext 188 */ 189 registerReader: function (reader, ext) { 190 var i, e; 191 192 for (i = 0; i < ext.length; i++) { 193 e = ext[i].toLowerCase(); 194 195 if (typeof this.readers[e] !== 'function') { 196 this.readers[e] = reader; 197 } 198 } 199 }, 200 201 /** 202 * Creates a shortcut to a method, e.g. {@link JXG.Board#createElement} is a shortcut to {@link JXG.Board#create}. 203 * Sometimes the target is undefined by the time you want to define the shortcut so we need this little helper. 204 * @param {Object} object The object the method we want to create a shortcut for belongs to. 205 * @param {String} fun The method we want to create a shortcut for. 206 * @returns {Function} A function that calls the given method. 207 */ 208 shortcut: function (object, fun) { 209 return function () { 210 return object[fun].apply(this, arguments); 211 }; 212 }, 213 214 /** 215 * s may be a string containing the name or id of an element or even a reference 216 * to the element itself. This function returns a reference to the element. Search order: id, name. 217 * @param {JXG.Board} board Reference to the board the element belongs to. 218 * @param {String} s String or reference to a JSXGraph element. 219 * @returns {Object} Reference to the object given in parameter object 220 * @deprecated Use {@link JXG.Board#select} 221 */ 222 getRef: function (board, s) { 223 jxg.deprecated('JXG.getRef()', 'Board.select()'); 224 return board.select(s); 225 }, 226 227 /** 228 * This is just a shortcut to {@link JXG.getRef}. 229 * @deprecated Use {@link JXG.Board#select}. 230 */ 231 getReference: function (board, s) { 232 jxg.deprecated('JXG.getReference()', 'Board.select()'); 233 return board.select(s); 234 }, 235 236 /** 237 * s may be the string containing the id of an HTML tag that hosts a JSXGraph board. 238 * This function returns the reference to the board. 239 * @param {String} s String of an HTML tag that hosts a JSXGraph board 240 * @returns {Object} Reference to the board or null. 241 */ 242 getBoardByContainerId: function (s) { 243 var b; 244 for (b in JXG.boards) { 245 if (JXG.boards.hasOwnProperty(b) && 246 JXG.boards[b].container === s) { 247 return JXG.boards[b]; 248 } 249 } 250 251 return null; 252 }, 253 254 /** 255 * This method issues a warning to the developer that the given function is deprecated 256 * and, if available, offers an alternative to the deprecated function. 257 * @param {String} what Describes the function that is deprecated 258 * @param {String} [replacement] The replacement that should be used instead. 259 */ 260 deprecated: function (what, replacement) { 261 var warning = what + ' is deprecated.'; 262 263 if (replacement) { 264 warning += ' Please use ' + replacement + ' instead.'; 265 } 266 267 jxg.warn(warning); 268 }, 269 270 /** 271 * Outputs a warning via console.warn(), if available. If console.warn() is 272 * unavailable this function will look for an HTML element with the id 'warning' 273 * and append the warning to this element's innerHTML. 274 * @param {String} warning The warning text 275 */ 276 warn: function (warning) { 277 if (typeof window === 'object' && window.console && console.warn) { 278 console.warn('WARNING:', warning); 279 } else if (typeof document === 'object' && document.getElementById('warning')) { 280 document.getElementById('debug').innerHTML += 'WARNING: ' + warning + '<br />'; 281 } 282 }, 283 284 /** 285 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 286 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 287 * @param s An arbitrary number of parameters. 288 * @see JXG#debugWST 289 */ 290 debugInt: function (s) { 291 var i, p; 292 293 for (i = 0; i < arguments.length; i++) { 294 p = arguments[i]; 295 if (typeof window === 'object' && window.console && console.log) { 296 console.log(p); 297 } else if (typeof document === 'object' && document.getElementById('debug')) { 298 document.getElementById('debug').innerHTML += p + '<br/>'; 299 } 300 } 301 }, 302 303 /** 304 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 305 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 306 * This method adds a stack trace (if available). 307 * @param s An arbitrary number of parameters. 308 * @see JXG#debug 309 */ 310 debugWST: function (s) { 311 var e = new Error(); 312 313 jxg.debugInt.apply(this, arguments); 314 315 if (e && e.stack) { 316 jxg.debugInt('stacktrace'); 317 jxg.debugInt(e.stack.split('\n').slice(1).join('\n')); 318 } 319 }, 320 321 /** 322 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 323 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 324 * This method adds a line of the stack trace (if available). 325 * 326 * @param s An arbitrary number of parameters. 327 * @see JXG#debug 328 */ 329 debugLine: function (s) { 330 var e = new Error(); 331 332 jxg.debugInt.apply(this, arguments); 333 334 if (e && e.stack) { 335 jxg.debugInt('Called from', e.stack.split('\n').slice(2, 3).join('\n')); 336 } 337 }, 338 339 /** 340 * Add something to the debug log. If available a JavaScript debug console is used. Otherwise 341 * we're looking for a HTML div with id "debug". If this doesn't exist, too, the output is omitted. 342 * @param s An arbitrary number of parameters. 343 * @see JXG#debugWST 344 * @see JXG#debugLine 345 * @see JXG#debugInt 346 */ 347 debug: function (s) { 348 jxg.debugInt.apply(this, arguments); 349 } 350 }); 351 352 return jxg; 353 }); 354