1 /*
  2  * ilib-web.js - glue code for web apps to load local ilib code and data
  3  * using XHR
  4  * 
  5  * Copyright © 2015, JEDLSoft
  6  *
  7  * Licensed under the Apache License, Version 2.0 (the "License");
  8  * you may not use this file except in compliance with the License.
  9  * You may obtain a copy of the License at
 10  *
 11  *     http://www.apache.org/licenses/LICENSE-2.0
 12  *
 13  * Unless required by applicable law or agreed to in writing, software
 14  * distributed under the License is distributed on an "AS IS" BASIS,
 15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  *
 17  * See the License for the specific language governing permissions and
 18  * limitations under the License.
 19  */
 20 
 21 var path = {
 22     dirname: function(pathname) {
 23         var i = pathname.lastIndexOf("/");
 24         return i !== -1 ? pathname.substring(0,i) : pathname;
 25     },
 26 
 27     join: function() {
 28         var arr = [];
 29         for (var i = 0; i < arguments.length; i++) {
 30             arr.push(arguments[i]);
 31         }
 32         return arr.join("/");
 33     },
 34 
 35     normalize: function(pathname) {
 36         if (pathname) {
 37             var previousLen;
 38             do {
 39                 previousLen = pathname.length;
 40                 pathname = pathname.replace(/\/\.\//g, "/").replace(/\/[^/]+[^\.]\/\.\./g, "").replace(/^\.\//, "").replace(/\/\//g, "/");
 41             } while (pathname.length < previousLen);
 42         }
 43         return pathname;
 44     }
 45 };
 46 
 47 
 48 var requireClass = function() {
 49     this.cache = {};
 50     this.loading = {};
 51     this.updateRequire = /\brequire\s*\(\s*"([^/][^"+]*)"/g;
 52 
 53     var pos;
 54     var scripts = document.getElementsByTagName("script");
 55 
 56     this.protocol = "file://";
 57     this.root = ".";
 58 
 59     for (var i = 0; i < scripts.length; i++) {
 60         var source = scripts[i].src;
 61 
 62         if (navigator && navigator.userAgent && (navigator.userAgent.indexOf(" .NET") > -1) ){
 63             // IE brower
 64             var colon = source.indexOf('://');
 65             this.protocol = source.substring(0, colon+3);
 66             this.root = source.substring(colon+3, pos-1);
 67             if (this.root.indexOf("/") !== 0) {
 68                 this.root = "/" + this.root;
 69             }
 70             break;
 71         } else {
 72             if (source && (pos = source.search(/ilib-web\.js$/)) !== -1) {
 73                 var url = new URL(source);
 74                 this.protocol = url.protocol + "//";
 75                 this.root = url.pathname;
 76                 break;
 77             }
 78         }
 79     }
 80 };
 81 
 82 requireClass.prototype.loadFile = function(pathname) {
 83     // special case for IE because it has a @#$%ed up XMLHttpRequest implementation
 84     var req = (navigator.userAgent.indexOf(" .NET") > -1) ? 
 85         new ActiveXObject("MSXML2.XMLHTTP") :
 86         new XMLHttpRequest();
 87 
 88     req.open("GET", this.protocol + pathname, false);
 89     req.send();
 90 
 91     return req.responseText;
 92 };
 93 
 94 requireClass.prototype.require = function(pathname) {
 95     
 96     //console.log("this.root is " + this.root + " and pathname before was " + pathname);
 97     
 98     if (pathname.charAt(0) !== '/') {
 99         // make the current path be relative to the parent's path, otherwise use the root
100         pathname = path.join((module && module.filename) ? path.dirname(module.filename) : this.root, pathname);
101     }
102 
103     pathname = path.normalize(pathname);
104 
105     if (this.cache[pathname]) {
106         return this.cache[pathname];
107     }
108 
109     // don't try to load things that are currently in the process of loading
110     if (this.loading[pathname]) {
111         //console.log("require: already loading...");
112         return {};
113     }
114 
115     //console.log("loading module " + pathname);
116 
117     this.loading[pathname] = true;
118 
119     var text = this.loadFile(pathname);
120     var dirname = path.dirname(pathname);
121     var match, replacement;
122     
123     if (text) {
124         var tmp = module.filename;
125         module.filename = pathname;
126         module.exports = null;
127         module.require = requireClass.prototype.require.bind(r);
128         
129         while ((match = this.updateRequire.exec(text)) !== null) {
130             replacement = path.normalize(path.join(dirname, match[1]));
131             text = text.replace(new RegExp('"' + match[1] + '"', "g"), '"' + replacement + '"');
132             this.updateRequire.lastIndex = match.index + replacement.length + 2;
133         }
134         // for debugging in chrome with nice file names instead of random ids like "VM (2342)"
135         text = text + "\n//# sourceURL=" + pathname + "\n";
136 
137         // console.log("text is " + text);
138         try {
139             eval(text);
140 
141             this.cache[pathname] = module.exports;
142         } finally {
143             this.loading[pathname] = undefined;
144             module.filename = tmp;
145         }
146 
147         return module.exports;
148     }
149 
150     return undefined;
151 };
152 
153 if (typeof(window.module) === 'undefined') {
154     window.module = {
155         exports: {},
156         filename: null
157     };
158 }
159 
160 var r = new requireClass();
161 var require = requireClass.prototype.require.bind(r);
162 
163 var WebLoader = require("../lib/WebLoader.js");
164 
165 var ilib = require("../lib/ilib.js");
166 ilib.setLoaderCallback(new WebLoader(ilib));
167 
168 ilib._dyncode = true; // indicate that we are using dynamically loaded code
169 ilib._dyndata = true;