Subversion Repositories wimsdev

Rev

Rev 10533 | Rev 11759 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1.  
  2. /** Original deployggb.js file, modified tu use internal hosted version of Geogebra, instead of downloading it from geogebra CDN **/
  3.  
  4. // Hack WIMS 1 : replace the original "getTubeURL" geogebra function.
  5. var getTubeURL = function() {
  6.     return "scripts/js/geogebra/geogebraweb/";
  7. };
  8.  
  9. /** See "readme.md" to see other modifications to be done to an ggb upgrade. **/
  10.  
  11. /*
  12.   @author: GeoGebra - Dynamic Mathematics for Everyone, http://www.geogebra.org
  13.   @license: This file is subject to the GeoGebra Non-Commercial License Agreement, see http://www.geogebra.org/license. For questions please write us at office@geogebra.org.
  14. */
  15.  
  16. /*global renderGGBElement, deployJava, XDomainRequest, ggbApplets, console */
  17.  
  18. var latestVersion="5.0.332.0";
  19. var isRenderGGBElementEnabled = false;
  20. var scriptLoadStarted = false;
  21. var html5AppletsToProcess = null;
  22. var ggbHTML5LoadedCodebaseIsWebSimple = false;
  23. var ggbHTML5LoadedCodebaseVersion = null;
  24. var ggbHTML5LoadedScript = null;
  25.  
  26. var ggbCompiledResourcesLoadFinished = false;
  27. var ggbCompiledResourcesLoadInProgress = false;
  28. var ggbCompiledAppletsLoaded = false;
  29.  
  30. /**
  31.  * @param ggbVersion The version of the GeoGebraFile as string in the format x.x (e.g. '4.4'). If the version is not specified, the latest stable GeoGebraVersion is used (currently 4.4).
  32.  * @param parameters An object containing parameters that are passed to the applet.
  33.  * @param views An object containing information about which views are used in the GeoGebra worksheet. Each variable is boolean.
  34.  *              E.g.: {"is3D":false,"AV":false,"SV":false,"CV":false,"EV2":false,"CP":false,"PC":false,"DA":false,"FI":false,"PV":false,"macro":false};
  35.  * @param html5NoWebSimple Set to true to avoid using web Simple for simple html5 applets. In this case the full version is used always.
  36.  */
  37. var GGBApplet = function() {
  38.     "use strict";
  39.     var applet = {};
  40.  
  41.     // Define the parameters
  42.     var ggbVersion = '5.0';
  43.     var parameters = {};
  44.     var views = null;
  45.     var html5NoWebSimple = false;
  46.     var html5NoWebSimpleParamExists = false;
  47.     var appletID = null;
  48.     var initComplete = false;
  49.     var html5OverwrittenCodebaseVersion = null;
  50.     var html5OverwrittenCodebase = null;
  51.  
  52.     for(var i=0; i<arguments.length; i++) {
  53.         var p = arguments[i];
  54.         if (p !== null) {
  55.             switch(typeof(p)) {
  56.                 case 'number':
  57.                     ggbVersion = p.toFixed(1);
  58.                     break;
  59.                 case 'string':
  60.                     // Check for a version number
  61.                     if (p.match(new RegExp("^[0-9]\\.[0-9]+$"))) {
  62.                         ggbVersion = p;
  63.                     } else {
  64.                         appletID = p;
  65.                     }
  66.                     break;
  67.                 case 'object':
  68.                     if (typeof p.is3D !== "undefined") {
  69.                         views = p;
  70.                     } else {
  71.                         parameters = p;
  72.                     }
  73.                     break;
  74.                 case 'boolean':
  75.                     html5NoWebSimple = p;
  76.                     html5NoWebSimpleParamExists = true;
  77.                     break;
  78.             }
  79.         }
  80.     }
  81.  
  82.     if (views === null) {
  83.         views = {"is3D":false,"AV":false,"SV":false,"CV":false,"EV2":false,"CP":false,"PC":false,"DA":false,"FI":false,"PV":false,"macro":false};
  84.  
  85.         // don't use web simple when material is loaded from tube, because we don't know which views are used.
  86.         if (parameters.material_id !== undefined && !html5NoWebSimpleParamExists) {
  87.             html5NoWebSimple = true;
  88.         }
  89.     }
  90.  
  91.     if (appletID !== null && parameters.id === undefined) {
  92.         parameters.id = appletID;
  93.     }
  94.  
  95.     // Private members
  96.     var jnlpFilePath = "";
  97.     var html5Codebase = "";
  98.     var javaCodebase = "";
  99.     var isOverriddenJavaCodebase = false;
  100.     var isHTML5Offline = false;
  101.     var isJavaOffline = false;
  102.     var loadedAppletType = null;
  103.     var javaCodebaseVersion = null;
  104.     var html5CodebaseVersion = null;
  105.     var html5CodebaseScript = null;
  106.     var html5CodebaseIsWebSimple = false;
  107.     var previewImagePath = null;
  108.     var previewLoadingPath = null;
  109.     var previewPlayPath = null;
  110.     var fonts_css_url = null;
  111.     var jnlpBaseDir = null;
  112.     var preCompiledScriptPath = null;
  113.     var preCompiledResourcePath = null;
  114.     var preCompiledScriptVersion = null;
  115.  
  116.     if (parameters.height !== undefined) {
  117.         parameters.height = Math.round(parameters.height);
  118.     }
  119.     if (parameters.width !== undefined) {
  120.         parameters.width = Math.round(parameters.width);
  121.     }
  122.     var parseVersion =function(d){
  123.         return parseFloat(d)>4.0 ? parseFloat(d) : 5;
  124.     };
  125.     /**
  126.      * Overrides the codebase for HTML5.
  127.      * @param codebase Can be an URL or a local file path.
  128.      * @param offline Set to true, if the codebase is a local URL and no web URL
  129.      */
  130.     applet.setHTML5Codebase = function(codebase, offline) {
  131.         html5OverwrittenCodebase = codebase;
  132.         setHTML5CodebaseInternal(codebase, offline);
  133.     };
  134.  
  135.     /**
  136.      * Overrides the codebase version for Java.
  137.      * @param version The version of the codebase that shoudl be used for java applets.
  138.      */
  139.     applet.setJavaCodebaseVersion = function(version) {
  140.         javaCodebaseVersion = version;
  141.         setDefaultJavaCodebaseForVersion(version);
  142.     };
  143.  
  144.     /**
  145.      * Overrides the codebase version for HTML5.
  146.      * If another codebase than the default codebase should be used, this method has to be called before setHTML5Codebase.
  147.      * @param version The version of the codebase that should be used for HTML5 applets.
  148.      */
  149.     applet.setHTML5CodebaseVersion = function(version, offline) {
  150.         if (version==="4.2") {
  151.             return;
  152.         } // Version 4.2 is not working properly
  153.         html5OverwrittenCodebaseVersion = version;
  154.         setDefaultHTML5CodebaseForVersion(version, offline);
  155.     };
  156.  
  157.     applet.getHTML5CodebaseVersion = function() {
  158.         return html5CodebaseVersion;
  159.     };
  160.  
  161.     applet.getParameters = function() {
  162.         return parameters;
  163.     };
  164.  
  165.  
  166.     /**
  167.      * Overrides the codebase for Java.
  168.      * @param codebase Can be an URL or a local file path.
  169.      * @param offline Set to true, if the codebase is a local URL and no web URL
  170.      */
  171.     applet.setJavaCodebase = function(codebase, offline) {
  172.         isOverriddenJavaCodebase = true;
  173.  
  174.         if (codebase.slice(-1) === '/') {
  175.             javaCodebaseVersion = codebase.slice(-4,-1);
  176.         } else {
  177.             javaCodebaseVersion = codebase.slice(-3);
  178.         }
  179.  
  180.         if (offline === null) {
  181.             offline = (codebase.indexOf("http") === -1);
  182.         }
  183.         if (offline && jnlpBaseDir !== null) {
  184.             jnlpBaseDir = null;
  185.         }
  186.  
  187.         doSetJavaCodebase(codebase, offline);
  188.     };
  189.  
  190.     applet.setFontsCSSURL = function(url) {
  191.         fonts_css_url = url;
  192.     };
  193.  
  194.     /**
  195.       * This function is not needed anymore. Keep it for downward compatibility of the API.
  196.       */
  197.     applet.setGiacJSURL = function(url) {
  198.     };
  199.  
  200.     var doSetJavaCodebase = function(codebase, offline) {
  201.         javaCodebase = codebase;
  202.  
  203.         // Check if the codebase is online or local
  204.         isJavaOffline = offline;
  205.  
  206.         // Set the name of the JNLP file to the codebase directory
  207.         if (jnlpBaseDir === null) {
  208.             var dir='';
  209.             if (isJavaOffline) {
  210.                 var loc = window.location.pathname;
  211.                 dir = loc.substring(0, loc.lastIndexOf('/'))+'/';
  212.             }
  213.             applet.setJNLPFile(dir+codebase+'/'+buildJNLPFileName(isJavaOffline));
  214.         } else {
  215.             applet.setJNLPFile(jnlpBaseDir+javaCodebaseVersion+'/'+buildJNLPFileName(isJavaOffline));
  216.         }
  217.     };
  218.  
  219.     /**
  220.      * Overrides the JNLP file to use.
  221.      * By default (if this method is not called), the jnlp file in the codebase directory is used.
  222.      * Cannot be used in combination with setJNLPBaseDir
  223.      * @param newJnlpFilePath The absolute path to the JNLP file.
  224.      */
  225.     applet.setJNLPFile = function(newJnlpFilePath) {
  226.         jnlpFilePath = newJnlpFilePath;
  227.     };
  228.  
  229.     /**
  230.      * Sets an alternative base directory for the JNLP File. The path must not include the version number.
  231.      * @param baseDir
  232.      */
  233.     applet.setJNLPBaseDir = function(baseDir) {
  234.         jnlpBaseDir = baseDir;
  235.         applet.setJNLPFile(jnlpBaseDir+javaCodebaseVersion+'/'+buildJNLPFileName(isJavaOffline));
  236.     };
  237.  
  238.     /**
  239.      * Injects the applet;
  240.      * @param containerID The id of the HTML element that is the parent of the new applet.
  241.      * All other content (innerText) of the container will be overwritten with the new applet.
  242.      * @param type Can be 'preferJava', 'preferHTML5', 'java', 'html5', 'auto' or 'screenshot'. Default='auto';
  243.      * @param boolean noPreview. Set to true if no preview image should be shown
  244.      * @return The type of the applet that was injected or null if the applet could not be injected.
  245.      */
  246.     applet.inject = function() {
  247.         function isOwnIFrame() {
  248.             return window.frameElement && window.frameElement.getAttribute("data-singleton");
  249.         }
  250.  
  251.         var type = 'auto';
  252.         var container_ID = parameters.id;
  253.         var container;
  254.         var noPreview = false;
  255.         for(var i=0; i<arguments.length; i++) {
  256.             var p = arguments[i];
  257.             if (typeof(p) === "string") {
  258.                 p = p.toLowerCase();
  259.                 if (p === 'preferjava' || p === 'preferhtml5' || p === 'java' || p === 'html5' || p === 'auto' || p === 'screenshot' || p === 'prefercompiled' || p === 'compiled') {
  260.                     type = p;
  261.                 } else {
  262.                     container_ID = arguments[i];
  263.                 }
  264.             } else if (typeof(p) === "boolean") {
  265.                 noPreview = p;
  266.             } else if (p instanceof HTMLElement) {
  267.                 container = p;
  268.             }
  269.         }
  270.  
  271.         continueInject();
  272.  
  273.         function continueInject() {
  274.             // Check if the initialization is complete
  275.             if (! initComplete) {
  276.                 // Try again in 200 ms.
  277.                 setTimeout(continueInject, 200);
  278.                 return;
  279.             }
  280.  
  281.             // Use the container id as appletid, if it was not defined.
  282.             type = detectAppletType(type); // Sets the type to either 'java' or 'html5'
  283.  
  284.             var appletElem = container || document.getElementById(container_ID);
  285.  
  286.             if (!appletElem) {
  287.                 console.log("possibly bug on ajax loading? ");
  288.                 return;
  289.             }
  290.  
  291.             // Remove an existing applet
  292.             applet.removeExistingApplet(appletElem, false);
  293.  
  294.             // Read the applet dimensions from the container, if they were not defined in the params
  295.             //it is okay, but sadly no height of the container, so we must take care of this too - geogebraweb won't wet widht and height if one if it 0
  296.             if (parameters.width === undefined && appletElem.clientWidth) {
  297.                 parameters.width = appletElem.clientWidth;
  298.             }
  299.             if (parameters.height === undefined && appletElem.clientHeight) {
  300.                 parameters.height = appletElem.clientHeight;
  301.             }
  302.  
  303.             if (!(parameters.width && parameters.height) && type === "html5") {
  304.                 delete parameters.width;
  305.                 delete parameters.height;
  306.             }
  307.  
  308.             // Inject the new applet
  309.             loadedAppletType = type;
  310.             if (type === "screenshot") {
  311.                 injectScreenshot(appletElem, parameters);
  312.             } else if (type === "compiled") {
  313.                 injectCompiledApplet(appletElem, parameters, true);
  314.             } else {
  315.                 // Check if applets should be loaded instantly or with a play button
  316.                 var playButton = false;
  317.                 if (parameters.hasOwnProperty("playButton") && parameters.playButton || parameters.hasOwnProperty("clickToLoad") && parameters.clickToLoad) {
  318.                     playButton = true;
  319.                 } else if (parameters.hasOwnProperty("playButtonAutoDecide") && parameters.playButtonAutoDecide) {
  320.                     playButton = (!isInIframe() || isOwnIFrame())  && isMobileDevice();
  321.                 }
  322.  
  323.                 if (playButton) {
  324.                     loadedAppletType = "screenshot";
  325.                     injectPlayButton(appletElem, parameters, noPreview, type);
  326.                 } else if (type === "java") {
  327.                     injectJavaApplet(appletElem, parameters);
  328.                 } else {
  329.                     injectHTML5Applet(appletElem, parameters, noPreview);
  330.                 }
  331.             }
  332.         }
  333.  
  334.         return;
  335.     };
  336.  
  337.     function isInIframe () {
  338.         try {
  339.             return window.self !== window.top;
  340.         } catch (e) {
  341.             return true;
  342.         }
  343.     }
  344.  
  345.     function isMobileDevice() {
  346.         if (parameters.hasOwnProperty("screenshotGenerator") && parameters.screenshotGenerator) {
  347.             return false;
  348.         }
  349.         return (Math.max(screen.width,screen.height) < 800);
  350.     }
  351.  
  352.     applet.getViews = function() {
  353.         return views;
  354.     };
  355.  
  356.     /**
  357.      * @returns boolean Whether the system is capable of showing the GeoGebra Java applet
  358.      */
  359.     applet.isJavaInstalled = function() {
  360.         if (typeof deployJava === 'undefined') {
  361.             // incase deployJava.js not available
  362.             if (navigator.javaEnabled()) {
  363.                 // Check if IE is in metro mode
  364.                 if (isInternetExplorer() && getIEVersion() >= 10) {
  365.                     if(window.innerWidth === screen.width && window.innerHeight === screen.height) {
  366.                         return false;
  367.                     }
  368.                 }
  369.  
  370.                 // Check if on Android device
  371.                 if (navigator.userAgent.indexOf('Android ') > -1) {
  372.                     return false;
  373.                 }
  374.  
  375.                 // Check if the java plugin is installed
  376.                 if (!isInternetExplorer() && !pluginEnabled('java')) {
  377.                     return false;
  378.                 }
  379.  
  380.                 return true;
  381.             }
  382.         } else {
  383.             return (deployJava.versionCheck("1.6.0+") || deployJava.versionCheck("1.4") || deployJava.versionCheck("1.5.0*"));
  384.         }
  385.     };
  386.  
  387.     function pluginEnabled(name) {
  388.         var plugins = navigator.plugins,
  389.             i = plugins.length,
  390.             regExp = new RegExp(name, 'i');
  391.         while (i--) {
  392.             if (regExp.test(plugins[i].name)) {
  393.                 return true;
  394.             }
  395.         }
  396.         return false;
  397.     }
  398.  
  399.     var fetchParametersFromTube = function(successCallback) {
  400.         var tubeurl = getTubeURL();
  401.  
  402.         // load ggbbase64 string and settings from API
  403.         var api_request = {
  404.             "request": {
  405.                 "-api": "1.0.0",
  406.                 "login": {
  407.                     "-type":"cookie",
  408.                     "-getuserinfo":"false"
  409.                 },
  410.                 "task": {
  411.                     "-type": "fetch",
  412.                     "fields": {
  413.                         "field": [
  414.                             { "-name": "id" },
  415.                             { "-name": "geogebra_format" },
  416. //                            { "-name": "prefapplettype" },
  417.                             { "-name": "width" },
  418.                             { "-name": "height" },
  419.                             { "-name": "toolbar" },
  420.                             { "-name": "menubar" },
  421.                             { "-name": "inputbar" },
  422.                             { "-name": "reseticon" },
  423.                             { "-name": "labeldrags" },
  424.                             { "-name": "shiftdragzoom" },
  425.                             { "-name": "rightclick" },
  426.                             { "-name": "ggbbase64" },
  427.                             { "-name": "preview_url" }
  428.                         ]
  429.                     },
  430.                     "filters" : {
  431.                         "field": [{
  432.                                 "-name":"id", "#text": ""+parameters.material_id+""
  433.                         }]
  434.                     },
  435.                     "order": {
  436.                         "-by": "id",
  437.                         "-type": "asc"
  438.                     },
  439.                     "limit": { "-num": "1" }
  440.                 }
  441.             }
  442.         },
  443.  
  444.         // TODO: add prefapplet type (params:'type' API:'prefapplettype')
  445.         // TODO: Read view settings from database
  446.  
  447.         success = function() {
  448.             var text = xhr.responseText;
  449.             var jsondata= JSON.parse(text); //retrieve result as an JSON object
  450.             var item = null;
  451.             for (i=0; i<jsondata.responses.response.length; i++) {
  452.                 if (jsondata.responses.response[i].item !== undefined) {
  453.                     item = jsondata.responses.response[i].item;
  454.                 }
  455.             }
  456.             if (item === null) {
  457.                 onError();
  458.                 return;
  459.             }
  460.  
  461.             if (item.geogebra_format !== "") {
  462.                 ggbVersion = item.geogebra_format;
  463.             }
  464.             if (parameters.ggbBase64 === undefined) {
  465.                 parameters.ggbBase64 = item.ggbBase64;
  466.             }
  467.             if (parameters.width === undefined) {
  468.                 parameters.width = item.width;
  469.             }
  470.             if (parameters.height === undefined) {
  471.                 parameters.height = item.height;
  472.             }
  473.             if (parameters.showToolBar === undefined) {
  474.                 parameters.showToolBar = item.toolbar === "true";
  475.             }
  476.             if (parameters.showMenuBar === undefined) {
  477.                 parameters.showMenuBar = item.menubar === "true";
  478.             }
  479.             if (parameters.showAlgebraInput === undefined) {
  480.                 parameters.showAlgebraInput = item.inputbar === "true";
  481.             }
  482.             if (parameters.showResetIcon === undefined) {
  483.                 parameters.showResetIcon = item.reseticon === "true";
  484.             }
  485.             if (parameters.enableLabelDrags === undefined) {
  486.                 parameters.enableLabelDrags = item.labeldrags === "true";
  487.             }
  488.             if (parameters.enableShiftDragZoom === undefined) {
  489.                 parameters.enableShiftDragZoom = item.shiftdragzoom === "true";
  490.             }
  491.             if (parameters.enableRightClick === undefined) {
  492.                 parameters.enableRightClick = item.rightclick === "true";
  493.             }
  494.             if (parameters.showToolBarHelp === undefined) {
  495.                 parameters.showToolBarHelp =  parameters.showToolBar;
  496.             }
  497.  
  498.             if (parseFloat(item.geogebra_format) >= 5.0) {
  499.                 views.is3D = true;
  500.             }
  501.  
  502. //            var views = {"is3D":false,"AV":false,"SV":false,"CV":false,"EV2":false,"CP":false,"PC":false,"DA":false,"FI":false,"PV":false,"macro":false};
  503.  
  504.             var previewUrl = (item.previewUrl === undefined) ? tubeurl+"/files/material-"+item.id+".png" : item.previewUrl;
  505.             applet.setPreviewImage(previewUrl, tubeurl+"/images/GeoGebra_loading.png", tubeurl+"/images/applet_play.png");
  506.  
  507.             successCallback();
  508.         };
  509.  
  510.         var url = tubeurl+"/api/json.php";
  511.         var xhr = createCORSRequest('POST', url);
  512.  
  513.         var onError = function() {
  514.             log("Error: The request for fetching material_id " + parameters.material_id + " from tube was not successful.");
  515.         };
  516.  
  517.         if (!xhr) {
  518.             onError();
  519.             return;
  520.         }
  521.  
  522.         // Response handlers.
  523.         xhr.onload = success;
  524.         xhr.onerror = onError;
  525.         xhr.onprogress = function(){}; // IE9 will abort the xhr.send without this
  526.  
  527.         // Send request
  528.         if ( xhr.setRequestHeader ) { // IE9's XDomainRequest does not support this method
  529.             xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  530.         }
  531.         xhr.send(JSON.stringify(api_request));
  532.     };
  533.  
  534.     // Create the XHR object.
  535.     function createCORSRequest(method, url) {
  536.         var xhr = new XMLHttpRequest();
  537.         if ("withCredentials" in xhr) {
  538.             // XHR for Chrome/Firefox/Opera/Safari.
  539.             xhr.open(method, url, true);
  540.         } else if (typeof XDomainRequest !== "undefined") {
  541.             // XDomainRequest for IE.
  542.             xhr = new XDomainRequest();
  543.             xhr.open(method, url);
  544.         } else {
  545.             // CORS not supported.
  546.             xhr = null;
  547.         }
  548.         return xhr;
  549.     }
  550.  
  551.  
  552.     /**
  553.      * @return NULL if no version found. Else return some things like: '1.6.0_31'
  554.      */
  555.     var JavaVersion = function() {
  556.         var resutl = null;
  557.         // Walk through the full list of mime types.
  558.         for( var i=0,size=navigator.mimeTypes.length; i<size; i++ )
  559.         {
  560.             // The jpi-version is the plug-in version.  This is the best
  561.             // version to use.
  562.             if( (resutl = navigator.mimeTypes[i].type.match(/^application\/x-java-applet;jpi-version=(.*)$/)) !== null ) {
  563.                 return resutl[1];
  564.             }
  565.         }
  566.         return null;
  567.     };
  568.  
  569.     /**
  570.      * @returns boolean Whether the system is capable of showing the GeoGebra HTML5 applet
  571.      */
  572.     applet.isHTML5Installed = function() {
  573.         if (isInternetExplorer()) {
  574.             if ((views.is3D || html5CodebaseScript === "web3d.nocache.js") && getIEVersion() < 11) { // WebGL is supported since IE 11
  575.                 return false;
  576.             } else if (getIEVersion() < 10) {
  577.                 return false;
  578.             }
  579.         }
  580.         return true;
  581.     };
  582.  
  583.     /**
  584.      * @returns boolean Whether the system is capable of showing precompiled HTML5 applets
  585.      */
  586.     applet.isCompiledInstalled = function() {
  587.         if (isInternetExplorer()) {
  588.             if (views.is3D && getIEVersion() < 11) { // WebGL is supported since IE 11
  589.                 return false;
  590.             } else if (getIEVersion() < 9) {
  591.                 return false;
  592.             }
  593.         }
  594.         return true;
  595.     };
  596.  
  597.     /**
  598.      * @returns The type of the loaded applet or null if no applet was loaded yet.
  599.      */
  600.     applet.getLoadedAppletType = function() {
  601.         return loadedAppletType;
  602.     };
  603.  
  604.     applet.setPreviewImage = function(previewFilePath, loadingFilePath, playFilePath) {
  605.         previewImagePath = previewFilePath;
  606.         previewLoadingPath = loadingFilePath;
  607.         previewPlayPath = playFilePath;
  608.     };
  609.  
  610.     applet.removeExistingApplet = function(appletParent, showScreenshot) {
  611.         var i;
  612.         if (typeof appletParent === 'string') {
  613.             appletParent = document.getElementById(appletParent);
  614.         }
  615.         if (loadedAppletType === 'compiled' && window[parameters.id] !== undefined) {
  616.             // Stop/remove the applet
  617.             if (typeof window[parameters.id].stopAnimation === "function") {
  618.                 window[parameters.id].stopAnimation();
  619.             }
  620.             if (typeof window[parameters.id].remove === "function") {
  621.                 window[parameters.id].remove();
  622.             }
  623.  
  624.             // Set the applet objects to undefined
  625.             if (ggbApplets !== undefined) {
  626.                 for (i=0; i<ggbApplets.length;i++) {
  627.                     if (ggbApplets[i] === window[parameters.id]) {
  628.                         ggbApplets.splice(i, 1);
  629.                     }
  630.                 }
  631.             }
  632.             window[parameters.id] = undefined;
  633.         }
  634.  
  635.         loadedAppletType = null;
  636.         for (i=0; i<appletParent.childNodes.length;i++) {
  637.             var tag = appletParent.childNodes[i].tagName;
  638.             if (appletParent.childNodes[i].className === "applet_screenshot") {
  639.                 if (showScreenshot) {
  640.                     // Show the screenshot instead of the removed applet
  641.                     appletParent.childNodes[i].style.display = "block";
  642.                     loadedAppletType = "screenshot";
  643.                 } else {
  644.                     // Hide the screenshot
  645.                     appletParent.childNodes[i].style.display = "none";
  646.                 }
  647.             } else if (tag === "APPLET" || tag === "ARTICLE" || tag === "DIV" || (loadedAppletType === 'compiled' && (tag === "SCRIPT" || tag === "STYLE"))) {
  648.                 // Remove the applet
  649.                 appletParent.removeChild(appletParent.childNodes[i]);
  650.                 i--;
  651.             }
  652.         }
  653.  
  654.         var appName = (parameters.id !== undefined ? parameters.id : "ggbApplet");
  655.         var app = window[appName];
  656.         if (app) {
  657.             if (typeof app === "object" && typeof app.getBase64 === "function") { // Check if the variable is a GeoGebra Applet and remove it
  658.                 app.remove();
  659.                 window[appName] = null;
  660.             }
  661.         }
  662.     };
  663.  
  664.     applet.refreshHitPoints = function() {
  665.         if (parseVersion(ggbHTML5LoadedCodebaseVersion) >= 5.0) {
  666.             return true; // Not necessary anymore in 5.0
  667.         }
  668.         var app = applet.getAppletObject();
  669.         if (app) {
  670.             if (typeof app.recalculateEnvironments === "function") {
  671.                 app.recalculateEnvironments();
  672.                 return true;
  673.             }
  674.         }
  675.         return false;
  676.     };
  677.  
  678.     applet.startAnimation = function() {
  679.         var app = applet.getAppletObject();
  680.         if (app) {
  681.             if (typeof app.startAnimation === "function") {
  682.                 app.startAnimation();
  683.                 return true;
  684.             }
  685.         }
  686.         return false;
  687.     };
  688.  
  689.     applet.stopAnimation = function() {
  690.         var app = applet.getAppletObject();
  691.         if (app) {
  692.             if (typeof app.stopAnimation === "function") {
  693.                 app.stopAnimation();
  694.                 return true;
  695.             }
  696.         }
  697.         return false;
  698.     };
  699.  
  700.     applet.setPreCompiledScriptPath = function(path, version) {
  701.         preCompiledScriptPath = path;
  702.         if (preCompiledResourcePath === null) {
  703.             preCompiledResourcePath = preCompiledScriptPath;
  704.         }
  705.         preCompiledScriptVersion = version;
  706.     };
  707.  
  708.     applet.setPreCompiledResourcePath = function(path) {
  709.         preCompiledResourcePath = path;
  710.     };
  711.  
  712.     applet.getAppletObject = function() {
  713.         var appName = (parameters.id !== undefined ? parameters.id : "ggbApplet");
  714.         return window[appName];
  715.     };
  716.  
  717.     applet.resize = function() {};
  718.  
  719.     var injectJavaApplet = function(appletElem, parameters) {
  720.         var applet = document.createElement("applet");
  721.         applet.setAttribute("name", (parameters.id !== undefined ? parameters.id : "ggbApplet"));
  722.         if (parameters.height !== undefined && parameters.height > 0) {
  723.             applet.setAttribute("height", parameters.height);
  724.         }
  725.         if (parameters.width !== undefined && parameters.width > 0) {
  726.             applet.setAttribute("width", parameters.width);
  727.         }
  728.         applet.setAttribute("code", "dummy");
  729.  
  730.         appendParam(applet, "jnlp_href", jnlpFilePath);
  731.         if (isOverriddenJavaCodebase) {
  732.             appendParam(applet, "codebase", javaCodebase);
  733.         }
  734.  
  735.         appendParam(applet, "boxborder", "false");
  736.         appendParam(applet, "centerimage", "true");
  737.  
  738.         if(ggbVersion === "5.0") {
  739.             appendParam(applet, "java_arguments", "-Xmx1024m -Djnlp.packEnabled=false");
  740.         } else {
  741.             appendParam(applet, "java_arguments", "-Xmx1024m -Djnlp.packEnabled=true");
  742.         }
  743.  
  744.         // Add dynamic parameters
  745.         for (var key in parameters) {
  746.             if (key !== 'width' && key !== 'height') {
  747.                 appendParam(applet, key, parameters[key]);
  748.             }
  749.         }
  750.  
  751.         appendParam(applet, "framePossible", "false");
  752.         if (! isJavaOffline) {
  753.             appendParam(applet, "image", "http://www.geogebra.org/images/java_loading.gif");
  754.         }
  755.         appendParam(applet, "codebase_lookup", "false");
  756.  
  757.         if (navigator.appName !== 'Microsoft Internet Explorer' || getIEVersion() > 9) {
  758.             applet.appendChild(document.createTextNode("This is a Java Applet created using GeoGebra from www.geogebra.org - it looks like you don't have Java installed, please go to www.java.com"));
  759.         }
  760.  
  761.         applet.style.display = "block";
  762.         appletElem.appendChild(applet);
  763.  
  764. //        setTimeout(validateJavaApplet(appletElem, container_ID),5000);
  765.  
  766.         log("GeoGebra Java applet injected. Used JNLP file = '"+jnlpFilePath+"'"+(isOverriddenJavaCodebase?" with overridden codebase '"+javaCodebase+"'." : "."), parameters);
  767.     };
  768.  
  769.     var appendParam = function(applet, name, value) {
  770.         var param = document.createElement("param");
  771.         param.setAttribute("name", name);
  772.         param.setAttribute("value", value);
  773.         applet.appendChild(param);
  774.     };
  775.  
  776.     var valBoolean = function(value) {
  777.         return (value && value !== "false");
  778.     };
  779.  
  780.     var injectHTML5Applet = function(appletElem, parameters, noPreview) {
  781.         if (parseVersion(html5CodebaseVersion) <= 4.2) {
  782.             noPreview = true;
  783.         }
  784.         // Decide if the script has to be (re)loaded or renderGGBElement can be used to load the applet
  785.         var loadScript = !isRenderGGBElementEnabled && !scriptLoadStarted;
  786.         // Reload the script when not loaded yet, or  currently the wrong version is loaded
  787.         if ((!isRenderGGBElementEnabled && !scriptLoadStarted) || (ggbHTML5LoadedCodebaseVersion !== html5CodebaseVersion || (ggbHTML5LoadedCodebaseIsWebSimple && !html5CodebaseIsWebSimple))) {
  788.             loadScript = true ;
  789.             isRenderGGBElementEnabled = false;
  790.             scriptLoadStarted = false;
  791.         }
  792.  
  793.         var article = document.createElement("article");
  794.         var oriWidth = parameters.width;
  795.         var oriHeight = parameters.height;
  796.  
  797.         // The HTML5 version 4.4 changes the height depending on which bars are shown. So we have to correct it here.
  798.         if (parameters.width !== undefined) {
  799.             if (parseVersion(html5CodebaseVersion) <= 4.4) {
  800.                 if (valBoolean(parameters.showToolBar)) {
  801.                     parameters.height -= 7;
  802.                 }
  803.                 if (valBoolean(parameters.showAlgebraInput)) {
  804.                     parameters.height -= 37;
  805.                 }
  806.                 if (parameters.width < 605 && valBoolean(parameters.showToolBar)) {
  807.                     parameters.width = 605;
  808.                     oriWidth = 605;
  809.                 }
  810.             } else {
  811.                 // calculate the minWidth
  812.                 var minWidth = 100;
  813.                 if (valBoolean(parameters.showToolBar) || valBoolean(parameters.showMenuBar)) {
  814.                     if (parameters.hasOwnProperty("customToolBar")) {
  815.                         parameters.customToolbar = parameters.customToolBar;
  816.                     }
  817.                     minWidth = (valBoolean(parameters.showMenuBar) ? 245 : 155);
  818.                 }
  819.  
  820.                 if (oriWidth < minWidth) {
  821.                     parameters.width = minWidth;
  822.                     oriWidth = minWidth;
  823.                 }
  824.             }
  825.         }
  826.         article.className = "notranslate"; //we remove geogebraweb here, as we don't want to parse it out of the box.
  827.         article.style.border = 'none';
  828.         article.style.display = 'inline-block';
  829.  
  830.         for (var key in parameters) {
  831.             if (parameters.hasOwnProperty(key) && key !== "appletOnLoad" && key !== 'scale') {
  832.                 article.setAttribute("data-param-"+key, parameters[key]);
  833.             }
  834.         }
  835.  
  836.         // Resize the applet when the window is resized
  837.         applet.resize = function() {
  838.             GGBAppletUtils.responsiveResize(appletElem, parameters);
  839.         };
  840.  
  841.         if (typeof jQuery === "function") {
  842.             jQuery(window).resize(function() {
  843.                 applet.resize();
  844.             });
  845.         } else {
  846.             var oldOnResize = null;
  847.             if (window.onresize !== undefined && typeof window.onresize === "function") {
  848.                 oldOnResize = window.onresize;
  849.             }
  850.             window.onresize = function() {
  851.                 applet.resize();
  852.                 if (typeof oldOnResize === "function") {
  853.                     oldOnResize();
  854.                 }
  855.             };
  856.         }
  857.  
  858.  
  859.         // Add the tag for the preview image
  860.         if (!noPreview && parameters.width !== undefined) {
  861.             var previewContainer = createScreenShotDiv(oriWidth, oriHeight, parameters.borderColor, false);
  862.  
  863.             // This div is needed to have an element with position relative as origin for the absolute positioned image
  864.             var previewPositioner = document.createElement("div");
  865.             previewPositioner.className = "applet_scaler";
  866.             previewPositioner.style.position = "relative";
  867.             previewPositioner.style.display = 'block';
  868.             previewPositioner.style.width = oriWidth+'px';
  869.             previewPositioner.style.height = oriHeight+'px';
  870.  
  871.             // Prevent GeoGebraWeb from showing the splash
  872.             if (!parameters.hasOwnProperty('showSplash')) {
  873.                 article.setAttribute("data-param-showSplash", 'false');
  874.             }
  875.  
  876.             if (window.GGBT_spinner) {
  877.                 window.GGBT_spinner.attachSpinner(previewPositioner, '66%');
  878.             }
  879.  
  880.             if (parseVersion(html5CodebaseVersion)>=5.0) {
  881.  
  882.                 // Workaround: Remove the preview image when the applet is fully loaded
  883.                 if (typeof parameters.appletOnLoad === "function") {
  884.                     var oriAppletOnload = parameters.appletOnLoad;
  885.                 }
  886.                 parameters.appletOnLoad = function() {
  887.                     var preview = appletElem.querySelector(".ggb_preview");
  888.                     if (preview) {
  889.                         preview.parentNode.removeChild(preview);
  890.                     }
  891.                     if (window.GGBT_spinner) {
  892.                         window.GGBT_spinner.removeSpinner(previewPositioner);
  893.                     }
  894.                     if (typeof oriAppletOnload === "function") {
  895.                         oriAppletOnload();
  896.                     }
  897.                 };
  898.                 previewPositioner.appendChild(previewContainer);
  899.             } else {
  900.                 article.appendChild(previewContainer);
  901.             }
  902.  
  903.             previewPositioner.appendChild(article);
  904.             appletElem.appendChild(previewPositioner);
  905.  
  906.             // Redo resizing when screenshot is loaded to recalculate it after scrollbars are gone
  907.             setTimeout(function() {
  908.                 applet.resize();
  909.             }, 1);
  910.         } else {
  911.             var appletScaler = document.createElement("div");
  912.             appletScaler.className = "applet_scaler";
  913.             appletScaler.style.position = "relative";
  914.             appletScaler.style.display = 'block';
  915.  
  916.             appletScaler.appendChild(article);
  917.             appletElem.appendChild(appletScaler);
  918.  
  919.             // Apply scaling
  920.             applet.resize();
  921.         }
  922.  
  923.  
  924.         function renderGGBElementWithParams(article, parameters) {
  925.             if (parameters && typeof parameters.appletOnLoad === "function" && typeof renderGGBElement === "function") {
  926.                 renderGGBElement(article, parameters.appletOnLoad);
  927.             } else {
  928.                 renderGGBElement(article);
  929.             }
  930.  
  931.             log("GeoGebra HTML5 applet injected and rendered with previously loaded codebase.", parameters);
  932.         }
  933.  
  934.  
  935.         function renderGGBElementOnTube(a, parameters) {
  936.             if (typeof renderGGBElement === "undefined") {
  937.                 //it is possible, that we get here many times, before script are loaded. So best here to save the article element for later - otherwise only last article processed :-)
  938.                 if (html5AppletsToProcess === null) {
  939.                     html5AppletsToProcess = [];
  940.                 }
  941.                 html5AppletsToProcess.push({
  942.                     article : a,
  943.                     params : parameters
  944.                 });
  945.                 window.renderGGBElementReady = function() {
  946.                     isRenderGGBElementEnabled = true;
  947.                     if (html5AppletsToProcess !== null && html5AppletsToProcess.length) {
  948.                         html5AppletsToProcess.forEach(function(obj) {
  949.                             renderGGBElementWithParams(obj.article, obj.params);
  950.                         });
  951.                         html5AppletsToProcess = null;
  952.                     }
  953.  
  954.                 };
  955.  
  956.                 //TODO: remove this hack, because it is a hack!
  957.                 if (parseVersion(html5CodebaseVersion) < 5.0) {
  958.                         a.className += " geogebraweb";
  959.                 }
  960.  
  961.             } else {
  962.                 renderGGBElementWithParams(a, parameters);
  963.             }
  964.         }
  965.  
  966.         // Load the web script
  967.         if (loadScript) {
  968.             scriptLoadStarted = true;
  969.             if (parseVersion(html5CodebaseVersion)>=4.4) {
  970.                 var f_c_u;
  971.                 if (fonts_css_url === null) {
  972.                     f_c_u = html5Codebase+"css/fonts.css";
  973.                 } else {
  974.                     f_c_u = fonts_css_url;
  975.                 }
  976.  
  977.                 var fontscript1 = document.createElement("script");
  978.                 fontscript1.type = 'text/javascript';
  979.                 fontscript1.innerHTML = '\n' +
  980.                     '//<![CDATA[\n' +
  981.                     'WebFontConfig = {\n' +
  982.                     '   loading: function() {},\n' +
  983.                     '   active: function() {},\n' +
  984.                     '   inactive: function() {},\n' +
  985.                     '   fontloading: function(familyName, fvd) {},\n' +
  986.                     '   fontactive: function(familyName, fvd) {},\n' +
  987.                     '   fontinactive: function(familyName, fvd) {},\n' +
  988.                     '   custom: {\n' +
  989.                     '       families: ["geogebra-sans-serif", "geogebra-serif"],\n' +
  990.                     '           urls: [ "'+f_c_u+'" ]\n' +
  991.                     '   }\n' +
  992.                     '};\n' +
  993.                     '//]]>\n' +
  994.                     '\n';
  995.  
  996.                 var fontscript2 = document.createElement("script");
  997.                 fontscript2.type = 'text/javascript';
  998.                 fontscript2.src = html5Codebase+'js/webfont.js';
  999.  
  1000.                 appletElem.appendChild(fontscript1);
  1001.                 appletElem.appendChild(fontscript2);
  1002.             }
  1003.  
  1004.             // Remove all table tags within an article tag if there are any
  1005.             for (var i=0; i<article.childNodes.length;i++) {
  1006.                 var tag = article.childNodes[i].tagName;
  1007.                 if (tag === "TABLE") {
  1008.                     article.removeChild(article.childNodes[i]);
  1009.                     i--;
  1010.                 }
  1011.             }
  1012.  
  1013.             // Remove old script tags
  1014.             if (ggbHTML5LoadedScript !== null) {
  1015.                 var el = document.querySelector('script[src="'+ggbHTML5LoadedScript+'"]');
  1016.                 if (el !== undefined) {
  1017.                     el.parentNode.removeChild(el);
  1018.                 }
  1019.             }
  1020.  
  1021.             var script = document.createElement("script");
  1022.  
  1023.             var scriptLoaded = function() {
  1024.                 renderGGBElementOnTube(article, parameters);
  1025.             };
  1026.  
  1027.             log(html5Codebase);
  1028.  
  1029.             script.src=html5Codebase + html5CodebaseScript;
  1030.             script.onload = scriptLoaded;
  1031.             ggbHTML5LoadedCodebaseIsWebSimple = html5CodebaseIsWebSimple;
  1032.             ggbHTML5LoadedCodebaseVersion = html5CodebaseVersion;
  1033.             ggbHTML5LoadedScript = script.src;
  1034.             log("GeoGebra HTML5 codebase loaded: '"+html5Codebase+"'.", parameters);
  1035.             appletElem.appendChild(script);
  1036.         } else {
  1037.             renderGGBElementOnTube(article, parameters);
  1038.         }
  1039.  
  1040.         parameters.height = oriHeight;
  1041.         parameters.width = oriWidth;
  1042.     };
  1043.  
  1044.     var injectCompiledApplet = function(appletElem, parameters, noPreview) {
  1045.         var appletObjectName = parameters.id;
  1046.         //if (scale !== 1) {
  1047.         //    parameters.scale = scale;
  1048.         //    appletElem.style.minWidth = parameters.width * scale+"px";
  1049.         //    appletElem.style.minHeight = parameters.height * scale+"px";
  1050.         //}
  1051.  
  1052.         var viewContainer = document.createElement("div");
  1053.         viewContainer.id = "view-container-"+appletObjectName;
  1054.         viewContainer.setAttribute("width", parameters.width);
  1055.         viewContainer.setAttribute("height", parameters.height);
  1056.         viewContainer.style.width = parameters.width+"px";
  1057.         viewContainer.style.height = parameters.height+"px";
  1058. //        viewContainer.style.border = "1px solid black";
  1059.  
  1060.         if (parameters.showSplash === undefined) {
  1061.             parameters.showSplash = true;
  1062.         }
  1063.  
  1064.         // Resize the applet when the window is resized
  1065.         var oldOnResize = null;
  1066.         if (window.onresize !== undefined && typeof window.onresize === "function") {
  1067.             oldOnResize = window.onresize;
  1068.         }
  1069.         window.onresize = function() {
  1070.             var scale = GGBAppletUtils.getScale(parameters, appletElem);
  1071.             var scaleElem = null;
  1072.             for (var i=0; i<appletElem.childNodes.length;i++) {
  1073.                 if (appletElem.childNodes[i].className === "applet_scaler") {
  1074.                     scaleElem = appletElem.childNodes[i];
  1075.                     break;
  1076.                 }
  1077.             }
  1078.  
  1079.             if (scaleElem !== null) {
  1080.                 scaleElem.style.transformOrigin = "0% 0% 0px";
  1081.                 scaleElem.parentNode.style.transform = "";
  1082.                 if (!isNaN(scale) && scale !== 1) {
  1083.                     // Set the scale factor for the applet
  1084.                     scaleElem.style.transform = "scale(" + scale + "," + scale + ")";
  1085.                     scaleElem.parentNode.style.width = ((parameters.width+2)*scale)+'px';
  1086.                     scaleElem.parentNode.style.height = ((parameters.height+2)*scale)+'px';
  1087.  
  1088.                 } else {
  1089.                     // Remove scaling
  1090.                     scaleElem.style.transform = "none";
  1091.                     scaleElem.parentNode.style.width = (parameters.width+2)+'px';
  1092.                     scaleElem.parentNode.style.height = (parameters.height+2)+'px';
  1093.                 }
  1094.             }
  1095.  
  1096.             var appName = (parameters.id !== undefined ? parameters.id : "ggbApplet");
  1097.             var app = window[appName];
  1098.             if (app !== undefined && app !== null && typeof app.recalculateEnvironments === "function") {
  1099.                 app.recalculateEnvironments();
  1100.             }
  1101.  
  1102.             if (oldOnResize !== null) {
  1103.                 oldOnResize();
  1104.             }
  1105.         };
  1106.  
  1107.  
  1108.         var viewImages = document.createElement("div");
  1109.         viewImages.id = '__ggb__images';
  1110.  
  1111.         // Add the tag for the preview image
  1112.         var appletScaler;
  1113.         if (!noPreview && previewImagePath !== null && parseVersion(html5CodebaseVersion)>=4.4 && parameters.width !== undefined) {
  1114.             var previewContainer = createScreenShotDiv(parameters.width, parameters.height, parameters.borderColor, false);
  1115.  
  1116.             // This div is needed to have an element with position relative as origin for the absolute positioned image
  1117.             var previewPositioner = document.createElement("div");
  1118.             previewPositioner.style.position = "relative";
  1119.             previewPositioner.className = "applet_scaler";
  1120.             previewPositioner.style.display = 'block';
  1121.             previewPositioner.style.width = parameters.width+'px';
  1122.             previewPositioner.style.height = parameters.height+'px';
  1123.             previewPositioner.appendChild(previewContainer);
  1124.             appletElem.appendChild(previewPositioner);
  1125.             appletScaler = previewPositioner;
  1126.  
  1127.             // Redo resizing when screenshot is loaded to recalculate it after scrollbars are gone
  1128.             setTimeout(function() {
  1129.                 window.onresize();
  1130.             }, 1);
  1131.  
  1132.             if (typeof window.GGBT_ws_header_footer === "object") {
  1133.                 window.GGBT_ws_header_footer.setWsScrollerHeight();
  1134.             }
  1135.         } else {
  1136.             appletScaler = document.createElement("div");
  1137.             appletScaler.className = "applet_scaler";
  1138.             appletScaler.style.position = "relative";
  1139.             appletScaler.style.display = 'block';
  1140.  
  1141.             appletElem.appendChild(appletScaler);
  1142.             window.onresize();
  1143.         }
  1144.  
  1145.         // Load the web fonts
  1146.         if (!ggbCompiledResourcesLoadFinished && !ggbCompiledResourcesLoadInProgress) {
  1147. //            var resource1 = document.createElement("link");
  1148. //            resource1.type = 'text/css';
  1149. //            resource1.rel = 'stylesheet';
  1150. //            resource1.href = preCompiledResourcePath+'/mathquillggb.css';
  1151. //
  1152. //            var resource2 = document.createElement("script");
  1153. //            resource2.type = 'text/javascript';
  1154. //            resource2.src = preCompiledResourcePath+'/jquery-1.7.2.min.js';
  1155. //
  1156. //            var resource3 = document.createElement("script");
  1157. //            resource3.type = 'text/javascript';
  1158. //            resource3.src = preCompiledResourcePath+'/mathquillggb.js';
  1159.  
  1160.             var resource4 = document.createElement("script");
  1161.             resource4.type = 'text/javascript';
  1162.             resource4.innerHTML = '\n' +
  1163.                 'WebFontConfig = {\n' +
  1164.                 '   loading: function() {},\n' +
  1165.                 '   active: function() {},\n' +
  1166.                 '   inactive: function() {},\n' +
  1167.                 '   fontloading: function(familyName, fvd) {},\n' +
  1168.                 '   fontactive: function(familyName, fvd) {' +
  1169.                 '       if (!ggbCompiledAppletsLoaded) {' +
  1170.                 '           ggbCompiledAppletsLoaded = true;' +
  1171.                 '           ' +
  1172.                 '           setTimeout(function() {' +
  1173.                 '               ggbCompiledResourcesLoadFinished = true;' +
  1174.                 '               ggbCompiledResourcesLoadInProgress = false;' +
  1175.                 '               if (window.ggbApplets != undefined) {' +
  1176.                 '                   for (var i = 0 ; i < window.ggbApplets.length ; i++) {' +
  1177.                 '                       window.ggbApplets[i].init({scale:window.ggbApplets[i].scaleParameter, url:window.ggbApplets[i].preCompiledScriptPath+"/", ss:'+(parameters.showSplash?'true':'false')+', sdz:'+(parameters.enableShiftDragZoom?'true':'false')+', rc:'+(parameters.enableRightClick?'true':'false')+', sri:'+(parameters.showResetIcon?'true':'false')+'});' +
  1178.                 '                   }' +
  1179.                 '               }' +
  1180.                 '               if (typeof window.ggbCompiledAppletsOnLoad == "function") {' +
  1181.                 '                   window.ggbCompiledAppletsOnLoad();' +
  1182.                 '               }' +
  1183.                 '           },1);' +
  1184.                 '       }' +
  1185.                 '   },\n' +
  1186.                 '   fontinactive: function(familyName, fvd) {},\n' +
  1187.                 '   custom: {\n' +
  1188.                 '       families: ["geogebra-sans-serif", "geogebra-serif"],\n' +
  1189.                 '           urls: [ "'+preCompiledResourcePath+"/fonts/fonts.css"+'" ]\n' +
  1190.                 '   }\n' +
  1191.                 '};\n' +
  1192.                 '\n';
  1193.  
  1194.             var resource5 = document.createElement("script");
  1195.             resource5.type = 'text/javascript';
  1196.             resource5.src = preCompiledResourcePath+'/fonts/webfont.js';
  1197.  
  1198.             ggbCompiledResourcesLoadInProgress = true;
  1199. //            appletScaler.appendChild(resource1);
  1200. //            appletScaler.appendChild(resource2);
  1201. //            appletScaler.appendChild(resource3);
  1202.             appletScaler.appendChild(resource4);
  1203.             appletScaler.appendChild(resource5);
  1204.         }
  1205.  
  1206.         // Load the applet script
  1207.         var appletStyle = document.createElement("style");
  1208.         appletStyle.innerHTML = '\n' +
  1209.             '.view-frame {\n' +
  1210.             '    border: 1px solid black;\n' +
  1211.             '    display: inline-block;\n' +
  1212.             '}\n' +
  1213.             '#tip {\n' +
  1214.             '    background-color: yellow;\n' +
  1215.             '    border: 1px solid blue;\n' +
  1216.             '    position: absolute;\n' +
  1217.             '    left: -200px;\n' +
  1218.             '    top: 100px;\n' +
  1219.             '};\n';
  1220.  
  1221.         appletScaler.appendChild(appletStyle);
  1222.  
  1223.         var script = document.createElement("script");
  1224.  
  1225.         var scriptLoaded = function() {
  1226.             window[appletObjectName].preCompiledScriptPath = preCompiledScriptPath;
  1227.             window[appletObjectName].scaleParameter = parameters.scale;
  1228.  
  1229.             if (!noPreview) {
  1230.                 appletScaler.querySelector(".ggb_preview").remove();
  1231.             }
  1232.             appletScaler.appendChild(viewContainer);
  1233.             appletScaler.appendChild(viewImages);
  1234.  
  1235.             if (ggbCompiledResourcesLoadFinished) {
  1236.                 window[appletObjectName].init({scale:parameters.scale, url:preCompiledScriptPath+'/', ss:parameters.showSplash, sdz:parameters.enableShiftDragZoom, rc:parameters.enableRightClick, sri:parameters.showResetIcon});
  1237.                 if (typeof window.ggbAppletOnLoad === 'function') {
  1238.                     window.ggbAppletOnLoad(appletElem.id);
  1239.                 }
  1240.                 if (typeof parameters.appletOnLoad === 'function') {
  1241.                     parameters.appletOnLoad(appletElem.id);
  1242.                 }
  1243.  
  1244.             }
  1245.         };
  1246.  
  1247.         var scriptFile = preCompiledScriptPath + "/applet.js" + (preCompiledScriptVersion !== null && preCompiledScriptVersion !== null ? "?v="+preCompiledScriptVersion : "");
  1248.         script.src=scriptFile;
  1249.         script.onload = scriptLoaded;
  1250.  
  1251.         log("GeoGebra precompiled applet injected. Script="+scriptFile+".");
  1252.         appletScaler.appendChild(script);
  1253.     };
  1254.  
  1255.     var injectScreenshot = function(appletElem, parameters, showPlayButton) {
  1256.         // Add the tag for the preview image
  1257.         var previewContainer = createScreenShotDiv(parameters.width, parameters.height, parameters.borderColor, showPlayButton);
  1258.  
  1259.         // This div is needed to have an element with position relative as origin for the absolute positioned image
  1260.         var previewPositioner = document.createElement("div");
  1261.         previewPositioner.style.position = "relative";
  1262.         previewPositioner.style.display = 'block';
  1263.         previewPositioner.style.width = parameters.width+'px';
  1264.         previewPositioner.style.height = parameters.height+'px';
  1265.         previewPositioner.className = "applet_screenshot applet_scaler" + (showPlayButton ? " applet_screenshot_play" : "");
  1266.         previewPositioner.appendChild(previewContainer);
  1267.  
  1268.         var scale = GGBAppletUtils.getScale(parameters, appletElem, showPlayButton);
  1269.  
  1270.  
  1271.         if(showPlayButton) {
  1272.             appletElem.appendChild(getPlayButton());
  1273.             if (!window.GGBT_wsf_view) {
  1274.                 appletElem.style.position = "relative";
  1275.             }
  1276.         } else if (window.GGBT_spinner) {
  1277.             window.GGBT_spinner.attachSpinner(previewPositioner, '66%');
  1278.         }
  1279.  
  1280.         appletElem.appendChild(previewPositioner);
  1281.  
  1282.         // Set the scale for the preview image
  1283.         if (scale !== 1 && !isNaN(scale)) {
  1284.             // Set the scale factor for the preview image
  1285.             previewPositioner.style.transform = "scale(" + scale + "," + scale + ")";
  1286.             previewPositioner.style.transformOrigin = "0% 0% 0px";
  1287.             previewPositioner.style.width = (parameters.width)+'px';
  1288.             previewPositioner.style.height = (parameters.height)+'px';
  1289.             previewPositioner.parentNode.style.width = (parameters.width*scale)+'px';
  1290.             previewPositioner.parentNode.style.height = (parameters.height*scale)+'px';
  1291.         }
  1292.  
  1293.         applet.resize = function() {
  1294.             resizeScreenshot(appletElem, previewContainer, previewPositioner, showPlayButton);
  1295.         };
  1296.  
  1297.         if (typeof jQuery === "function") {
  1298.             jQuery(window).resize(function() {
  1299.                 applet.resize();
  1300.             });
  1301.         } else {
  1302.             var oldOnResize = null;
  1303.             // Resize the preview when the window is resized
  1304.             if (window.onresize !== undefined && typeof window.onresize === "function") {
  1305.                 oldOnResize = window.onresize;
  1306.             }
  1307.             window.onresize = function() {
  1308.                 applet.resize();
  1309.                 if (typeof oldOnResize === "function") {
  1310.                     oldOnResize();
  1311.                 }
  1312.             };
  1313.         }
  1314.         applet.resize();
  1315.     };
  1316.  
  1317.     function resizeScreenshot(appletElem, previewContainer, previewPositioner, showPlayButton, oldOnResize) {
  1318.         if (!appletElem.contains(previewContainer)) { // Don't resize the screenshot if it is not visible (anymore)
  1319.             return;
  1320.         }
  1321.  
  1322.         if (typeof window.GGBT_wsf_view === "object" && window.GGBT_wsf_view.isFullscreen()) {
  1323.             if (appletElem.id !== "fullscreencontent") {
  1324.                 return;
  1325.             }
  1326.             window.GGBT_wsf_view.setCloseBtnPosition(appletElem);
  1327.         }
  1328.  
  1329.         var scale = GGBAppletUtils.getScale(parameters, appletElem, showPlayButton);
  1330.  
  1331.         if (previewPositioner.parentNode !== null) {
  1332.             if (!isNaN(scale) && scale !== 1) {
  1333.                 previewPositioner.style.transform = "scale(" + scale + "," + scale + ")";
  1334.                 previewPositioner.style.transformOrigin = "0% 0% 0px";
  1335.                 previewPositioner.parentNode.style.width = (parameters.width * scale) + 'px';
  1336.                 previewPositioner.parentNode.style.height = (parameters.height * scale) + 'px';
  1337.             } else {
  1338.                 previewPositioner.style.transform = "none";
  1339.                 previewPositioner.parentNode.style.width = (parameters.width) + 'px';
  1340.                 previewPositioner.parentNode.style.height = (parameters.height) + 'px';
  1341.             }
  1342.         }
  1343.  
  1344.         // positions the applet in the center of the popup
  1345.         if(typeof window.GGBT_wsf_view === 'object' && window.GGBT_wsf_view.isFullscreen()) {
  1346.             GGBAppletUtils.positionCenter(appletElem);
  1347.         }
  1348.  
  1349.         if (typeof window.GGBT_ws_header_footer === "object") {
  1350.             window.GGBT_ws_header_footer.setWsScrollerHeight();
  1351.         }
  1352.  
  1353.         if (typeof oldOnResize === "function") {
  1354.             oldOnResize();
  1355.         }
  1356.  
  1357.     }
  1358.  
  1359.     applet.onExitFullscreen = function(fullscreenContainer, appletElem) {
  1360.         appletElem.appendChild(fullscreenContainer);
  1361.     };
  1362.  
  1363.     var injectPlayButton = function(appletElem, parameters, noPreview, type) {
  1364.         injectScreenshot (appletElem, parameters, true);
  1365.  
  1366.         // Load applet on play button click
  1367.         var play = function() {
  1368.             // Remove the screenshot after the applet is injected
  1369.             var elems = [];
  1370.             for (i=0; i<appletElem.childNodes.length;i++) {
  1371.                 elems.push(appletElem.childNodes[i]);
  1372.             }
  1373.             if (type === "java") {
  1374.                 loadedAppletType = type;
  1375.                 injectJavaApplet(appletElem, parameters);
  1376.             } else {
  1377.                 if (window.GGBT_wsf_view) {
  1378.                     var content = window.GGBT_wsf_view.renderFullScreen(appletElem, parameters.id);
  1379.                     var container = document.getElementById("fullscreencontainer");
  1380.                     var oldcontent = jQuery(appletElem).find('.fullscreencontent');
  1381.                     if (oldcontent.length > 0) {
  1382.                         // Reuse the previously rendered applet
  1383.                         content.remove();
  1384.                         oldcontent.attr("id", "fullscreencontent").show();
  1385.                         jQuery(container).append(oldcontent);
  1386.                         window.onresize();
  1387.                     } else {
  1388.                         // Render a new applet
  1389.                         injectHTML5Applet(content, parameters, false);
  1390.                     }
  1391.                     window.GGBT_wsf_view.launchFullScreen(container);
  1392.                 } else {
  1393.                     loadedAppletType = type;
  1394.                     injectHTML5Applet(appletElem, parameters, false);
  1395.                 }
  1396.             }
  1397.  
  1398.             if (!window.GGBT_wsf_view) {
  1399.                 for (i = 0; i < elems.length; i++) {
  1400.                     appletElem.removeChild(elems[i]);
  1401.                 }
  1402.             }
  1403.         };
  1404.  
  1405.         // Find the play button and add the click handler
  1406.         var imgs = appletElem.getElementsByClassName("ggb_preview_play");
  1407.         for (var i = 0; i < imgs.length; i++) {
  1408.             imgs[i].addEventListener('click', play, false);
  1409.             imgs[i].addEventListener('ontouchstart', play, false);
  1410.         }
  1411.  
  1412.         // Call onload
  1413.         if (typeof window.ggbAppletPlayerOnload === 'function') {
  1414.             window.ggbAppletPlayerOnload(appletElem);
  1415.         }
  1416.  
  1417.         //remove fullscreen button if not needed
  1418.         if (isMobileDevice() && window.GGBT_wsf_view) {
  1419.             $(".wsf-element-fullscreen-button").remove();
  1420.         }
  1421.     };
  1422.  
  1423.     var getPlayButton = function() {
  1424.         var playButtonContainer = document.createElement("div");
  1425.         playButtonContainer.className = 'ggb_preview_play icon-applet-play';
  1426.         if (!window.GGBT_wsf_view) { // on tube, the play button image is defined in a css file
  1427.             var css = '' +
  1428.                 '.icon-applet-play {' +
  1429.                 '   width: 100%;' +
  1430.                 '   height: 100%;box-sizing: border-box;position: absolute;z-index: 1001;cursor: pointer;border-width: 0px;' +
  1431.                 '   background-color: transparent;background-repeat: no-repeat;left: 0;top: 0;background-position: center center;' +
  1432.                 '   background-image: url("'+getTubeURL()+'/images/worksheet/icon-start-applet.png");' +
  1433.                 '}' +
  1434.                 '.icon-applet-play:hover {' +
  1435.                         'background-image: url("'+getTubeURL()+'/images/worksheet/icon-start-applet-hover.png");' +
  1436.                 '}';
  1437.             var style = document.createElement('style');
  1438.  
  1439.             if (style.styleSheet) {
  1440.                 style.styleSheet.cssText = css;
  1441.             } else {
  1442.                 style.appendChild(document.createTextNode(css));
  1443.             }
  1444.  
  1445.             document.getElementsByTagName('head')[0].appendChild(style);
  1446.         }
  1447.         return playButtonContainer;
  1448.     };
  1449.  
  1450.     var createScreenShotDiv = function(oriWidth, oriHeight, borderColor, showPlayButton) {
  1451.         var previewContainer = document.createElement("div");
  1452.         previewContainer.className = "ggb_preview";
  1453.         previewContainer.style.position = "absolute";
  1454.         //previewContainer.style.zIndex = "1000001";
  1455.         // too high z-index causes various problems
  1456.         // overlaps fixed header
  1457.         // overlaps popups
  1458.         previewContainer.style.zIndex = "90";
  1459.         previewContainer.style.width = oriWidth-2+'px'; // Remove 2 pixel for the border
  1460.         previewContainer.style.height = oriHeight-2+'px'; // Remove 2 pixel for the border
  1461.         previewContainer.style.top = "0px";
  1462.         previewContainer.style.left = "0px";
  1463.         previewContainer.style.overflow = "hidden";
  1464.         previewContainer.style.backgroundColor = "white";
  1465.         var bc = 'lightgrey';
  1466.         if (borderColor !== undefined) {
  1467.             if (borderColor === "none") {
  1468.                 bc = "transparent";
  1469.             } else {
  1470.                 bc = borderColor;
  1471.             }
  1472.         }
  1473.         previewContainer.style.border = "1px solid " + bc;
  1474.  
  1475.         var preview = document.createElement("img");
  1476.         preview.style.position = "relative";
  1477.         preview.style.zIndex = "1000";
  1478.         preview.style.top = "-1px"; // Move up/left to hide the border on the image
  1479.         preview.style.left = "-1px";
  1480.         if (previewImagePath !== null) {
  1481.             preview.setAttribute("src", previewImagePath);
  1482.         }
  1483.         preview.style.opacity = 0.7;
  1484.  
  1485.         if (previewLoadingPath !== null) {
  1486.  
  1487.             var previewOverlay;
  1488.  
  1489.             var pWidth, pHeight;
  1490.             if (!showPlayButton) {
  1491.                 previewOverlay = document.createElement("img");
  1492.                 previewOverlay.style.position = "absolute";
  1493.                 previewOverlay.style.zIndex = "1001";
  1494.                 previewOverlay.style.opacity = 1.0;
  1495.  
  1496.                 preview.style.opacity = 0.3;
  1497.  
  1498.                 pWidth = 360;
  1499.                 if (pWidth > (oriWidth/4*3)) {
  1500.                     pWidth = oriWidth/4*3;
  1501.                 }
  1502.                 pHeight = pWidth/5.8;
  1503.                 previewOverlay.setAttribute("src", previewLoadingPath);
  1504.  
  1505.                 previewOverlay.setAttribute("width", pWidth);
  1506.                 previewOverlay.setAttribute("height", pHeight);
  1507.                 var pX = (oriWidth - pWidth) / 2;
  1508.                 var pY = (oriHeight - pHeight) / 2;
  1509.                 previewOverlay.style.left = pX + "px";
  1510.                 previewOverlay.style.top = pY + "px";
  1511.  
  1512.                 previewContainer.appendChild(previewOverlay);
  1513.             }
  1514.         }
  1515.  
  1516.         previewContainer.appendChild(preview);
  1517.         return previewContainer;
  1518.     };
  1519.  
  1520.  
  1521.     var buildJNLPFileName = function(isOffline) {
  1522.         var version = parseFloat(javaCodebaseVersion);
  1523.         var filename = "applet" + version*10 + "_";
  1524.         if (isOffline) {
  1525.             filename += "local";
  1526.         } else {
  1527.             filename += "web";
  1528.         }
  1529.         if (views.is3D) {
  1530.             filename += "_3D";
  1531.         }
  1532.         filename += ".jnlp";
  1533.         return filename;
  1534.     };
  1535.  
  1536.  
  1537.     /**
  1538.      * Detects the type of the applet (java or html5).
  1539.      * If a fixed type is passed in preferredType (java or html5), this type is forced.
  1540.      * Otherwise the method tries to find out which types are supported by the system.
  1541.      * If a preferredType is passed, this type is used if it is supported.
  1542.      * If auto is passed, the preferred type is html5 for versions >= 4.4 and java for all versions < 4.4.
  1543.      * @param preferredType can be 'preferJava', 'preferHTML5', 'java', 'html5', 'auto' or 'screenshot'. Default='auto'
  1544.      */
  1545.     var detectAppletType = function(preferredType) {
  1546.         preferredType = preferredType.toLowerCase();
  1547.         if ((preferredType === "java") || (preferredType === "html5") || (preferredType === "screenshot") || (preferredType === "compiled")) {
  1548.             return preferredType;
  1549.         }
  1550.  
  1551.         if (preferredType === "preferjava") {
  1552.             if (applet.isJavaInstalled()) {
  1553.                 return "java";
  1554.             } else {
  1555.                 return "html5";
  1556.             }
  1557.         } else if (preferredType === "preferhtml5") {
  1558.             if (applet.isHTML5Installed()) {
  1559.                 return "html5";
  1560.             } else {
  1561.                 return "java";
  1562.             }
  1563.         } else if ((preferredType === "prefercompiled") && (preCompiledScriptPath !== null)) {
  1564.             if (applet.isCompiledInstalled()) {
  1565.                 return "compiled";
  1566.             } else {
  1567.                 return "java";
  1568.             }
  1569.         } else {
  1570.             // type=auto
  1571.             if ((applet.isJavaInstalled()) &&
  1572.                 (!applet.isHTML5Installed())) {
  1573.                 return "java";
  1574.             } else {
  1575.                 return "html5";
  1576.             }
  1577.         }
  1578.     };
  1579.  
  1580.     var getIEVersion = function() {
  1581.         var a=navigator.appVersion;
  1582.         if (a.indexOf("Trident/7.0") > 0) {
  1583.             return 11;
  1584.         } else {
  1585.             return a.indexOf('MSIE')+1?parseFloat(a.split('MSIE')[1]):999;
  1586.         }
  1587.     };
  1588.  
  1589.     var isInternetExplorer = function() {
  1590.         return (getIEVersion() !== 999);
  1591.     };
  1592.  
  1593.  
  1594.     var modules = ["web", "webSimple", "web3d", "tablet", "tablet3d", "phone"];
  1595.     /**
  1596.      * @param version Can be: 3.2, 4.0, 4.2, 4.4, 5.0, test, test42, test44, test50
  1597.      */
  1598.     var setDefaultHTML5CodebaseForVersion = function(version, offline) {
  1599.         html5CodebaseVersion = version;
  1600.         if (offline) {
  1601.             setHTML5CodebaseInternal(html5CodebaseVersion, true);
  1602.             return;
  1603.         }
  1604.  
  1605.         // Set the codebase URL for the version
  1606.         var hasWebSimple = ! html5NoWebSimple;
  1607.         if (hasWebSimple) {
  1608.             var v = parseVersion(html5CodebaseVersion);
  1609.             if ((!isNaN(v) && v < 4.4)) {
  1610.                 hasWebSimple = false;
  1611.             }
  1612.         }
  1613.  
  1614.         var protocol,
  1615.             codebase;
  1616.         if (window.location.protocol.substr(0,4) === 'http') {
  1617.             protocol = window.location.protocol;
  1618.         } else {
  1619.             protocol = 'http:';
  1620.         }
  1621.         var index = html5CodebaseVersion.indexOf("//");
  1622.         if (index > 0) {
  1623.             codebase = html5CodebaseVersion;
  1624.         } else if(index === 0) {
  1625.             codebase = protocol + html5CodebaseVersion;
  1626.         } else {
  1627.             //codebase = "https://cdn.geogebra.org/apps/"+latestVersion+"/";
  1628.             codebase = getTubeURL();
  1629.         }
  1630.  
  1631.         for(var key in modules){
  1632.             if (html5CodebaseVersion.slice(modules[key].length*-1) === modules[key] ||
  1633.                 html5CodebaseVersion.slice((modules[key].length+1)*-1) === modules[key]+"/") {
  1634.                 setHTML5CodebaseInternal(codebase, false);
  1635.                 return;
  1636.             }
  1637.         }
  1638.  
  1639.         // Decide if web, websimple or web3d should be used
  1640.         if (!GGBAppletUtils.isFlexibleWorksheetEditor() && hasWebSimple && !views.is3D && !views.AV && !views.SV && !views.CV && !views.EV2 && !views.CP && !views.PC && !views.DA && !views.FI && !views.PV &&
  1641.             !valBoolean(parameters.showToolBar) && !valBoolean(parameters.showMenuBar) && !valBoolean(parameters.showAlgebraInput) && !valBoolean(parameters.enableRightClick)) {
  1642.             codebase += 'webSimple/';
  1643.         } else {
  1644.             codebase += 'web3d/';
  1645.         }
  1646.  
  1647.         setHTML5CodebaseInternal(codebase, false);
  1648.     };
  1649.  
  1650.     var setHTML5CodebaseInternal = function(codebase, offline) {
  1651.         if (codebase.slice(-1) !== '/') {
  1652.             codebase += '/';
  1653.         }
  1654.         html5Codebase = codebase;
  1655.  
  1656.         if (offline === null) {
  1657.             offline = (codebase.indexOf("http") === -1);
  1658.         }
  1659.         isHTML5Offline = offline;
  1660.  
  1661.         // Set the scriptname (web or webSimple)
  1662.         html5CodebaseScript = "web.nocache.js";
  1663.         html5CodebaseIsWebSimple = false;
  1664.         var folders = html5Codebase.split("/");
  1665.         if (folders.length > 1) {
  1666.             if (! offline && folders[folders.length-2] === 'webSimple') {  // Currently we don't use webSimple for offline worksheets
  1667.                 html5CodebaseScript = "webSimple.nocache.js";
  1668.                 html5CodebaseIsWebSimple = true;
  1669.             } else if (modules.indexOf(folders[folders.length-2]) >= 0) {
  1670.                 html5CodebaseScript = folders[folders.length-2] + ".nocache.js";
  1671.             }
  1672.         }
  1673.  
  1674.         // Extract the version from the codebase folder
  1675.         folders = codebase.split('/');
  1676.         html5CodebaseVersion = folders[folders.length-3];
  1677.         if (html5CodebaseVersion.substr(0,4) === 'test') {
  1678.             html5CodebaseVersion = html5CodebaseVersion.substr(4,1) + '.' + html5CodebaseVersion.substr(5,1);
  1679.         } else if (html5CodebaseVersion.substr(0,3) === 'war' || html5CodebaseVersion.substr(0,4) === 'beta') {
  1680.             html5CodebaseVersion = '5.0';
  1681.         }
  1682.     };
  1683.  
  1684.     var setDefaultJavaCodebaseForVersion = function(version) {
  1685.  
  1686.         // There are no test versions for java. So when test is passed, it will be converted to the normal codebase
  1687.         if (version === "test32") {
  1688.             javaCodebaseVersion = "3.2";
  1689.         } else if (version === "test40") {
  1690.             javaCodebaseVersion = "4.0";
  1691.         } else if (version === "test42") {
  1692.             javaCodebaseVersion = "4.2";
  1693.         } else if (version === "test50") {
  1694.             javaCodebaseVersion = "5.0";
  1695.         } else if (version === "test") {
  1696.             javaCodebaseVersion = ggbVersion;
  1697.         } else {
  1698.             javaCodebaseVersion = version;
  1699.         }
  1700.  
  1701.         // For versions below 4.0 the java codebase of version 4.0 is used.
  1702.         if (parseVersion(javaCodebaseVersion)<4.0) {
  1703.             javaCodebaseVersion = "4.0";
  1704.         }
  1705.  
  1706.         var protocol;
  1707.         if (window.location.protocol.substr(0,4) === 'http') {
  1708.             protocol = window.location.protocol;
  1709.         } else {
  1710.             protocol = 'http:';
  1711.         }
  1712.         var codebase = protocol+"//jars.geogebra.org/webstart/" + javaCodebaseVersion + '/';
  1713.         if (javaCodebaseVersion === '4.0' || javaCodebaseVersion === '4.2') {
  1714.             codebase += 'jnlp/';
  1715.         }
  1716.  
  1717.         applet.setJNLPBaseDir('https://www.geogebra.org/webstart/');
  1718.  
  1719.         doSetJavaCodebase(codebase, false);
  1720.     };
  1721.  
  1722.     var log = function(text, parameters) {
  1723.         if ( window.console && window.console.log ) {
  1724.             if(!parameters || (typeof parameters.showLogging === 'undefined') ||
  1725.                 (parameters.showLogging && parameters.showLogging !== "false")) {
  1726.                     console.log(text);
  1727.             }
  1728.         }
  1729.     };
  1730.  
  1731.     // Read the material parameters from the tube API, if a material_id was passed
  1732.     if (parameters.material_id !== undefined) {
  1733.         fetchParametersFromTube(continueInit);
  1734.     } else {
  1735.         continueInit();
  1736.     }
  1737.  
  1738.     function continueInit() {
  1739.         var html5Version = ggbVersion;
  1740.         if (html5OverwrittenCodebaseVersion !== null) {
  1741.             html5Version = html5OverwrittenCodebaseVersion;
  1742.         } else {
  1743.             if (parseFloat(html5Version) < 5.0) { // Use 5.0 as default for html5. Change the version number here, when a new stable version is released.
  1744.                 html5Version = "5.0";
  1745.             }
  1746.         }
  1747.  
  1748.         // Initialize the codebase with the default URLs
  1749.         setDefaultHTML5CodebaseForVersion(html5Version, false);
  1750.         setDefaultJavaCodebaseForVersion(ggbVersion); // For java we always use the version of the file per default.
  1751.  
  1752.         if (html5OverwrittenCodebase !== null) {
  1753.             setHTML5CodebaseInternal(html5OverwrittenCodebase, isHTML5Offline);
  1754.         }
  1755.         initComplete = true;
  1756.     }
  1757.  
  1758.     return applet;
  1759. };
  1760.  
  1761. var GGBAppletUtils = (function() {
  1762.     "use strict";
  1763.  
  1764.     function isFlexibleWorksheetEditor() {
  1765.         return (window.GGBT_wsf_edit !== undefined);
  1766.     }
  1767.  
  1768.     function getWidthHeight(appletElem, appletWidth, allowUpscale, noBorder) {
  1769.         // Find the container class
  1770.         var container = null;
  1771.  
  1772.         var myWidth = 0, myHeight = 0, windowWidth = 0, border = 0, borderRight = 0, borderLeft = 0, borderTop = 0;
  1773.  
  1774.         if (container) {
  1775.             myWidth = container.offsetWidth;
  1776.             myHeight = container.offsetWidth;
  1777.         } else {
  1778.             if (window.innerWidth && document.documentElement.clientWidth) {
  1779.                 myWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
  1780.                 myHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
  1781.                 // Using mywith instead of innerWidth because after rotating a mobile device the innerWidth is sometimes wrong (e.g. on Galaxy Note III)
  1782.                 // windowWidth = window.innerWidth
  1783.                 windowWidth = myWidth;
  1784.             } else if (typeof( window.innerWidth ) === 'number') {
  1785.                 //Non-IE
  1786.                 myWidth = window.innerWidth;
  1787.                 myHeight = window.innerHeight;
  1788.                 windowWidth = window.innerWidth;
  1789.             } else if (document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight )) {
  1790.                 //IE 6+ in 'standards compliant mode'
  1791.                 myWidth = document.documentElement.clientWidth;
  1792.                 myHeight = document.documentElement.clientHeight;
  1793.                 windowWidth = document.documentElement.clientWidth;
  1794.             } else if (document.body && ( document.body.clientWidth || document.body.clientHeight )) {
  1795.                 //IE 4 compatible
  1796.                 myWidth = document.body.clientWidth;
  1797.                 myHeight = document.body.clientHeight;
  1798.                 windowWidth = document.documentElement.clientWidth;
  1799.             }
  1800.  
  1801.             if (appletElem) {
  1802.                 var rect = appletElem.getBoundingClientRect();
  1803.                 if (rect.left > 0) {
  1804.                     if (rect.left <= myWidth && (noBorder === undefined || !noBorder)) {
  1805.                         if (document.dir === 'rtl') {
  1806.                             borderRight = myWidth - rect.width - rect.left;
  1807.                             borderLeft = (windowWidth <= 480 ? 10 : 30);
  1808.                         } else {
  1809.                             borderLeft = rect.left;
  1810.                             borderRight = (windowWidth <= 480 ? 10 : 30);
  1811.                         }
  1812.                         border = borderLeft + borderRight;
  1813.                     }
  1814.                 }
  1815.             }
  1816.  
  1817.             // overwrite borders with other numbers if it is in fullscreen mode
  1818.             // make sure X is visible all the time
  1819.             if(appletElem && typeof window.GGBT_wsf_view === "object" && window.GGBT_wsf_view.isFullscreen()) {
  1820.                 // APPLET IS DISPLAYED IN FULLSCREEN
  1821.                 var appletRect = appletElem.getBoundingClientRect();
  1822.  
  1823.                 // X is positioned to the right/left
  1824.                 // set a border so it is visible
  1825.                 if(window.GGBT_wsf_view.getCloseBtnPosition() === 'closePositionRight') {
  1826.                     // X is positioned to the right/left
  1827.                     // 40 is the width of the X close button
  1828.                     border = 40;
  1829.                     borderTop = 0;
  1830.                 } else if(window.GGBT_wsf_view.getCloseBtnPosition() === 'closePositionTop') {
  1831.                     // X is positioned on top
  1832.                     border = 0;
  1833.                     borderTop = 40;
  1834.                 }
  1835.             }
  1836.         }
  1837.  
  1838.         //console.log('myWidth: '+ myWidth);
  1839.         //console.log('myHeight: ' + myHeight);
  1840.         //console.log('border: ' + border);
  1841.         //console.log('borderTop: '+ borderTop);
  1842.  
  1843.         if (appletElem) {
  1844.             if ((allowUpscale === undefined || !allowUpscale) && appletWidth > 0 && appletWidth + border < myWidth) {
  1845.                 myWidth = appletWidth;
  1846.             } else {
  1847.                 myWidth -= border;
  1848.             }
  1849.  
  1850.             if(typeof window.GGBT_wsf_view === "object" && window.GGBT_wsf_view.isFullscreen() && (allowUpscale === undefined || !allowUpscale)) {
  1851.                 // applet is displayed in fullscreen
  1852.                 myHeight -= borderTop;
  1853.             }
  1854.         }
  1855.  
  1856.         //console.log('myWidth: ' + myWidth + ', myHeight: ' + myHeight);
  1857.  
  1858.         return {width: myWidth, height: myHeight};
  1859.     }
  1860.  
  1861.     function calcScale(parameters, appletElem, allowUpscale, showPlayButton){
  1862.         if (parameters.isScreenshoGenerator) {
  1863.             return 1;
  1864.         }
  1865.         var ignoreHeight = (showPlayButton !== undefined && showPlayButton);
  1866.         var windowSize = getWidthHeight(appletElem, parameters.width, allowUpscale, ignoreHeight && window.GGBT_wsf_view);
  1867.         var windowWidth = parseInt(windowSize.width);
  1868.  
  1869.         var appletWidth = parameters.width;
  1870.         var appletHeight = parameters.height;
  1871.         if (appletWidth === undefined) {
  1872.             var articles = appletElem.getElementsByTagName('article');
  1873.             if (articles.length === 1) {
  1874.                 appletWidth = articles[0].offsetWidth;
  1875.                 appletHeight = articles[0].offsetHeight;
  1876.             }
  1877.         }
  1878.  
  1879.         var xscale = windowWidth / appletWidth;
  1880.         var yscale = (ignoreHeight ? 1 : windowSize.height / appletHeight);
  1881.         if (allowUpscale !== undefined && !allowUpscale) {
  1882.             xscale = Math.min(1, xscale);
  1883.             yscale = Math.min(1, yscale);
  1884.         }
  1885.  
  1886.         return Math.min(xscale, yscale);
  1887.     }
  1888.  
  1889.     function getScale(parameters, appletElem, showPlayButton) {
  1890.         var scale = 1,
  1891.             autoScale,
  1892.             allowUpscale = false;
  1893.  
  1894.         if (parameters.hasOwnProperty('allowUpscale')) {
  1895.             allowUpscale = parameters.allowUpscale;
  1896.         }
  1897.  
  1898.         if (parameters.hasOwnProperty('scale')) {
  1899.             scale = parseFloat(parameters.scale);
  1900.             if (isNaN(scale) || scale === null || scale === 0) {
  1901.                 scale = 1;
  1902.             }
  1903.             if (scale > 1) {
  1904.                 allowUpscale = true;
  1905.             }
  1906.         }
  1907.  
  1908.         if(appletElem && typeof window.GGBT_wsf_view === "object" && window.GGBT_wsf_view.isFullscreen()) {
  1909.             allowUpscale = true;
  1910.         }
  1911.  
  1912.         if (!isFlexibleWorksheetEditor() && !(parameters.hasOwnProperty('disableAutoScale') && parameters.disableAutoScale)) {
  1913.             autoScale = calcScale(parameters, appletElem, allowUpscale, showPlayButton);
  1914.         } else {
  1915.             return scale;
  1916.         }
  1917.  
  1918.         if (allowUpscale && (!parameters.hasOwnProperty('scale') || scale === 1)) {
  1919.             return autoScale;
  1920.         } else {
  1921.             return Math.min(scale, autoScale);
  1922.         }
  1923.     }
  1924.  
  1925.     /**
  1926.      * Positiones the applet in the center of the screen
  1927.      * Used for fullscreen popups
  1928.      * @param appletElem
  1929.      */
  1930.     function positionCenter(appletElem) {
  1931.         var windowWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
  1932.         var windowHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
  1933.         var appletRect = appletElem.getBoundingClientRect();
  1934.  
  1935.         var calcHorizontalBorder = (windowWidth - appletRect.width) / 2;
  1936.         var calcVerticalBorder = (windowHeight - appletRect.height) / 2;
  1937.  
  1938.         if(calcVerticalBorder < 0) {
  1939.             calcVerticalBorder = 0;
  1940.         }
  1941.  
  1942.         appletElem.style.position = "relative";
  1943.  
  1944.         if(window.GGBT_wsf_view.getCloseBtnPosition() === 'closePositionRight') {
  1945.             // X is positioned to the right/left
  1946.  
  1947.             if(calcHorizontalBorder < 40) {
  1948.                 // if there is not enough space left for the X, don't position it in the center
  1949.                 appletElem.style.left = '40px';
  1950.             } else {
  1951.                 appletElem.style.left = calcHorizontalBorder + 'px';
  1952.             }
  1953.             appletElem.style.top = calcVerticalBorder + 'px';
  1954.  
  1955.         } else if(window.GGBT_wsf_view.getCloseBtnPosition() === 'closePositionTop') {
  1956.             // X is positioned on top
  1957.  
  1958.             if(calcVerticalBorder < 40) {
  1959.                 // if there is not enough space left for the X, don't position it in the center
  1960.                 appletElem.style.top = '40px';
  1961.             } else {
  1962.                 appletElem.style.top = calcVerticalBorder + 'px';
  1963.             }
  1964.  
  1965.             appletElem.style.left = calcHorizontalBorder + 'px';
  1966.         }
  1967.     }
  1968.  
  1969.     function responsiveResize(appletElem, parameters) {
  1970.         var article = appletElem.getElementsByTagName("article")[0];
  1971.  
  1972.         if (article) {
  1973.             if (typeof window.GGBT_wsf_view === "object" && window.GGBT_wsf_view.isFullscreen()) {
  1974.                 var articles = appletElem.getElementsByTagName("article");
  1975.                 if (articles.length > 0 && parameters.id !== articles[0].getAttribute("data-param-id")) {
  1976.                     return;
  1977.                 }
  1978.  
  1979.                 window.GGBT_wsf_view.setCloseBtnPosition(appletElem);
  1980.             }
  1981.  
  1982.             var scale = getScale(parameters, appletElem);
  1983.  
  1984.             article.removeAttribute("data-param-scale");
  1985.             article.setAttribute("data-scalex", scale);
  1986.             article.setAttribute("data-scaley", scale);
  1987.             if (isFlexibleWorksheetEditor()) {
  1988.                 article.setAttribute("data-param-scale", scale);
  1989.             }
  1990.  
  1991.             var scaleElem = null;
  1992.             for (var i = 0; i < appletElem.childNodes.length; i++) {
  1993.                 if (appletElem.childNodes[i].className === "applet_scaler") {
  1994.                     scaleElem = appletElem.childNodes[i];
  1995.                     break;
  1996.                 }
  1997.             }
  1998.  
  1999.             if (scaleElem !== null) {
  2000.                 scaleElem.style.transformOrigin = "0% 0% 0px";
  2001.                 scaleElem.parentNode.style.transform = "";
  2002.                 if (!isNaN(scale) && scale !== 1) {
  2003.                     // Set the scale factor for the applet
  2004.                     scaleElem.style.transform = "scale(" + scale + "," + scale + ")";
  2005.                     scaleElem.parentNode.style.width = (parameters.width * scale) + 'px';
  2006.                     scaleElem.parentNode.style.height = (parameters.height * scale) + 'px';
  2007.  
  2008.                 } else {
  2009.                     // Remove scaling
  2010.                     scaleElem.style.transform = "none";
  2011.                     scaleElem.parentNode.style.width = (parameters.width) + 'px';
  2012.                     scaleElem.parentNode.style.height = (parameters.height) + 'px';
  2013.                 }
  2014.             }
  2015.  
  2016.             // positions the applet in the center of the popup
  2017.             if (typeof window.GGBT_wsf_view === 'object' && window.GGBT_wsf_view.isFullscreen()) {
  2018.                 positionCenter(appletElem);
  2019.             }
  2020.  
  2021.             var appName = (parameters.id !== undefined ? parameters.id : "ggbApplet");
  2022.             var app = window[appName];
  2023.             if (app !== undefined && app !== null && typeof app.recalculateEnvironments === "function") {
  2024.                 app.recalculateEnvironments();
  2025.             }
  2026.  
  2027.             if (window.GGBT_wsf_view && !window.GGBT_wsf_view.isFullscreen()) {
  2028.                 window.GGBT_wsf_general.adjustContentToResize($(article).parents('.content-added-content'));
  2029.             }
  2030.         }
  2031.     }
  2032.  
  2033.     return {
  2034.         responsiveResize: responsiveResize,
  2035.         isFlexibleWorksheetEditor: isFlexibleWorksheetEditor,
  2036.         positionCenter: positionCenter,
  2037.         getScale: getScale
  2038.     };
  2039. })();
  2040.