mox.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /**
  2. * $Id: TinyMCE_DOMUtils.class.js 91 2006-10-02 14:53:22Z spocke $
  3. *
  4. * @author Moxiecode
  5. * @copyright Copyright © 2004-2006, Moxiecode Systems AB, All rights reserved.
  6. */
  7. /**#@+
  8. * @class This is the core class for the Moxiecode API. It handles core problems like
  9. * creating new classes and instances and also console logging to the devkit.
  10. * @member moxiecode
  11. * @static
  12. */
  13. var mox = {
  14. /**#@+
  15. * @field
  16. */
  17. /**
  18. * State true/false if DOMContentLoaded has been fired or not.
  19. */
  20. contentLoaded : false,
  21. /**
  22. * Class load que, this gets filled when pending scripts/classes are loaded.
  23. */
  24. que : [],
  25. /**
  26. * Class lookup array with states 1 is loading, 2 is finished loading.
  27. */
  28. classes : {},
  29. /**
  30. * Constant if the current browser is Opera or not.
  31. *
  32. * @type bool
  33. */
  34. isOpera : (/Opera/gi).test(navigator.userAgent),
  35. /**
  36. * Constant if the current browser is Safari or not.
  37. *
  38. * @type bool
  39. */
  40. isSafari : (/Safari|KHTML|Konqueror/gi).test(navigator.userAgent),
  41. /**
  42. * Constant if the current browser is Gecko/Firefox/Mozilla or not.
  43. *
  44. * @type bool
  45. */
  46. isGecko : !(/Safari|KHTML|Konqueror/gi).test(navigator.userAgent) && (/Gecko/gi).test(navigator.userAgent),
  47. /**
  48. * Constant if the current browser is Microsoft Internet Explorer or not.
  49. *
  50. * @type bool
  51. */
  52. isIE : (/MSIE/gi).test(navigator.userAgent) && (/Explorer/gi).test(navigator.appName),
  53. /**
  54. * Base URL where the API is located.
  55. */
  56. baseURL : '',
  57. /**#@+
  58. * @method
  59. */
  60. /**
  61. * Creates a new class by the specified name, this method will create the namespace
  62. * for the class and assign the methods specified to the new class object. It also
  63. * supports inheritage and the creation of purly static classes.
  64. *
  65. * @param {string} s Class name to create and possible classes to inherit and if it should be static.
  66. * @param {object} p Proprotype name/value object containing methods that the new class should include.
  67. */
  68. create : function(s, p) {
  69. var st, cp, bp, co, cn, bcn, m, pm, sn, n, t = this;
  70. // Parse static and split class and base class
  71. st = /static\s+/.test(s);
  72. s = s.replace(/(static)\s+/, '');
  73. s = s.replace(/\s+/, '').split(':');
  74. // Setup base prototype and constructor
  75. bcn = this.getClassName(s[1]);
  76. cn = this.getClassName(s[0]);
  77. co = p[cn];
  78. // Require base class if needed
  79. this.require(s[1], function() {
  80. if (bcn)
  81. bp = t.getClass(s[1]).prototype;
  82. // Add pass through constructor
  83. if (!co) {
  84. co = p[cn] = function() {
  85. if (bp)
  86. bp[bcn].apply(this, arguments);
  87. };
  88. }
  89. // Inherit constructor
  90. if (bp) {
  91. t._inherit(bp, p, bcn, cn);
  92. co = p[cn];
  93. }
  94. // Get class prototype
  95. cp = co.prototype;
  96. // Add base methods
  97. if (bp) {
  98. for (n in bp)
  99. cp[n] = bp[n];
  100. }
  101. // Add class methods
  102. for (n in p) {
  103. // Handle static members
  104. if (n == 'static') {
  105. for (sn in p[n])
  106. co[sn] = p[n][sn];
  107. } else {
  108. if (bp && bp[n])
  109. t._inherit(bp, p, n, n);
  110. cp[n] = p[n];
  111. }
  112. }
  113. // Add class to namespace
  114. t.getClass(s[0], st ? new co() : co);
  115. t.provide(s[0]);
  116. });
  117. },
  118. /**
  119. * Returs a class by name, this will resolve the namespaces in a string and look for the class this
  120. * method can also be used to add new classes to the API. It has this dual functionality to
  121. * reduce script size.
  122. *
  123. * @param {string} s Class name to look for, for example mox.somepackage.someclass.
  124. * @param {function} cl Optional class to add to the API.
  125. * @return {function} Function reference to the specified class or null if it wasn't found.
  126. */
  127. getClass : function(s, cl) {
  128. var i, l, n, c;
  129. for (i=0, s = s.split('.'), l=s.length, c = window; i<l; i++) {
  130. n = s[i];
  131. if (i == l - 1) {
  132. if (cl)
  133. c[n] = cl;
  134. return c[n];
  135. }
  136. c = !c[n] ? (c[n] = {}) : c[n];
  137. }
  138. return null;
  139. },
  140. /**
  141. * Returns the class name/last portion of a namespaced class string.
  142. *
  143. * @param {string} s Namespaced input string for example: mox.somepackage.SomeClass.
  144. * @return {string} Last portion of namespaced string for example: SomeClass.
  145. */
  146. getClassName : function(s) {
  147. return !s ? '' : s.match(/(^|\.)([a-z0-9_]+)$/i)[2];
  148. },
  149. /**
  150. * Logs a message to devkit if it's enabled.
  151. *
  152. * @param {mixed} 1..n Unlimited number of arguments to log as a message to devkit console window.
  153. */
  154. log : function() {
  155. var d = mox.devkit, c = window.console, a = arguments;
  156. // Log to devkit
  157. if (d)
  158. d.DevKit.log.apply(d.DevKit, a);
  159. // Log to firebug
  160. if (c && c.debug && !this.isSafari)
  161. c.debug(a.length == 1 ? a[0] : a);
  162. },
  163. /**
  164. * Binds a function to a specific scope, this is useful for event methods so that they are bound
  165. * to the correct class scope.
  166. *
  167. * @param {object} s Scope reference to bind function to.
  168. * @param {function} f Function to execute in the specified scope.
  169. * @return {function} Scope bound function object.
  170. */
  171. bind : function(s, f) {
  172. return typeof(f) == 'function' ? function() {
  173. return f.apply(s, arguments);
  174. } : null;
  175. },
  176. /**
  177. * Sets up the baseURL of the moxiecode API by searching for the specified key.
  178. *
  179. * @param {string} k key to search for.
  180. * @return {string} Base URL for the API or null if it wasn't found.
  181. */
  182. findBaseURL : function(k) {
  183. var i, nl = document.getElementsByTagName('script'), n;
  184. for (i=0; i<nl.length; i++) {
  185. n = nl[i];
  186. if (n.src && k.test(n.src))
  187. return this.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
  188. }
  189. return null;
  190. },
  191. /**
  192. * Imports/loads the specified classes(s). This method will not load the same class twice.
  193. *
  194. * @param {string/Array} f Array or string containting full class name to load.
  195. * @param {function} cb Optional callback to execute ones the specified classes are loaded.
  196. */
  197. require : function(f, cb) {
  198. var i, o = [];
  199. if (!f) {
  200. if (cb)
  201. cb();
  202. return;
  203. }
  204. if (typeof(f) == 'string')
  205. f = [f];
  206. for (i=0; i<f.length; i++) {
  207. if (!this.getClass(f[i]))
  208. o.push(f[i]);
  209. }
  210. if (cb) {
  211. if (o.length == 0)
  212. cb();
  213. else
  214. this.que.push({classes : o, count : 0, callback : cb});
  215. }
  216. this.loadClasses(o);
  217. },
  218. /**
  219. * Tells the loading que that a class has been loaded. This will trigger callback functions ones
  220. * specific classes get loaded.
  221. *
  222. * @param {string} c Class that got loaded for example mox.DOM.
  223. */
  224. provide : function(c) {
  225. var i, y, q, cl, cb = [];
  226. if (this.classes[c] > 1)
  227. return;
  228. this.classes[c] = 2;
  229. for (i=0, q = this.que; i<q.length; i++) {
  230. if (q[i]) {
  231. for (y=0, cl = q[i].classes; y<cl.length; y++) {
  232. if (cl[y] == c)
  233. q[i].count++;
  234. }
  235. if (q[i].count >= q[i].classes.length) {
  236. cb.push(q[i].callback);
  237. q[i] = null;
  238. }
  239. }
  240. }
  241. for (i=0; i<cb.length; i++)
  242. cb[i]();
  243. },
  244. /**
  245. * Loads a specific class asynchrous by adding it to the head element.
  246. *
  247. * @param {string} c Class name to load.
  248. */
  249. loadClasses : function(cl) {
  250. var d = document, s, i, c;
  251. for (i=0; i<cl.length; i++) {
  252. c = cl[i];
  253. if (this.classes[c] > 0)
  254. continue;
  255. this.classes[c] = 1;
  256. s = d.createElement('script');
  257. s.setAttribute('type', 'text/javascript');
  258. s.setAttribute('src', this.baseURL + '/' + c.toLowerCase().replace(/\./g, '/') + '.js');
  259. d.getElementsByTagName('head')[0].appendChild(s);
  260. }
  261. },
  262. // Private method
  263. _inherit : function(bp, p, bn, n) {
  264. var m = p[n], pm = bp[bn];
  265. p[n] = function() {
  266. // NOTE: Maybe restore parent after call
  267. this.parent = pm;
  268. return m.apply(this, arguments);
  269. };
  270. },
  271. _pageInit : function() {
  272. if (this.isIE && !/https/gi.test(document.location.protocol)) {
  273. document.write('<script id=__ie_onload defer src=javascript:void(0)><\/script>');
  274. document.getElementById("__ie_onload").onreadystatechange = mox._pageDone;
  275. }
  276. },
  277. _pageDone : function() {
  278. if (this.readyState == "complete")
  279. mox.contentLoaded = true;
  280. }
  281. /**#@-*/
  282. };
  283. // Set contentLoaded state
  284. if (mox.isGecko) {
  285. window.addEventListener('DOMContentLoaded', function() {
  286. mox.contentLoaded = true;
  287. }, false);
  288. };
  289. mox._pageInit();
  290. // Look for the API
  291. mox.findBaseURL(/mox\.js/);