1 /* 2 Copyright 2008-2011 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. 11 12 JSXGraph is free software: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /** 27 * @fileoverview The JXG.Dump namespace provides methods to save a board to javascript. 28 */ 29 30 /** 31 * The JXG.Dump namespace provides classes and methods to save a board to javascript. 32 * @namespace 33 */ 34 JXG.Dump = { 35 36 /** 37 * Adds markers to every element of the board 38 * @param {JXG.Board} board 39 * @param {Array|String} markers 40 * @param {Array|%} values 41 */ 42 addMarkers: function (board, markers, values) { 43 var e, l, i; 44 45 if (!JXG.isArray(markers)) { 46 markers = [markers]; 47 } 48 49 if (!JXG.isArray(values)) { 50 values = [values]; 51 } 52 53 l = Math.min(markers.length, values.length); 54 55 markers.length = l; 56 values.length = l; 57 58 for (e in board.objects) { 59 for (i = 0; i < l; i++) { 60 board.objects[e][markers[i]] = values[i]; 61 } 62 } 63 }, 64 65 /** 66 * Removes markers from every element on the board. 67 * @param {JXG.Board} board 68 * @param {Array|String} markers 69 */ 70 deleteMarkers: function (board, markers) { 71 var e, l, i; 72 73 if (!JXG.isArray(markers)) { 74 markers = [markers]; 75 } 76 77 l = markers.length; 78 79 markers.length = l; 80 81 for (e in board.objects) { 82 for (i = 0; i < l; i++) { 83 delete board.objects[e][markers[i]]; 84 } 85 } 86 }, 87 88 /** 89 * Stringifies a string, i.e. puts some quotation marks around <tt>s</tt> if it is of type string. 90 * @param {%} s 91 * @returns {String} " + s + " 92 */ 93 str: function (s) { 94 if (typeof s === 'string' && s.substr(0, 7) !== 'function') { 95 s = '\'' + s + '\''; 96 } 97 98 return s; 99 }, 100 101 /** 102 * Eliminate default values given by {@link JXG.Options} from the attributes object. 103 * @param {Object} instance Attribute object of the element 104 * @param {Object} % Arbitrary number of objects <tt>instance</tt> will be compared to. Usually these are 105 * sub-objects of the {@link JXG.Board#options} structure. 106 * @returns {Object} Minimal attributes object 107 */ 108 minimizeObject: function (instance) { 109 var p, pl, copy = JXG.deepCopy(instance), 110 defaults = [], i; 111 112 for (i = 1; i < arguments.length; i++) { 113 defaults.push(arguments[i]); 114 } 115 116 for (i = 0; i < defaults.length; i++) { 117 for (p in defaults[i]) { 118 pl = p.toLowerCase(); 119 120 if (typeof defaults[i][p] !== 'object' && defaults[i][p] == copy[pl]) { 121 delete copy[pl]; 122 } 123 } 124 } 125 126 return copy; 127 }, 128 129 /** 130 * Prepare the attributes object for an element. 131 * @param {JXG.Board} board 132 * @param {JXG.GeometryElement} obj Geometry element which attributes object is generated 133 * @returns {Object} An attributes object. 134 */ 135 prepareAttributes: function (board, obj) { 136 var a, s; 137 138 a = this.minimizeObject(obj.getAttributes(), board.options[obj.elType], board.options.elements); 139 140 for (s in obj.subs) { 141 a[s] = this.minimizeObject(obj.subs[s].getAttributes(), board.options[obj.elType][s], board.options[obj.subs[s].elType], board.options.elements); 142 a[s].id = obj.subs[s].id; 143 a[s].name = obj.subs[s].name; 144 } 145 146 a.id = obj.id; 147 a.name = obj.name; 148 149 return a; 150 }, 151 152 /** 153 * Generate a save-able structure with all elements. This is used by {@link JXG.Dump#toJessie} and {@link JXG.Dump#toJavaScript} 154 * to generate the script. 155 * @param {JXG.Board} board 156 * @returns {Array} An array with all metadata necessary to save the construction. 157 */ 158 dump: function (board) { 159 var e, obj, element, s, 160 elementList = [], i; 161 162 this.addMarkers(board, 'dumped', false); 163 164 for (e in board.objects) { 165 obj = board.objects[e]; 166 element = {}; 167 168 if (!obj.dumped && obj.dump) { 169 element.type = obj.getType(); 170 element.parents = obj.getParents(); 171 172 if (element.type === 'point' && element.parents[0] == 1) { 173 element.parents = element.parents.slice(1); 174 } 175 176 for (s = 0; s < element.parents.length; s++) { 177 if (typeof element.parents[s] === 'string') { 178 element.parents[s] = '\'' + element.parents[s] + '\''; 179 } 180 } 181 182 element.attributes = this.prepareAttributes(board, obj); 183 184 elementList.push(element); 185 } 186 } 187 188 this.deleteMarkers(board, 'dumped'); 189 190 return elementList; 191 }, 192 193 /** 194 * Converts a JavaScript object into a JSAN (JessieScript Attribute Notation) string. 195 * @param {Object} obj A JavaScript object, functions will be ignored. 196 * @returns {String} The given object stored in a JSAN string. 197 */ 198 toJSAN: function (obj) { 199 var s, i; 200 201 switch (typeof obj) { 202 case 'object': 203 if (obj) { 204 var list = []; 205 if (obj instanceof Array) { 206 for (i = 0; i < obj.length; i++) { 207 list.push(this.toJSAN(obj[i])); 208 } 209 return '[' + list.join(',') + ']'; 210 } else { 211 for (var prop in obj) { 212 list.push(prop + ': ' + this.toJSAN(obj[prop])); 213 } 214 return '<<' + list.join(', ') + '>> '; 215 } 216 } else { 217 return 'null'; 218 } 219 case 'string': 220 return '\'' + obj.replace(/(["'])/g, '\\$1') + '\''; 221 case 'number': 222 case 'boolean': 223 return new String(obj); 224 case 'null': 225 return 'null'; 226 } 227 }, 228 229 /** 230 * Saves the construction in <tt>board</tt> to JessieScript. 231 * @param {JXG.Board} board 232 * @returns {String} JessieScript 233 */ 234 toJessie: function (board) { 235 var elements = this.dump(board), 236 script = [], i; 237 238 for (i = 0; i < elements.length; i++) { 239 if (elements[i].attributes.name.length > 0) { 240 script.push('// ' + elements[i].attributes.name); 241 } 242 243 script.push('s' + i + ' = ' + elements[i].type + '(' + elements[i].parents.join(', ') + ') ' + this.toJSAN(elements[i].attributes).replace(/\n/, '\\n') + ';'); 244 script.push(''); 245 } 246 247 return script.join('\n'); 248 }, 249 250 /** 251 * Saves the construction in <tt>board</tt> to JavaScript. 252 * @param {JXG.Board} board 253 * @returns {String} JavaScript 254 */ 255 toJavaScript: function (board) { 256 var elements = this.dump(board), 257 script = [], i; 258 259 for (i = 0; i < elements.length; i++) { 260 script.push('board.create("' + elements[i].type + '", [' + elements[i].parents.join(', ') + '], ' + JXG.toJSON(elements[i].attributes) + ');'); 261 } 262 263 return script.join('\n'); 264 } 265 };