ace-extra.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. if( !('ace' in window) ) window['ace'] = {}
  2. ace.config = {
  3. cookie_expiry : 604800, //1 week duration for saved settings
  4. cookie_path: '',
  5. storage_method: 2 //2 means use cookies, 1 means localStorage, 0 means localStorage if available otherwise cookies
  6. }
  7. if( !('vars' in window['ace']) ) window['ace'].vars = {}
  8. ace.vars['very_old_ie'] = !('querySelector' in document.documentElement);
  9. ace.settings = {
  10. is : function(item, status) {
  11. //such as ace.settings.is('navbar', 'fixed')
  12. return (ace.data.get('settings', item+'-'+status) == 1)
  13. },
  14. exists : function(item, status) {
  15. return (ace.data.get('settings', item+'-'+status) !== null)
  16. },
  17. set : function(item, status) {
  18. ace.data.set('settings', item+'-'+status, 1)
  19. },
  20. unset : function(item, status) {
  21. ace.data.set('settings', item+'-'+status, -1)
  22. },
  23. remove : function(item, status) {
  24. ace.data.remove('settings', item+'-'+status)
  25. },
  26. navbar_fixed : function(navbar, fix , save, chain) {
  27. if(ace.vars['very_old_ie']) return false;
  28. var navbar = navbar || '#navbar';
  29. if(typeof navbar === 'string') navbar = document.querySelector(navbar);
  30. if(!navbar) return false;
  31. fix = fix || false;
  32. save = save && true;
  33. if(!fix && chain !== false) {
  34. //unfix sidebar as well
  35. var sidebar = null;
  36. if(
  37. ace.settings.is('sidebar', 'fixed')
  38. ||
  39. ((sidebar = document.getElementById('sidebar')) && ace.hasClass(sidebar , 'sidebar-fixed'))
  40. )
  41. {
  42. ace.settings.sidebar_fixed(sidebar, false, save);
  43. }
  44. }
  45. if(fix) {
  46. if(!ace.hasClass(navbar , 'navbar-fixed-top')) ace.addClass(navbar , 'navbar-fixed-top');
  47. if(save !== false) ace.settings.set('navbar', 'fixed');
  48. } else {
  49. ace.removeClass(navbar , 'navbar-fixed-top');
  50. if(save !== false) ace.settings.unset('navbar', 'fixed');
  51. }
  52. try {
  53. document.getElementById('ace-settings-navbar').checked = fix;
  54. } catch(e) {}
  55. if(window.jQuery) jQuery(document).trigger('settings.ace', ['navbar_fixed' , fix , navbar]);
  56. },
  57. sidebar_fixed : function(sidebar, fix , save, chain) {
  58. if(ace.vars['very_old_ie']) return false;
  59. var sidebar = sidebar || '#sidebar';
  60. if(typeof sidebar === 'string') sidebar = document.querySelector(sidebar);
  61. if(!sidebar) return false;
  62. fix = fix || false;
  63. save = save && true;
  64. if(!fix && chain !== false) {
  65. //unfix breadcrumbs as well
  66. var breadcrumbs = null;
  67. if(
  68. ace.settings.is('breadcrumbs', 'fixed')
  69. ||
  70. ((breadcrumbs = document.getElementById('breadcrumbs')) && ace.hasClass(breadcrumbs , 'breadcrumbs-fixed'))
  71. )
  72. {
  73. ace.settings.breadcrumbs_fixed(breadcrumbs, false, save);
  74. }
  75. }
  76. if( fix && chain !== false && !ace.settings.is('navbar', 'fixed') ) {
  77. ace.settings.navbar_fixed(null, true, save);
  78. }
  79. if(fix) {
  80. if( !ace.hasClass(sidebar , 'sidebar-fixed') ) {
  81. ace.addClass(sidebar , 'sidebar-fixed');
  82. var toggler = document.getElementById('menu-toggler');
  83. if(toggler) ace.addClass(toggler , 'fixed');
  84. }
  85. if(save !== false) ace.settings.set('sidebar', 'fixed');
  86. } else {
  87. ace.removeClass(sidebar , 'sidebar-fixed');
  88. var toggler = document.getElementById('menu-toggler');
  89. if(toggler) ace.removeClass(toggler , 'fixed');
  90. if(save !== false) ace.settings.unset('sidebar', 'fixed');
  91. }
  92. try {
  93. document.getElementById('ace-settings-sidebar').checked = fix;
  94. } catch(e) {}
  95. if(window.jQuery) jQuery(document).trigger('settings.ace', ['sidebar_fixed' , fix , sidebar]);
  96. },
  97. //fixed position
  98. breadcrumbs_fixed : function(breadcrumbs, fix , save, chain) {
  99. if(ace.vars['very_old_ie']) return false;
  100. var breadcrumbs = breadcrumbs || '#breadcrumbs';
  101. if(typeof breadcrumbs === 'string') breadcrumbs = document.querySelector(breadcrumbs);
  102. if(!breadcrumbs) return false;
  103. fix = fix || false;
  104. save = save && true;
  105. if(fix && chain !== false && !ace.settings.is('sidebar', 'fixed')) {
  106. ace.settings.sidebar_fixed(null, true, save);
  107. }
  108. if(fix) {
  109. if(!ace.hasClass(breadcrumbs , 'breadcrumbs-fixed')) ace.addClass(breadcrumbs , 'breadcrumbs-fixed');
  110. if(save !== false) ace.settings.set('breadcrumbs', 'fixed');
  111. } else {
  112. ace.removeClass(breadcrumbs , 'breadcrumbs-fixed');
  113. if(save !== false) ace.settings.unset('breadcrumbs', 'fixed');
  114. }
  115. try {
  116. document.getElementById('ace-settings-breadcrumbs').checked = fix;
  117. } catch(e) {}
  118. if(window.jQuery) jQuery(document).trigger('settings.ace', ['breadcrumbs_fixed' , fix , breadcrumbs]);
  119. },
  120. //fixed size
  121. main_container_fixed : function(main_container, inside , save) {
  122. if(ace.vars['very_old_ie']) return false;
  123. inside = inside || false;
  124. save = save && true;
  125. var main_container = main_container || '#main-container';
  126. if(typeof main_container === 'string') main_container = document.querySelector(main_container);
  127. if(!main_container) return false;
  128. var navbar_container = document.getElementById('navbar-container');
  129. if(inside) {
  130. if( !ace.hasClass(main_container , 'container') ) ace.addClass(main_container , 'container');
  131. if( navbar_container && !ace.hasClass(navbar_container , 'container') ) ace.addClass(navbar_container , 'container');
  132. if( save !== false ) ace.settings.set('main-container', 'fixed');
  133. } else {
  134. ace.removeClass(main_container , 'container');
  135. if(navbar_container) ace.removeClass(navbar_container , 'container');
  136. if(save !== false) ace.settings.unset('main-container', 'fixed');
  137. }
  138. try {
  139. document.getElementById('ace-settings-add-container').checked = inside;
  140. } catch(e) {}
  141. if(navigator.userAgent.match(/webkit/i)) {
  142. //webkit has a problem redrawing and moving around the sidebar background in realtime
  143. //so we do this, to force redraw
  144. //there will be no problems with webkit if the ".container" class is statically put inside HTML code.
  145. var sidebar = document.getElementById('sidebar')
  146. ace.toggleClass(sidebar , 'menu-min')
  147. setTimeout(function() { ace.toggleClass(sidebar , 'menu-min') } , 0)
  148. }
  149. if(window.jQuery) jQuery(document).trigger('settings.ace', ['main_container_fixed', inside, main_container]);
  150. },
  151. sidebar_collapsed : function(sidebar, collapse , save) {
  152. if(ace.vars['very_old_ie']) return false;
  153. var sidebar = sidebar || '#sidebar';
  154. if(typeof sidebar === 'string') sidebar = document.querySelector(sidebar);
  155. if(!sidebar) return false;
  156. collapse = collapse || false;
  157. if(collapse) {
  158. ace.addClass(sidebar , 'menu-min');
  159. if(save !== false) ace.settings.set('sidebar', 'collapsed');
  160. } else {
  161. ace.removeClass(sidebar , 'menu-min');
  162. if(save !== false) ace.settings.unset('sidebar', 'collapsed');
  163. }
  164. if(window.jQuery) jQuery(document).trigger('settings.ace', ['sidebar_collapsed' , collapse, sidebar]);
  165. if(!window.jQuery) {
  166. var toggle_btn = document.querySelector('.sidebar-collapse[data-target="#'+(sidebar.getAttribute('id')||'')+'"]');
  167. if(!toggle_btn) toggle_btn = sidebar.querySelector('.sidebar-collapse');
  168. if(!toggle_btn) return;
  169. var icon = toggle_btn.querySelector('[data-icon1][data-icon2]'), icon1, icon2;
  170. if(!icon) return;
  171. icon1 = icon.getAttribute('data-icon1');//the icon for expanded state
  172. icon2 = icon.getAttribute('data-icon2');//the icon for collapsed state
  173. if(collapse) {
  174. ace.removeClass(icon, icon1);
  175. ace.addClass(icon, icon2);
  176. }
  177. else {
  178. ace.removeClass(icon, icon2);
  179. ace.addClass(icon, icon1);
  180. }
  181. }
  182. }
  183. /**
  184. ,
  185. select_skin : function(skin) {
  186. }
  187. */
  188. }
  189. //check the status of something
  190. ace.settings.check = function(item, val) {
  191. if(! ace.settings.exists(item, val) ) return;//no such setting specified
  192. var status = ace.settings.is(item, val);//is breadcrumbs-fixed? or is sidebar-collapsed? etc
  193. var mustHaveClass = {
  194. 'navbar-fixed' : 'navbar-fixed-top',
  195. 'sidebar-fixed' : 'sidebar-fixed',
  196. 'breadcrumbs-fixed' : 'breadcrumbs-fixed',
  197. 'sidebar-collapsed' : 'menu-min',
  198. 'main-container-fixed' : 'container'
  199. }
  200. //if an element doesn't have a specified class, but saved settings say it should, then add it
  201. //for example, sidebar isn't .fixed, but user fixed it on a previous page
  202. //or if an element has a specified class, but saved settings say it shouldn't, then remove it
  203. //for example, sidebar by default is minimized (.menu-min hard coded), but user expanded it and now shouldn't have 'menu-min' class
  204. var target = document.getElementById(item);//#navbar, #sidebar, #breadcrumbs
  205. if(status != ace.hasClass(target , mustHaveClass[item+'-'+val])) {
  206. ace.settings[item.replace('-','_')+'_'+val](null, status);//call the relevant function to make the changes
  207. }
  208. }
  209. //save/retrieve data using localStorage or cookie
  210. //method == 1, use localStorage
  211. //method == 2, use cookies
  212. //method not specified, use localStorage if available, otherwise cookies
  213. ace.data_storage = function(method, undefined) {
  214. var prefix = 'ace_';
  215. var storage = null;
  216. var type = 0;
  217. if((method == 1 || method === undefined) && 'localStorage' in window && window['localStorage'] !== null) {
  218. storage = ace.storage;
  219. type = 1;
  220. }
  221. else if(storage == null && (method == 2 || method === undefined) && 'cookie' in document && document['cookie'] !== null) {
  222. storage = ace.cookie;
  223. type = 2;
  224. }
  225. //var data = {}
  226. this.set = function(namespace, key, value, path, undefined) {
  227. if(!storage) return;
  228. if(value === undefined) {//no namespace here?
  229. value = key;
  230. key = namespace;
  231. if(value == null) storage.remove(prefix+key)
  232. else {
  233. if(type == 1)
  234. storage.set(prefix+key, value)
  235. else if(type == 2)
  236. storage.set(prefix+key, value, ace.config.cookie_expiry, path || ace.config.cookie_path)
  237. }
  238. }
  239. else {
  240. if(type == 1) {//localStorage
  241. if(value == null) storage.remove(prefix+namespace+'_'+key)
  242. else storage.set(prefix+namespace+'_'+key, value);
  243. }
  244. else if(type == 2) {//cookie
  245. var val = storage.get(prefix+namespace);
  246. var tmp = val ? JSON.parse(val) : {};
  247. if(value == null) {
  248. delete tmp[key];//remove
  249. if(ace.sizeof(tmp) == 0) {//no other elements in this cookie, so delete it
  250. storage.remove(prefix+namespace);
  251. return;
  252. }
  253. }
  254. else {
  255. tmp[key] = value;
  256. }
  257. storage.set(prefix+namespace , JSON.stringify(tmp), ace.config.cookie_expiry, path || ace.config.cookie_path)
  258. }
  259. }
  260. }
  261. this.get = function(namespace, key, undefined) {
  262. if(!storage) return null;
  263. if(key === undefined) {//no namespace here?
  264. key = namespace;
  265. return storage.get(prefix+key);
  266. }
  267. else {
  268. if(type == 1) {//localStorage
  269. return storage.get(prefix+namespace+'_'+key);
  270. }
  271. else if(type == 2) {//cookie
  272. var val = storage.get(prefix+namespace);
  273. var tmp = val ? JSON.parse(val) : {};
  274. return key in tmp ? tmp[key] : null;
  275. }
  276. }
  277. }
  278. this.remove = function(namespace, key, undefined) {
  279. if(!storage) return;
  280. if(key === undefined) {
  281. key = namespace
  282. this.set(key, null);
  283. }
  284. else {
  285. this.set(namespace, key, null);
  286. }
  287. }
  288. }
  289. //cookie storage
  290. ace.cookie = {
  291. // The following functions are from Cookie.js class in TinyMCE, Moxiecode, used under LGPL.
  292. /**
  293. * Get a cookie.
  294. */
  295. get : function(name) {
  296. var cookie = document.cookie, e, p = name + "=", b;
  297. if ( !cookie )
  298. return;
  299. b = cookie.indexOf("; " + p);
  300. if ( b == -1 ) {
  301. b = cookie.indexOf(p);
  302. if ( b != 0 )
  303. return null;
  304. } else {
  305. b += 2;
  306. }
  307. e = cookie.indexOf(";", b);
  308. if ( e == -1 )
  309. e = cookie.length;
  310. return decodeURIComponent( cookie.substring(b + p.length, e) );
  311. },
  312. /**
  313. * Set a cookie.
  314. *
  315. * The 'expires' arg can be either a JS Date() object set to the expiration date (back-compat)
  316. * or the number of seconds until expiration
  317. */
  318. set : function(name, value, expires, path, domain, secure) {
  319. var d = new Date();
  320. if ( typeof(expires) == 'object' && expires.toGMTString ) {
  321. expires = expires.toGMTString();
  322. } else if ( parseInt(expires, 10) ) {
  323. d.setTime( d.getTime() + ( parseInt(expires, 10) * 1000 ) ); // time must be in miliseconds
  324. expires = d.toGMTString();
  325. } else {
  326. expires = '';
  327. }
  328. document.cookie = name + "=" + encodeURIComponent(value) +
  329. ((expires) ? "; expires=" + expires : "") +
  330. ((path) ? "; path=" + path : "") +
  331. ((domain) ? "; domain=" + domain : "") +
  332. ((secure) ? "; secure" : "");
  333. },
  334. /**
  335. * Remove a cookie.
  336. *
  337. * This is done by setting it to an empty value and setting the expiration time in the past.
  338. */
  339. remove : function(name, path) {
  340. this.set(name, '', -1000, path);
  341. }
  342. };
  343. //local storage
  344. ace.storage = {
  345. get: function(key) {
  346. return window['localStorage'].getItem(key);
  347. },
  348. set: function(key, value) {
  349. window['localStorage'].setItem(key , value);
  350. },
  351. remove: function(key) {
  352. window['localStorage'].removeItem(key);
  353. }
  354. };
  355. //count the number of properties in an object
  356. //useful for getting the number of elements in an associative array
  357. ace.sizeof = function(obj) {
  358. var size = 0;
  359. for(var key in obj) if(obj.hasOwnProperty(key)) size++;
  360. return size;
  361. }
  362. //because jQuery may not be loaded at this stage, we use our own toggleClass
  363. ace.hasClass = function(elem, className) { return (" " + elem.className + " ").indexOf(" " + className + " ") > -1; }
  364. ace.addClass = function(elem, className) {
  365. if (!ace.hasClass(elem, className)) {
  366. var currentClass = elem.className;
  367. elem.className = currentClass + (currentClass.length? " " : "") + className;
  368. }
  369. }
  370. ace.removeClass = function(elem, className) {ace.replaceClass(elem, className);}
  371. ace.replaceClass = function(elem, className, newClass) {
  372. var classToRemove = new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i");
  373. elem.className = elem.className.replace(classToRemove, function (match, p1, p2) {
  374. return newClass? (p1 + newClass + p2) : " ";
  375. }).replace(/^\s+|\s+$/g, "");
  376. }
  377. ace.toggleClass = function(elem, className) {
  378. if(ace.hasClass(elem, className))
  379. ace.removeClass(elem, className);
  380. else ace.addClass(elem, className);
  381. }
  382. ace.isHTTMlElement = function(elem) {
  383. return window.HTMLElement ? elem instanceof HTMLElement : ('nodeType' in elem ? elem.nodeType == 1 : false);
  384. }
  385. //data_storage instance used inside ace.settings etc
  386. ace.data = new ace.data_storage(ace.config.storage_method);