1 /* 2 Copyright 2008-2022 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 dual licensed under the GNU LGPL or MIT License. 13 14 You can redistribute it and/or modify it under the terms of the 15 16 * GNU Lesser General Public License as published by 17 the Free Software Foundation, either version 3 of the License, or 18 (at your option) any later version 19 OR 20 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 21 22 JSXGraph is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public License and 28 the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> 29 and <http://opensource.org/licenses/MIT/>. 30 */ 31 32 33 /*global JXG:true, define: true, ActiveXObject:true, jxgBinFileReader:true, DOMParser:true, XMLHttpRequest:true, document:true, navigator:true*/ 34 /*jslint nomen: true, plusplus: true*/ 35 36 /* depends: 37 jxg 38 utils/env 39 utils/type 40 utils/encoding 41 utils/base64 42 */ 43 44 define([ 45 'jxg', 'utils/env', 'utils/type', 'utils/encoding', 'utils/base64' 46 ], function (JXG, Env, Type, Encoding, Base64) { 47 48 "use strict"; 49 50 /** 51 * The FileReader object bundles the file input capabilities of JSXGraph. 52 */ 53 JXG.FileReader = { 54 /** 55 * 56 * @param {String} url 57 * @param {JXG.Board} board 58 * @param {String} format 59 * @param {Boolean} async 60 * @param {Function} callback 61 * 62 * @private 63 */ 64 handleRemoteFile: function(url, board, format, async, encoding, callback) { 65 var request = false; 66 67 try { 68 request = new XMLHttpRequest(); 69 if (format.toLowerCase() === 'raw') { 70 request.overrideMimeType('text/plain; charset=' + encoding); 71 } else { 72 request.overrideMimeType('text/xml; charset=' + encoding); 73 } 74 } catch (e) { 75 try { 76 request = new ActiveXObject("Msxml2.XMLHTTP"); 77 } catch (ex) { 78 try { 79 request = new ActiveXObject("Microsoft.XMLHTTP"); 80 } catch (exc) { 81 request = false; 82 } 83 } 84 } 85 if (!request) { 86 JXG.debug("AJAX not activated!"); 87 return; 88 } 89 90 request.open("GET", url, async); 91 if (format.toLowerCase() === 'raw') { 92 this.cbp = function () { 93 var req = request; 94 if (req.readyState === 4) { 95 board(req.responseText); 96 } 97 }; 98 } else { 99 this.cbp = function () { 100 var req = request, 101 text = ''; 102 103 if (req.readyState === 4) { 104 // Hack for ancient IEs: 105 // We use the Visual Basic stuff from below. 106 if (Type.exists(req.responseStream) && 107 // PK: zip, geogebra 108 // 31: gzip, cinderella 109 (req.responseText.slice(0, 2) === "PK" || 110 Encoding.asciiCharCodeAt(req.responseText.slice(0, 1), 0) === 31)) { 111 112 // After this, text contains the binary? zip-compressed string 113 text = Base64.decode(jxgBinFileReader(req)); 114 } else { 115 // This is for all browsers except ancient IEs. 116 text = req.responseText; 117 // console.log(text); 118 } 119 this.parseString(text, board, format, callback); 120 } 121 }; 122 } 123 124 this.cb = Type.bind(this.cbp, this); 125 // Old style 126 request.onreadystatechange = this.cb; 127 128 try { 129 request.send(null); 130 } catch (ex2) { 131 throw new Error("JSXGraph: A problem occurred while trying to read remote file '" + url + "'."); 132 } 133 }, 134 135 /** 136 * 137 * @param {Blob} url The Blob or File from which to read 138 * @param {JXG.Board} board 139 * @param {String} format 140 * @param {Boolean} async 141 * @param {Function} callback 142 * 143 * @private 144 */ 145 handleLocalFile: function(url, board, format, async, encoding, callback) { 146 if (!Type.exists(async)) { 147 async = true; 148 } 149 150 if (format.toLowerCase() === 'raw') { 151 this.cbp = function (e) { 152 board(e.target.result); 153 }; 154 } else { 155 this.cbp = function (e) { 156 var text = e.target.result; 157 //console.log(text); 158 this.parseString(text, board, format, callback); 159 }; 160 } 161 162 this.cb = Type.bind(this.cbp, this); 163 164 var reader = new FileReader(); 165 reader.onload = this.cb; 166 if (format.toLowerCase() === 'raw') { 167 reader.readAsText(url); 168 } else { 169 reader.readAsText(url, encoding); 170 } 171 }, 172 173 /** 174 * Opens a file using the given URL and passes the contents to {@link JXG.FileReader#parseString} 175 * @param {String} url 176 * @param {JXG.Board|function} board Either a board or in case <tt>format</tt> equals 'raw' this has to be a callback function. 177 * @param {String} format The expected file format. Possible values are <dl> 178 * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd> 179 * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd> 180 * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd> 181 * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd> 182 * <dt>graph</dt><dd>Graph file</dd> 183 * <dt>digraph</dt><dd>DiGraph file</dd> 184 * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd> 185 * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd> 186 * </dl> 187 * @param {Boolean} async Call ajax asynchonously. 188 * @param {function} callback A function that is run when the board is ready. 189 */ 190 parseFileContent: function (url, board, format, async, encoding, callback) { 191 if (Type.isString(url) || FileReader === undefined) { 192 this.handleRemoteFile(url, board, format, async, encoding, callback); 193 } else { 194 this.handleLocalFile(url, board, format, async, encoding, callback); 195 } 196 }, 197 198 /** 199 * Parses a given string according to the file format given in format. 200 * @param {String} str Contents of the file. 201 * @param {JXG.Board} board The board the construction in the file should be loaded in. 202 * @param {String} format Possible values are <dl> 203 * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd> 204 * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd> 205 * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd> 206 * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd> 207 * <dt>graph</dt><dd>Graph file</dd> 208 * <dt>digraph</dt><dd>DiGraph file</dd> 209 * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd> 210 * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd> 211 * </dl> 212 * @param {function} callback 213 */ 214 parseString: function (str, board, format, callback) { 215 var Reader, 216 read; 217 218 format = format.toLowerCase(); 219 Reader = JXG.readers[format]; 220 221 if (Type.exists(Reader)) { 222 read = new Reader(board, str); 223 read.read(); 224 } else if (format === 'jessiecode') { 225 226 } else { 227 throw new Error('JSXGraph: There is no reader available for \'' + format + '\'.'); 228 } 229 230 if (Type.isFunction(callback)) { 231 callback(board); 232 } 233 } 234 }; 235 236 // The following code is vbscript. This is a workaround to enable binary data downloads via AJAX in 237 // Microsoft Internet Explorer. 238 239 /*jslint evil:true, es5:true, white:true*/ 240 /*jshint multistr:true*/ 241 if (!Env.isMetroApp() && Env.isBrowser && typeof navigator === 'object' && /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) && document && document.write) { 242 document.write('<script type="text/vbscript">\n\ 243 Function Base64Encode(inData)\n\ 244 Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n\ 245 Dim cOut, sOut, I\n\ 246 For I = 1 To LenB(inData) Step 3\n\ 247 Dim nGroup, pOut, sGroup\n\ 248 nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n\ 249 &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n\ 250 nGroup = Oct(nGroup)\n\ 251 nGroup = String(8 - Len(nGroup), "0") & nGroup\n\ 252 pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n\ 253 Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n\ 254 Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n\ 255 Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n\ 256 sOut = sOut + pOut\n\ 257 Next\n\ 258 Select Case LenB(inData) Mod 3\n\ 259 Case 1: \'8 bit final\n\ 260 sOut = Left(sOut, Len(sOut) - 2) + "=="\n\ 261 Case 2: \'16 bit final\n\ 262 sOut = Left(sOut, Len(sOut) - 1) + "="\n\ 263 End Select\n\ 264 Base64Encode = sOut\n\ 265 End Function\n\ 266 \n\ 267 Function MyASC(OneChar)\n\ 268 If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\n\ 269 End Function\n\ 270 \n\ 271 Function jxgBinFileReader(xhr)\n\ 272 Dim byteString\n\ 273 Dim b64String\n\ 274 Dim i\n\ 275 byteString = xhr.responseBody\n\ 276 ReDim byteArray(LenB(byteString))\n\ 277 For i = 1 To LenB(byteString)\n\ 278 byteArray(i-1) = AscB(MidB(byteString, i, 1))\n\ 279 Next\n\ 280 b64String = Base64Encode(byteString)\n\ 281 jxgBinFileReader = b64String\n\ 282 End Function\n\ 283 </script>\n'); 284 } 285 286 return JXG.FileReader; 287 }); 288