      1 /*
      2     Copyright 2008-2013
      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          * Opens a file using the given URL and passes the contents to {@link JXG.FileReader#parseString}
     57          * @param {String} url
     58          * @param {JXG.Board|function} board Either a board or in case <tt>format</tt> equals 'raw' this has to be a callback function.
     59          * @param {String} format The expected file format. Possible values are <dl>
     60          * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd>
     61          * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd>
     62          * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd>
     63          * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd>
     64          * <dt>graph</dt><dd>Graph file</dd>
     65          * <dt>digraph</dt><dd>DiGraph file</dd>
     66          * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd>
     67          * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd>
     68          * </dl>
     69          * @param {Boolean} async Call ajax asynchonously.
     70          * @param {function} callback A function that is run when the board is ready.
     71          */
     72         parseFileContent: function (url, board, format, async, callback) {
     73             var request = false;
     74
     75             if (!Type.exists(async)) {
     76                 async = true;
     77             }
     78
     79             //this.request = false;
     80
     81             try {
     82                 request = new XMLHttpRequest();
     83                 if (format.toLowerCase() === 'raw') {
     84                     request.overrideMimeType('text/plain; charset=iso-8859-1');
     85                 } else {
     86                     request.overrideMimeType('text/xml; charset=iso-8859-1');
     87                 }
     88             } catch (e) {
     89                 try {
     90                     request = new ActiveXObject("Msxml2.XMLHTTP");
     91                 } catch (ex) {
     92                     try {
     93                         request = new ActiveXObject("Microsoft.XMLHTTP");
     94                     } catch (exc) {
     95                         request = false;
     96                     }
     97                 }
     98             }
     99
    100             if (!request) {
    101                 JXG.debug("AJAX not activated!");
    102                 return;
    103             }
    104
    105             request.open("GET", url, async);
    106
    107             if (format.toLowerCase() === 'raw') {
    108                 this.cbp = function () {
    109                     var req = request;
    110                     if (req.readyState === 4) {
    111                         board(req.responseText);
    112                     }
    113                 };
    114             } else {
    115                 this.cbp = function () {
    116                     var req = request,
    117                         text = '';
    118
    119                     if (req.readyState === 4) {
    120                         if (Type.exists(req.responseStream) &&
    121                                 // PK: zip, geogebra
    122                                 // 31: gzip, cinderella
    123                                 (req.responseText.slice(0, 2) === "PK" ||
    124                                 Encoding.asciiCharCodeAt(req.responseText.slice(0, 1), 0) === 31)) {
    125
    126                             // After this, text contains the base64 encoded, zip-compressed string
    127                             text = Base64.decode(jxgBinFileReader(req));
    128                         } else {
    129                             text = req.responseText;
    130                         }
    131                         this.parseString(text, board, format, callback);
    132                     }
    133                 };
    134             }
    135
    136             this.cb = Type.bind(this.cbp, this);
    137             request.onreadystatechange = this.cb;
    138
    139             try {
    140                 request.send(null);
    141             } catch (ex2) {
    142                 throw new Error("JSXGraph: A problem occurred while trying to read '" + url + "'.");
    143             }
    144         },
    145
    146         /**
    147          * Parses a given string according to the file format given in format.
    148          * @param {String} str Contents of the file.
    149          * @param {JXG.Board} board The board the construction in the file should be loaded in.
    150          * @param {String} format Possible values are <dl>
    151          * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd>
    152          * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd>
    153          * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd>
    154          * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd>
    155          * <dt>graph</dt><dd>Graph file</dd>
    156          * <dt>digraph</dt><dd>DiGraph file</dd>
    157          * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd>
    158          * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd>
    159          * </dl>
    160          * @param {function} callback
    161          */
    162         parseString: function (str, board, format, callback) {
    163             var Reader,
    164                 read;
    165
    166             format = format.toLowerCase();
    167
    168             Reader = JXG.readers[format];
    169
    170             if (Type.exists(Reader)) {
    171                 read = new Reader(board, str);
    172                 read.read();
    173             } else {
    174                 throw new Error('JSXGraph: There is no reader available for \'' + format + '\'.');
    175             }
    176
    177             if (typeof callback === 'function') {
    178                 callback(board);
    179             }
    180         }
    181     };
    182
    183     // The following code is vbscript. This is a workaround to enable binary data downloads via AJAX in
    184     // Microsoft Internet Explorer.
    185
    186     /*jslint evil:true, es5:true, white:true*/
    187     /*jshint multistr:true*/
    188     if (!Env.isMetroApp() && Env.isBrowser && typeof navigator === 'object' && /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) && document && document.write) {
    189         document.write('<script type="text/vbscript">\n\
    190 Function Base64Encode(inData)\n\
    191   Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n\
    192   Dim cOut, sOut, I\n\
    193   For I = 1 To LenB(inData) Step 3\n\
    194     Dim nGroup, pOut, sGroup\n\
    195     nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n\
    196       &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n\
    197     nGroup = Oct(nGroup)\n\
    198     nGroup = String(8 - Len(nGroup), "0") & nGroup\n\
    199     pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n\
    200       Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n\
    201       Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n\
    202       Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n\
    203     sOut = sOut + pOut\n\
    204   Next\n\
    205   Select Case LenB(inData) Mod 3\n\
    206     Case 1: \'8 bit final\n\
    207       sOut = Left(sOut, Len(sOut) - 2) + "=="\n\
    208     Case 2: \'16 bit final\n\
    209       sOut = Left(sOut, Len(sOut) - 1) + "="\n\
    210   End Select\n\
    211   Base64Encode = sOut\n\
    212 End Function\n\
    213 \n\
    214 Function MyASC(OneChar)\n\
    215   If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\n\
    216 End Function\n\
    217 \n\
    218 Function jxgBinFileReader(xhr)\n\
    219     Dim byteString\n\
    220     Dim b64String\n\
    221     Dim i\n\
    222     byteString = xhr.responseBody\n\
    223     ReDim byteArray(LenB(byteString))\n\
    224     For i = 1 To LenB(byteString)\n\
    225         byteArray(i-1) = AscB(MidB(byteString, i, 1))\n\
    226     Next\n\
    227     b64String = Base64Encode(byteString)\n\
    228     jxgBinFileReader = b64String\n\
    229 End Function\n\
    230 </script>\n');
    231     }
    232
    233     return JXG.FileReader;
    234 });
    235