PageRenderTime 49ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/MoodleWebRole/theme/chameleon/ui/chameleon_js.php

#
PHP | 3134 lines | 2458 code | 665 blank | 11 comment | 676 complexity | dd1a5dbd4b254aaa9b27f10079a64d3f MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, LGPL-2.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. header("Content-type: text/plain; charset=utf-8");
  3. $chameleon_theme_root = explode('/', $_SERVER['PHP_SELF']);
  4. array_pop($chameleon_theme_root);
  5. array_pop($chameleon_theme_root);
  6. $chameleon_theme_root = implode('/', $chameleon_theme_root);
  7. ?>
  8. if (!window.Node) {
  9. var Node = {
  10. ELEMENT_NODE: 1,
  11. ATTRIBUTE_NODE: 2,
  12. TEXT_NODE: 3,
  13. CDATA_SECTION_NODE: 4,
  14. ENTITY_REFERENCE_NODE: 5,
  15. ENTITY_NODE: 6,
  16. PROCESSING_INSTRUCTIONS_NODE: 7,
  17. COMMENT_NODE: 8,
  18. DOCUMENT_NODE: 9,
  19. DOCUMENT_TYPE_NODE: 10,
  20. DOCUMENT_FRAGMENT_NODE: 11,
  21. NOTATION_NODE: 12
  22. };
  23. }
  24. String.prototype.trim = function() {
  25. return this.replace(/^\s+|\s+$/g, '');
  26. };
  27. (function() {
  28. var struct = [];
  29. var hotspotMode = null;
  30. var Config = {
  31. THEME_ROOT: '<?php echo $chameleon_theme_root; ?>',
  32. REMOTE_URI: '<?php echo substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/')); ?>/css.php<?php echo (isset($_GET['id'])) ? '?id='.(int) $_GET['id'] : '?dummy=1'; ?>',
  33. FONTS_LIST: ['verdana, arial, helvetica, sans-serif', '"trebuchet ms", verdana, sans-serif', 'georgia, "trebuchet ms", times, serif', 'Other'],
  34. FONT_WEIGHTS: ['normal', 'bold'],
  35. FONT_STYLES: ['normal', 'italic'],
  36. TEXT_DECORATION: ['none', 'underline', 'overline', 'line-through'],
  37. TEXT_ALIGN: ['left', 'right', 'center', 'justify'],
  38. REPEAT_LIST: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'],
  39. POSITION_LIST: ['left top', 'left center', 'left bottom', 'center top', 'center center', 'center bottom', 'right top', 'right center', 'right bottom'],
  40. BORDER_LIST: ['solid', 'dotted', 'dashed', 'none'],
  41. UNITS: ['px', 'pt', 'em', '%'],
  42. PROPS_LIST: ['color', 'background-color', 'background-image', 'background-attachment', 'background-position', 'font-family', 'font-size', 'font-weight', 'font-style', 'line-height', 'margin', 'padding', 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width', 'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style', 'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color']
  43. };
  44. var Util = {
  45. __registry: {},
  46. __uniqueId: 0,
  47. createElement: function(tag, id) {
  48. if (!id) var id = 'chameleon-element-' + ++Util.__uniqueId;
  49. var obj = document.createElement(tag);
  50. obj.setAttribute('id', id);
  51. return obj;
  52. },
  53. removeElement: function(obj) {
  54. if (!obj || !obj.parentNode) return false;
  55. var kids = obj.getElementsByTagName('*');
  56. if (!kids.length && typeof obj.all != 'undefined') {
  57. kids = obj.all;
  58. }
  59. var n = kids.length;
  60. while (n--) {
  61. if (kids[n].id && Util.__registry[kids[n].id]) {
  62. Util.__removeAllEvents(kids[n]);
  63. }
  64. }
  65. if (Util.__registry[obj.id]) {
  66. Util.__removeAllEvents(obj);
  67. }
  68. obj.parentNode.removeChild(obj);
  69. },
  70. clearElement: function(obj) {
  71. while (obj.hasChildNodes()) {
  72. obj.removeChild(obj.firstChild);
  73. }
  74. },
  75. addEvent: function(obj, ev, fn) {
  76. if (!Util.__addToRegistry(obj, ev, fn)) return;
  77. if (obj.addEventListener) {
  78. obj.addEventListener(ev, fn, false);
  79. } else if (obj.attachEvent) {
  80. obj['e' + ev + fn] = fn;
  81. obj[ev + fn] = function() {
  82. obj['e' + ev + fn](window.event);
  83. };
  84. obj.attachEvent('on' + ev, obj[ev + fn]);
  85. }
  86. },
  87. removeEvent: function(obj, ev, fn) {
  88. if (!Util.__removeFromRegistry(obj, ev, fn)) return;
  89. if (obj.removeEventListener) {
  90. obj.removeEventListener(ev, fn, false);
  91. } else if (obj.detachEvent) {
  92. obj.detachEvent('on' + ev, obj[ev + fn]);
  93. obj[ev + fn] = null;
  94. }
  95. },
  96. __getEventId: function(obj) {
  97. if (obj == document) return 'chameleon-doc';
  98. if (obj == window) return 'chameleon-win';
  99. if (obj.id) return obj.id;
  100. return false;
  101. },
  102. __findEvent: function(id, ev, fn) {
  103. var i = Util.__registry[id][ev].length;
  104. while (i--) {
  105. if (Util.__registry[id][ev][i] == fn) {
  106. return i;
  107. }
  108. }
  109. return -1;
  110. },
  111. __addToRegistry: function(obj, ev, fn) {
  112. var id = Util.__getEventId(obj);
  113. if (!id) return false;
  114. if (!Util.__registry[id]) {
  115. Util.__registry[id] = {};
  116. }
  117. if (!Util.__registry[id][ev]) {
  118. Util.__registry[id][ev] = [];
  119. }
  120. if (Util.__findEvent(id, ev, fn) == -1) {
  121. Util.__registry[id][ev].push(fn);
  122. return true;
  123. }
  124. return false;
  125. },
  126. __removeFromRegistry: function(obj, ev, fn) {
  127. var id = Util.__getEventId(obj);
  128. if (!id) return false;
  129. var pos = Util.__findEvent(id, ev, fn);
  130. if (pos != -1) {
  131. Util.__registry[id][ev].splice(pos, 1);
  132. return true;
  133. }
  134. return false;
  135. },
  136. __removeAllEvents: function(obj) {
  137. for (var event in Util.__registry[obj.id]) {
  138. var n = Util.__registry[obj.id][event].length;
  139. while (n--) {
  140. Util.removeEvent(obj, event, Util.__registry[obj.id][event][n]);
  141. }
  142. }
  143. },
  144. cleanUp: function() {
  145. struct = null;
  146. UI.closeAllBoxes();
  147. }
  148. };
  149. var Pos = {
  150. getElement: function(obj) {
  151. var x = 0; var y = 0;
  152. if (obj.offsetParent) {
  153. while (obj.offsetParent) {
  154. x += obj.offsetLeft;
  155. y += obj.offsetTop;
  156. obj = obj.offsetParent;
  157. }
  158. }
  159. return {x: x, y: y};
  160. },
  161. getMouse: function(e) {
  162. var x = 0; var y = 0;
  163. if (e.pageX || e.pageY) {
  164. x = e.pageX;
  165. y = e.pageY;
  166. } else if (e.clientX || e.clientY) {
  167. x = e.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
  168. y = e.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
  169. }
  170. return {x: x, y: y};
  171. }
  172. };
  173. var CSS = {
  174. __localCSS: {},
  175. __remoteCSS: {},
  176. __localSaveRequired: false,
  177. __remoteSaveRequired: false,
  178. requireRemoteSave: function() {
  179. CSS.__remoteSaveRequired = true;
  180. },
  181. clearTheme: function() {
  182. /*var links = document.getElementsByTagName('link');
  183. var n = links.length;
  184. while (n--) {
  185. if (links[n].href && links[n].href.indexOf('<?php echo $chameleon_theme_root . "/styles.php"; ?>') != -1) {
  186. links[n].parentNode.removeChild(links[n]);
  187. break;
  188. }
  189. }*/
  190. },
  191. loadRemote: function(doSetup) {
  192. if (!Sarissa.IS_ENABLED_XMLHTTP) {
  193. return false;
  194. }
  195. var xmlhttp = new XMLHttpRequest();
  196. xmlhttp.onreadystatechange = function() {
  197. if (xmlhttp.readyState == 4) {
  198. if (xmlhttp.responseText.indexOf('CHAMELEON_ERROR') != -1) {
  199. alert('There was an error loading from the server:\n' + xmlhttp.responseText.replace(/CHAMELEON_ERROR /, '') + '.');
  200. return;
  201. }
  202. CSS.__remoteCSS = CSS.toObject(xmlhttp.responseText);
  203. CSS.__localCSS = CSS.__clone(CSS.__remoteCSS);
  204. CSS.preview();
  205. if (doSetup) {
  206. setup();
  207. }
  208. xmlhttp = null;
  209. }
  210. };
  211. xmlhttp.open('GET', Config.REMOTE_URI + '&nc=' + new Date().getTime(), true);
  212. xmlhttp.send(null);
  213. return true;
  214. },
  215. updateTemp: function(e, reset) {
  216. if (!CSS.__localSaveRequired && !reset) {
  217. UI.statusMsg('There are no changes that need saving!', 'chameleon-notice');
  218. return;
  219. }
  220. if (!reset) {
  221. UI.statusMsg('Updating temporary styles on the server...', 'chameleon-working');
  222. } else {
  223. UI.statusMsg('Deleting temporary styles from the server...', 'chameleon-working');
  224. }
  225. var css = CSS.toString();
  226. var xmlhttp = new XMLHttpRequest();
  227. xmlhttp.onreadystatechange = function() {
  228. if (xmlhttp.readyState == 4) {
  229. if (xmlhttp.responseText.indexOf('CHAMELEON_ERROR') != -1) {
  230. UI.statusMsg('There was an error saving to the server:\n' + xmlhttp.responseText.replace(/CHAMELEON_ERROR /, '') + '.', 'chameleon-error');
  231. } else {
  232. CSS.__localSaveRequired = false;
  233. if (!reset) {
  234. UI.statusMsg('Temporary styles have been updated.', 'chameleon-ok');
  235. } else {
  236. UI.statusMsg('Temporary styles have been cleared.', 'chameleon-ok');
  237. }
  238. }
  239. xmlhttp = null;
  240. }
  241. };
  242. xmlhttp.open('POST', Config.REMOTE_URI + '&temp=1', true);
  243. xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  244. xmlhttp.send('css=' + css);
  245. },
  246. updateRemote: function() {
  247. if (!CSS.__remoteSaveRequired) {
  248. UI.statusMsg('There are no changes that need saving!', 'chameleon-notice');
  249. return;
  250. }
  251. var css = CSS.toString(CSS.__localCSS);
  252. UI.statusMsg('Updating styles on the server...', 'chameleon-working');
  253. var xmlhttp = new XMLHttpRequest();
  254. xmlhttp.onreadystatechange = function() {
  255. if (xmlhttp.readyState == 4) {
  256. if (xmlhttp.responseText.indexOf('CHAMELEON_ERROR') != -1) {
  257. UI.statusMsg('There was an error saving to the server:\n' + xmlhttp.responseText.replace(/CHAMELEON_ERROR /, '') + '.', 'chameleon-error');
  258. } else {
  259. CSS.__remoteCSS = CSS.toObject(css);
  260. CSS.__localSaveRequired = false;
  261. CSS.__remoteSaveRequired = false;
  262. UI.statusMsg('Styles have been saved to the server.', 'chameleon-ok');
  263. }
  264. xmlhttp = null;
  265. }
  266. };
  267. xmlhttp.open('POST', Config.REMOTE_URI, true);
  268. xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  269. xmlhttp.send('css=' + css);
  270. },
  271. hardReset: function(e, noPrompt) {
  272. if (noPrompt || confirm('Are you sure? This will erase all styles that have not been permanently saved to the server.')) {
  273. CSS.__localCSS = {};
  274. CSS.updateTemp(null, true);
  275. CSS.__localCSS = CSS.__clone(CSS.__remoteCSS);
  276. CSS.__localSaveRequired = false;
  277. CSS.__remoteSaveRequired = false;
  278. CSS.preview();
  279. }
  280. },
  281. setPropValue: function(prop, value, selector) {
  282. if (!selector) var selector = CSS.Selector.get();
  283. if (!CSS.__localCSS[selector]) {
  284. CSS.__localCSS[selector] = {};
  285. }
  286. var matches = prop.match(/^border\-([^\-]+)$/);
  287. if (value) {
  288. var func = CSS.__requiresFunction(prop);
  289. if (func && value != 'none') {
  290. CSS.__localCSS[selector][prop] = func + '(' + value + ')';
  291. } else if (matches) {
  292. CSS.__localCSS[selector]['border-left-' + matches[1]] = value;
  293. CSS.__localCSS[selector]['border-right-' + matches[1]] = value;
  294. CSS.__localCSS[selector]['border-top-' + matches[1]] = value;
  295. CSS.__localCSS[selector]['border-bottom-' + matches[1]] = value;
  296. } else {
  297. CSS.__localCSS[selector][prop] = value;
  298. }
  299. } else {
  300. if (matches) {
  301. CSS.unsetProp('border-left-' + matches[1], selector);
  302. CSS.unsetProp('border-right-' + matches[1], selector);
  303. CSS.unsetProp('border-top-' + matches[1], selector);
  304. CSS.unsetProp('border-bottom-' + matches[1], selector);
  305. } else {
  306. CSS.unsetProp(prop, selector);
  307. }
  308. }
  309. CSS.__localSaveRequired = true;
  310. CSS.__remoteSaveRequired = true;
  311. CSS.preview(selector);
  312. },
  313. getPropValue: function(prop, selector) {
  314. if (!selector) var selector = CSS.Selector.get();
  315. if (!CSS.__localCSS[selector] || !CSS.__localCSS[selector][prop]) {
  316. return '';
  317. }
  318. return CSS.__cleanFunctions(CSS.__localCSS[selector][prop]);
  319. },
  320. unsetProp: function(prop, selector) {
  321. if (!selector) var selector = CSS.Selector.get();
  322. if (!CSS.__localCSS[selector] || !CSS.__localCSS[selector][prop]) return;
  323. CSS.__localCSS[selector][prop] = null;
  324. delete CSS.__localCSS[selector][prop];
  325. if (!CSS.__hasProps(selector)) {
  326. CSS.__localCSS[selector] = null;
  327. delete CSS.__localCSS[selector];
  328. }
  329. },
  330. __hasProps: function(selector) {
  331. for (var prop in CSS.__localCSS[selector]) {
  332. if (prop) {
  333. return true;
  334. }
  335. }
  336. return false;
  337. },
  338. __cleanFunctions: function(val) {
  339. var toClean = ['url'];
  340. for (var i = 0; i < toClean.length; ++i) {
  341. var start = val.indexOf(toClean[i] + '(');
  342. var end = val.indexOf(')', start);
  343. if (start == -1 || end == -1) {
  344. continue;
  345. }
  346. val = val.slice(start + toClean[i].length + 1, end);
  347. }
  348. return val;
  349. },
  350. __requiresFunction: function(prop) {
  351. var fnProps = {};
  352. fnProps['background-image'] = 'url';
  353. if (fnProps[prop]) {
  354. return fnProps[prop];
  355. }
  356. return false;
  357. },
  358. fixPath: function(val) {
  359. if (val == 'none') return val;
  360. var tmp = val.split('(');
  361. if (tmp.length > 1) {
  362. tmp[1] = Config.THEME_ROOT + '/' + tmp[1];
  363. return tmp.join('(');
  364. }
  365. return Config.THEME_ROOT + '/' + val;
  366. },
  367. preview: function(sel) {
  368. var styleId = 'chameleon-preview-styles';
  369. var h = document.getElementsByTagName('head')[0];
  370. var s = document.getElementById(styleId);
  371. if (!s) {
  372. var s = Util.createElement('style', styleId);
  373. s.setAttribute('type', 'text/css');
  374. h.appendChild(s);
  375. }
  376. if (navigator.userAgent.toLowerCase().indexOf('msie') != -1 && !window.opera && document.styleSheets && document.styleSheets.length > 0) {
  377. var lastStyle = document.styleSheets[document.styleSheets.length - 1];
  378. var ieCrashProtector = /[^a-z0-9 #_:\.\-\*]/i; // some characters appearing in a selector can cause addRule to crash IE in spectacular style - if the selector contains any character outside this list don't try to add to the preview
  379. var ieWarning = false;
  380. if (sel) {
  381. var matchedSelectors = [];
  382. if (typeof sel == 'string') {
  383. sel = [sel];
  384. }
  385. var n = lastStyle.rules.length;
  386. while (n--) {
  387. var ns = sel.length;
  388. if (ns == 0) {
  389. break;
  390. }
  391. while (ns--) {
  392. if (sel[ns].match(ieCrashProtector)) {
  393. ieWarning = true;
  394. sel.splice(ns, 1);
  395. break;
  396. }
  397. if (lastStyle.rules[n].selectorText.toLowerCase() == sel[ns].toLowerCase()) {
  398. matchedSelectors.push(sel[ns]);
  399. sel.splice(ns, 1);
  400. lastStyle.removeRule(n);
  401. break;
  402. }
  403. }
  404. }
  405. matchedSelectors = matchedSelectors.concat(sel);
  406. var sl = matchedSelectors.length;
  407. while (sl--) {
  408. lastStyle.addRule(matchedSelectors[sl], CSS.__propsToString(CSS.__localCSS[matchedSelectors[sl]], true));
  409. }
  410. } else {
  411. var n = lastStyle.rules.length;
  412. while (n--) {
  413. lastStyle.removeRule(n);
  414. }
  415. for (var sel in CSS.__localCSS) {
  416. if (sel.match(ieCrashProtector)) {
  417. ieWarning = true;
  418. continue;
  419. }
  420. var dec = CSS.__propsToString(CSS.__localCSS[sel], true);
  421. lastStyle.addRule(sel, dec);
  422. }
  423. }
  424. if (ieWarning) {
  425. UI.statusMsg('The edited CSS contains content that can not be previewed by Internet Explorer', 'chameleon-notice');
  426. }
  427. } else {
  428. Util.clearElement(s);
  429. s.appendChild(document.createTextNode(CSS.toString(CSS.__localCSS, true))); // I think innerHTML would be faster here, but it doesn't work in KHTML browsers (Safari etc)
  430. }
  431. },
  432. __merge: function() {
  433. var merged = {};
  434. for (var i = 0; i < arguments.length; ++i) {
  435. for (var sel in arguments[i]) {
  436. var newSelector = false;
  437. if (!merged[sel]) {
  438. merged[sel] = {};
  439. newSelector = true;
  440. }
  441. for (var prop in arguments[i][sel]) {
  442. merged[sel][prop] = arguments[i][sel][prop];
  443. }
  444. if (i > 0 && !newSelector) {
  445. for (var prop in merged[sel]) {
  446. if (!arguments[i][sel][prop]) {
  447. merged[sel][prop] = null;
  448. delete merged[sel][prop];
  449. }
  450. }
  451. }
  452. }
  453. if (i > 0) {
  454. for (var sel in merged) {
  455. if (!arguments[i][sel]) {
  456. merged[sel] = null;
  457. delete merged[sel];
  458. }
  459. }
  460. }
  461. }
  462. return merged;
  463. },
  464. __clone: function(src) {
  465. var cloned = {};
  466. for (var sel in src) {
  467. if (!cloned[sel]) {
  468. cloned[sel] = {};
  469. }
  470. for (var prop in src[sel]) {
  471. cloned[sel][prop] = src[sel][prop];
  472. }
  473. }
  474. return cloned;
  475. },
  476. toString: function(css, fixpath) {
  477. if (!css) var css = CSS.__localCSS;
  478. var dec = '';
  479. for (var sel in css) {
  480. dec += sel + ' ' + CSS.__propsToString(css[sel], fixpath, sel);
  481. }
  482. return dec;
  483. },
  484. __propsToString: function(css, fixpath) {
  485. CSS.__Shorthand.border = {};
  486. var hasBorder = false;
  487. var col = false;
  488. var importantBorders = [];
  489. var dec = '{\n';
  490. for (var prop in css) {
  491. var includeProp = true;
  492. if (prop.indexOf('border') != -1 && prop.indexOf('spacing') == -1 && prop.indexOf('collapse') == -1) {
  493. if (css[prop].indexOf('!important') == -1) {
  494. CSS.__Shorthand.recordBorder(prop, css[prop]);
  495. } else {
  496. importantBorders.push({prop: prop, css: css[prop]});
  497. }
  498. includeProp = false;
  499. hasBorder = true;
  500. }
  501. if (prop == 'color') {
  502. col = css[prop];
  503. }
  504. if (includeProp) {
  505. if (fixpath && (CSS.__requiresFunction(prop) == 'url') && css[prop] != 'none') {
  506. dec += ' ' + prop + ': ' + CSS.fixPath(css[prop]) + ';\n';
  507. } else {
  508. dec += ' ' + prop + ': ' + css[prop] + ';\n';
  509. }
  510. }
  511. }
  512. if (hasBorder) {
  513. dec += CSS.__Shorthand.getBorderString(col);
  514. }
  515. var n;
  516. if (n = importantBorders.length) {
  517. while (n--) {
  518. dec += ' ' + importantBorders[n].prop + ': ' + importantBorders[n].css + ';\n';
  519. }
  520. }
  521. dec += '}\n';
  522. return dec;
  523. },
  524. toObject: function(css) {
  525. var cssObj = {};
  526. var end;
  527. while (end = css.indexOf('}'), end != -1) {
  528. var cssRule = css.substr(0, end);
  529. var parts = cssRule.split('{');
  530. var selector = parts.shift()
  531. if (selector.indexOf(',') != -1) {
  532. var selectorArr = selector.split(',');
  533. } else {
  534. var selectorArr = [selector];
  535. }
  536. var rules = parts.pop().trim();
  537. rules = rules.split(';');
  538. for (var i = 0; i < rules.length; ++i) {
  539. if (rules[i].indexOf(':') == -1) {
  540. break;
  541. }
  542. var rule = rules[i].split(':');
  543. var prop = rule.shift().trim();
  544. var val = rule.pop().trim();
  545. for (var j = 0; j < selectorArr.length; ++j) {
  546. var noFontPropReset = {};
  547. selector = selectorArr[j].trim();
  548. if (!cssObj[selector]) {
  549. cssObj[selector] = {};
  550. }
  551. if (prop != 'font' && (prop.indexOf('font') != -1 || prop == 'line-height')) {
  552. noFontPropReset[prop] = true;
  553. }
  554. if (prop == 'background') {
  555. CSS.__Shorthand.setBackground(cssObj, selector, val);
  556. } else if (prop == 'font') {
  557. CSS.__Shorthand.setFont(cssObj, selector, val, noFontPropReset);
  558. } else if ((prop == 'border' || prop.match(/^border\-([^-]+)$/)) && prop.indexOf('spacing') == -1 && prop.indexOf('collapse') == -1) {
  559. CSS.__Shorthand.setBorder(cssObj, selector, val, prop);
  560. } else {
  561. cssObj[selector][prop] = val;
  562. }
  563. }
  564. }
  565. css = css.substring(end + 1);
  566. }
  567. return cssObj;
  568. },
  569. getSelectorCSS: function(selector, asObject) {
  570. if (!selector) var selector = CSS.Selector.get();
  571. var css = (CSS.__localCSS[selector]) ? CSS.__localCSS[selector] : {};
  572. if (asObject) {
  573. return css;
  574. }
  575. return selector + ' ' + CSS.__propsToString(css);
  576. },
  577. saveRequired: function() {
  578. return CSS.__localSaveRequired || CSS.__serverSaveRequired;
  579. },
  580. checkSpec: function(e, selector) {
  581. if (!selector) var selector = CSS.Selector.get();
  582. if (selector == '') {
  583. UI.statusMsg('First you have to choose which item to style!', 'chameleon-notice');
  584. return;
  585. }
  586. var splitSelector = function(selector) {
  587. var selectorEnd = selector.split(' ').pop();
  588. selectorEnd = selectorEnd.replace(/([\.:#])/g, '|$1');
  589. return selectorEnd.split('|');
  590. };
  591. var similar = [];
  592. var selectorBits = splitSelector(selector);
  593. for (var sel in CSS.__localCSS) {
  594. var selBits = splitSelector(sel);
  595. var n = selectorBits.length;
  596. while (n--) {
  597. var match = selectorBits[n];
  598. var m = selBits.length;
  599. while (m--) {
  600. if (selBits[m] == match) {
  601. var l = similar.length;
  602. var add = true;
  603. while (l--) {
  604. if (similar[l] == sel) {
  605. add = false;
  606. break;
  607. }
  608. }
  609. if (add) {
  610. similar.push(sel);
  611. }
  612. break;
  613. }
  614. }
  615. }
  616. }
  617. if (similar.length) {
  618. UI.Selector.__displayOverview(null, similar, selector);
  619. } else {
  620. UI.statusMsg('Your file currently contains no selectors that appear similar to "' + selector + '"', 'chameleon-notice');
  621. }
  622. },
  623. unloadPrompt: function() {
  624. if (CSS.__localSaveRequired) {
  625. if (confirm('You have made changes to the CSS on this page since the last time it was saved, these changes will be lost unless you save them now. Select OK to save a temporary copy or Cancel to continue and discard the unsaved CSS.')) {
  626. CSS.updateTemp();
  627. }
  628. }
  629. var cookieVal = (CSS.__remoteSaveRequired) ? 1 : 0;
  630. var crumb = new cookie('chameleon_server_save_required', cookieVal, 30, '/', null, null);
  631. crumb.set();
  632. }
  633. };
  634. CSS.Selector = {
  635. trimmed: [],
  636. full: [],
  637. selector: '',
  638. create: function() {
  639. CSS.Selector.trimmed = [];
  640. var n = struct.length;
  641. while (n--) {
  642. if (CSS.Selector.full[n]) {
  643. CSS.Selector.trimmed.push(CSS.Selector.full[n].val);
  644. }
  645. }
  646. CSS.Selector.set(CSS.Selector.trimmed.join(' '));
  647. },
  648. modify: function(e) {
  649. var target = e.target || e.srcElement;
  650. var p = target.position;
  651. var sel = CSS.Selector.full;
  652. if (!sel[p]) {
  653. UI.Selector.highlight(target);
  654. sel[p] = {val: target.selectorValue, id: target.id};
  655. } else if (sel[p].val != target.selectorValue) {
  656. UI.Selector.highlight(target);
  657. UI.Selector.unhighlight(document.getElementById(sel[p].id));
  658. sel[p] = {val: target.selectorValue, id: target.id};
  659. } else {
  660. UI.Selector.unhighlight(target);
  661. sel[p] = null;
  662. }
  663. CSS.Selector.create();
  664. UI.Selector.displaySelector(CSS.Selector.trimmed);
  665. },
  666. set: function(sel) {
  667. CSS.Selector.selector = sel;
  668. },
  669. get: function() {
  670. return CSS.Selector.selector;
  671. },
  672. reset: function() {
  673. CSS.Selector.trimmed = [];
  674. CSS.Selector.full = [];
  675. CSS.Selector.set('');
  676. }
  677. };
  678. CSS.__Shorthand = {
  679. border: {},
  680. recordBorder: function(prop, value) {
  681. var pr = prop.split('-')
  682. var p = pr.pop();
  683. var s = pr.pop();
  684. if (!CSS.__Shorthand.border[p]) {
  685. CSS.__Shorthand.border[p] = [];
  686. }
  687. if (!CSS.__Shorthand.border[s]) {
  688. CSS.__Shorthand.border[s] = {};
  689. }
  690. if (!CSS.__Shorthand.border[s][p]) {
  691. CSS.__Shorthand.border[s][p] = [];
  692. }
  693. CSS.__Shorthand.border[p].push({prop: prop, value: value});
  694. CSS.__Shorthand.border[s][p] = value;
  695. },
  696. getBorderString: function(col) {
  697. var cb = CSS.__Shorthand.border;
  698. var useHowManyProps = function(prop) {
  699. if (!cb['top'] || !cb['right'] || !cb['bottom'] || !cb['left']) {
  700. return false;
  701. }
  702. if (!(cb['top'][prop] && cb['right'][prop] && cb['bottom'][prop] && cb['left'][prop])) {
  703. return false;
  704. }
  705. if (cb['top'][prop] == cb['right'][prop] && cb['top'][prop] == cb['bottom'][prop] && cb['top'][prop] == cb['left'][prop]) {
  706. return 1;
  707. }
  708. if (cb['top'][prop] == cb['bottom'][prop] && cb['right'][prop] == cb['left'][prop]) {
  709. return 2;
  710. }
  711. if (cb['right'][prop] == cb['left'][prop]) {
  712. return 3;
  713. }
  714. return 4;
  715. };
  716. var getPropShorthand = function(prop) {
  717. var num = useHowManyProps(prop);
  718. if (!num) {
  719. return '';
  720. }
  721. if (prop.indexOf('color') != -1) {
  722. var l = inheritColor(cb['left'][prop]);
  723. var r = inheritColor(cb['right'][prop]);
  724. var t = inheritColor(cb['top'][prop]);
  725. var b = inheritColor(cb['bottom'][prop]);
  726. } else {
  727. var l = cb['left'][prop];
  728. var r = cb['right'][prop];
  729. var t = cb['top'][prop];
  730. var b = cb['bottom'][prop];
  731. }
  732. var propShorthand = '';
  733. if (num == 1) {
  734. propShorthand += ' border-' + prop + ': ' + l;
  735. } else if (num == 2) {
  736. propShorthand += ' border-' + prop + ': ' + t + ' ' + l;
  737. } else if (num == 3) {
  738. propShorthand += ' border-' + prop + ': ' + t + ' ' + l + ' ' + b;
  739. } else {
  740. propShorthand += ' border-' + prop + ': ' + t + ' ' + r + ' ' + b + ' ' + l;
  741. }
  742. return propShorthand + ';\n';
  743. };
  744. var propsStr = function(props) {
  745. var str = '';
  746. for (var i = 0; i < props.length; ++i) {
  747. str += ' ' + props[i].prop + ': ' + ((props[i].prop.indexOf('color') != -1) ? inheritColor(props[i].value) : props[i].value) + ';\n';
  748. }
  749. return str;
  750. };
  751. var inheritColor = function(val) {
  752. if (!col || val != 'inherit') return val;
  753. return col;
  754. };
  755. var setImportant = function(str) {
  756. if (!str) return '';
  757. if (str.indexOf('!important') == -1) return str;
  758. str = str.replace(/ *\!important */g, ' ');
  759. return str.substr(0, str.lastIndexOf(';')) + ' !important;\n';
  760. };
  761. var widthEqual = (cb['width']) ? CSS.__Shorthand.__allPropsEqual(cb['width']) : false;
  762. var styleEqual = (cb['style']) ? CSS.__Shorthand.__allPropsEqual(cb['style']) : false;
  763. var colorEqual = (cb['color']) ? CSS.__Shorthand.__allPropsEqual(cb['color']) : false;
  764. if (widthEqual && styleEqual && colorEqual) {
  765. var propStr = setImportant(cb['width'][0].value + ' ' + cb['style'][0].value + ' ' + inheritColor(cb['color'][0].value) + ';\n');
  766. if (cb['left'] && cb['top'] && cb['right'] && cb['bottom']) {
  767. return ' border: ' + propStr;
  768. }
  769. var sideShorthand = '';
  770. if (cb['top']) {
  771. sideShorthand += ' border-top: ' + propStr;
  772. }
  773. if (cb['right']) {
  774. sideShorthand += ' border-right: ' + propStr;
  775. }
  776. if (cb['bottom']) {
  777. sideShorthand += ' border-bottom: ' + propStr;
  778. }
  779. if (cb['left']) {
  780. sideShorthand += ' border-left: ' + propStr;
  781. }
  782. return sideShorthand;
  783. }
  784. var widthProps = getPropShorthand('width');
  785. if (!widthProps) {
  786. widthProps = (cb['width']) ? propsStr(cb['width']) : '';
  787. }
  788. var styleProps = getPropShorthand('style');
  789. if (!styleProps) {
  790. styleProps = (cb['style']) ? propsStr(cb['style']) : '';
  791. }
  792. var colorProps = getPropShorthand('color');
  793. if (!colorProps) {
  794. colorProps = (cb['color']) ? propsStr(cb['color']) : '';
  795. }
  796. return setImportant(widthProps) + setImportant(styleProps) + setImportant(colorProps);
  797. },
  798. setBorder: function(css, selector, value, prop) {
  799. var props = {};
  800. var p = '';
  801. props['width'] = {
  802. regexp: /^(thin|medium|thick|0|(\d+(([^%\d]+)|%)))$/,
  803. def: 'medium'
  804. };
  805. props['style'] = {
  806. regexp: /none|dotted|dashed|solid|double|groove|ridge|inset|outset/,
  807. def: 'none'
  808. };
  809. props['color'] = {
  810. regexp: /^((rgb\(\d{1,3} *, *\d{1,3} *, *\d{1,3} *\))|(#[A-F0-9]{3}([A-F0-9]{3})?)|([a-z]+))$/i,
  811. def: 'inherit'
  812. };
  813. var bits = value.split(' ');
  814. var imp = (bits[bits.length - 1] == '!important') ? ' ' + bits.pop() : '';
  815. if (prop == 'border') {
  816. for (var i in props) {
  817. css[selector]['border-top-' + i] = props[i].def;
  818. css[selector]['border-right-' + i] = props[i].def;
  819. css[selector]['border-bottom-' + i] = props[i].def;
  820. css[selector]['border-left-' + i] = props[i].def;
  821. var j = bits.length;
  822. while (j--) {
  823. if (bits[j].match(props[i].regexp)) {
  824. css[selector]['border-top-' + i] = bits[j];
  825. css[selector]['border-right-' + i] = bits[j];
  826. css[selector]['border-bottom-' + i] = bits[j];
  827. css[selector]['border-left-' + i] = bits[j];
  828. bits.splice(j, 1);
  829. break;
  830. }
  831. }
  832. }
  833. } else if (prop == 'border-left' || prop == 'border-right' || prop == 'border-top' || prop == 'border-bottom') {
  834. for (var i in props) {
  835. css[selector][prop + '-' + i] = props[i].def;
  836. var j = bits.length;
  837. while (j--) {
  838. if (bits[j].match(props[i].regexp)) {
  839. css[selector][prop + '-' + i] = bits[j] + imp;
  840. bits.splice(j, 1);
  841. break;
  842. }
  843. }
  844. }
  845. imp = '';
  846. } else if (prop == 'border-width' || prop == 'border-style' || prop == 'border-color') {
  847. var p = prop.split('-').pop();
  848. var num = bits.length;
  849. if (num == 1) {
  850. css[selector]['border-top-' + p] = bits[0];
  851. css[selector]['border-right-' + p] = bits[0];
  852. css[selector]['border-bottom-' + p] = bits[0];
  853. css[selector]['border-left-' + p] = bits[0];
  854. } else if (num == 2) {
  855. css[selector]['border-top-' + p] = bits[0];
  856. css[selector]['border-right-' + p] = bits[1];
  857. css[selector]['border-bottom-' + p] = bits[0];
  858. css[selector]['border-left-' + p] = bits[1];
  859. } else if (num == 3) {
  860. css[selector]['border-top-' + p] = bits[0];
  861. css[selector]['border-right-' + p] = bits[1];
  862. css[selector]['border-bottom-' + p] = bits[2];
  863. css[selector]['border-left-' + p] = bits[1];
  864. } else if (num == 4) {
  865. css[selector]['border-top-' + p] = bits[0];
  866. css[selector]['border-right-' + p] = bits[1];
  867. css[selector]['border-bottom-' + p] = bits[2];
  868. css[selector]['border-left-' + p] = bits[3];
  869. }
  870. }
  871. if (imp != '') {
  872. var sides = ['top', 'right', 'bottom', 'left'];
  873. for (var i = 0; i < 4; ++i) {
  874. for (var j in props) {
  875. if (p != '' && p != j) {
  876. continue;
  877. }
  878. if (css[selector]['border-' + sides[i] + '-' + j]) {
  879. css[selector]['border-' + sides[i] + '-' + j] += imp;
  880. }
  881. }
  882. }
  883. }
  884. },
  885. setBackground: function(css, selector, value) {
  886. var imp = (value.indexOf('!important') != -1) ? ' !important' : '';
  887. if (imp != '') {
  888. value = value.replace(/ *\!important */g, '');
  889. }
  890. var urlPos = value.indexOf('url(');
  891. if (urlPos == -1 && value.indexOf('none') == -1) {
  892. css[selector]['background-color'] = value + imp;
  893. return;
  894. } else if (urlPos == -1 && value.indexOf(' none') != -1) {
  895. var bits = value.split(' ');
  896. css[selector]['background-color'] = bits[0] + imp;
  897. css[selector]['background-image'] = bits[1] + imp;
  898. return;
  899. } else if (value == 'none') {
  900. css[selector]['background-image'] = value + imp;
  901. return;
  902. }
  903. var bits = value.split('url(');
  904. var endImg = bits[1].indexOf(')');
  905. if (endImg == -1) {
  906. return;
  907. }
  908. css[selector]['background-image'] = 'url(' + bits[1].substr(0, endImg).replace(/["']+/g, '') + ')' + imp; //"
  909. var pos = [];
  910. var bgOptions = bits[1].substring(endImg + 1).split(' ');
  911. var n = bgOptions.length;
  912. for (var i = 0; i < n; ++i) {
  913. var opt = bgOptions[i].trim();
  914. if (opt.indexOf('repeat') != -1) {
  915. css[selector]['background-repeat'] = opt + imp;
  916. } else if (opt == 'fixed' || opt == 'scroll') {
  917. css[selector]['background-attachment'] = opt + imp;
  918. } else if (opt != '') {
  919. pos.push(opt);
  920. }
  921. }
  922. if (pos.length == 2) {
  923. css[selector]['background-position'] = pos.join(' ') + imp;
  924. }
  925. var col = bits[0].trim();
  926. if (col != '') {
  927. css[selector]['background-color'] = col + imp;
  928. }
  929. },
  930. setFont: function(css, selector, value, noreset) {
  931. var imp = (value.indexOf('!important') != -1) ? ' !important' : '';
  932. if (imp != '') {
  933. value = value.replace(/ *\!important */g, '');
  934. }
  935. var order = ['font-style', 'font-variant', 'font-weight', 'font-size', 'font-family'];
  936. var numProps = order.length;
  937. var allowedVals = {};
  938. allowedVals['font-style'] = /(normal|italic|oblique|inherit)/;
  939. allowedVals['font-variant'] = /(normal|small\-caps|inherit)/;
  940. allowedVals['font-weight'] = /(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit)/;
  941. allowedVals['font-size'] = /([^ ]+)/;
  942. allowedVals['font-family'] = /(.+$)/;
  943. if (!noreset['font-style']) css[selector]['font-style'] = 'normal';
  944. if (!noreset['font-variant']) css[selector]['font-variant'] = 'normal';
  945. if (!noreset['font-weight']) css[selector]['font-weight'] = 'normal';
  946. if (!noreset['font-size']) css[selector]['font-size'] = 'medium';
  947. if (!noreset['line-height']) css[selector]['line-height'] = 'normal';
  948. var expandShorthand = function(bits) {
  949. var numBits = bits.length;
  950. var startProp = 0;
  951. for (var i = 0; i < numBits; ++i) {
  952. if (i > numProps - 1) {
  953. return;
  954. }
  955. for (var j = startProp; j < numProps; ++j) {
  956. if (bits[i].match(allowedVals[order[j]])) {
  957. if (order[j] == 'font-size' && bits[i].indexOf('/') != -1) {
  958. var fsLh = bits[i].split('/');
  959. css[selector]['font-size'] = fsLh[0] + imp;
  960. css[selector]['line-height'] = fsLh[1] + imp;
  961. } else {
  962. css[selector][order[j]] = bits[i] + imp;
  963. }
  964. startProp = j + 1;
  965. break;
  966. }
  967. }
  968. }
  969. };
  970. var removeCommaListSpaces = function(str) {
  971. var comma = str.indexOf(',');
  972. if (comma != -1) {
  973. return str.substr(0, comma) + str.substring(comma).replace(/ +/g, '');
  974. }
  975. return str;
  976. };
  977. var hasQuote = value.match(/(["'])/); //"
  978. if (hasQuote) {
  979. var tmp = value.split(hasQuote[1]);
  980. var bits = removeCommaListSpaces(tmp.shift()).split(' ');
  981. var startFont = bits.pop();
  982. expandShorthand(bits);
  983. css[selector]['font-family'] = startFont + hasQuote[1] + tmp.join(hasQuote[1]) + imp;
  984. } else {
  985. value = removeCommaListSpaces(value);
  986. expandShorthand(value.split(' '));
  987. }
  988. },
  989. __allPropsEqual: function(props) {
  990. var num = props.length - 1;
  991. if (num < 3) return false;
  992. for (var i = 0; i < num; ++i) {
  993. if (props[i].value != props[i + 1].value) {
  994. return false;
  995. }
  996. }
  997. return true;
  998. }
  999. };
  1000. CSS.FreeEdit = {
  1001. __initial: {},
  1002. setInitial: function(e) {
  1003. var target = e.target || e.srcElement;
  1004. CSS.FreeEdit.__initial = CSS.toObject(target.value);
  1005. },
  1006. saveComplete: function(e) {
  1007. var target = e.target || e.srcElement;
  1008. target.value = CSS.FreeEdit.__stripComments(target.value);
  1009. CSS.__localCSS = CSS.__merge(CSS.__localCSS, CSS.toObject(target.value));
  1010. CSS.__localSaveRequired = true;
  1011. CSS.__remoteSaveRequired = true;
  1012. CSS.preview();
  1013. },
  1014. saveSelector: function(e) {
  1015. var target = e.target || e.srcElement;
  1016. target.value = CSS.FreeEdit.__stripComments(target.value);
  1017. var changedSelectors = [];
  1018. var css = CSS.toObject(target.value);
  1019. for (var sel in css) {
  1020. changedSelectors.push(sel);
  1021. if (!CSS.__localCSS[sel]) {
  1022. CSS.__localCSS[sel] = {};
  1023. }
  1024. for (var prop in css[sel]) {
  1025. CSS.__localCSS[sel][prop] = css[sel][prop];
  1026. }
  1027. }
  1028. for (var sel in CSS.FreeEdit.__initial) {
  1029. if (!css[sel] && CSS.__localCSS[sel]) {
  1030. changedSelectors.push(sel);
  1031. CSS.__localCSS[sel] = null;
  1032. delete CSS.__localCSS[sel];
  1033. continue;
  1034. }
  1035. for (var prop in CSS.FreeEdit.__initial[sel]) {
  1036. if (!css[sel][prop] && CSS.__localCSS[sel][prop]) {
  1037. CSS.__localCSS[sel][prop] = null;
  1038. delete CSS.__localCSS[sel][prop];
  1039. }
  1040. }
  1041. }
  1042. CSS.__localSaveRequired = true;
  1043. CSS.__remoteSaveRequired = true;
  1044. CSS.preview(changedSelectors);
  1045. },
  1046. __stripComments: function(str) {
  1047. return str.replace(/\/\*([\s\S])*?\*\//g, '');
  1048. }
  1049. };
  1050. var FileHandler = {
  1051. getFiles: function(path) {
  1052. if (!path) path = '';
  1053. var xmlhttp = new XMLHttpRequest();
  1054. xmlhttp.onreadystatechange = function() {
  1055. if (xmlhttp.readyState == 4) {
  1056. UI.CSS.displayImagePicker(xmlhttp.responseXML);
  1057. xmlhttp = null;
  1058. }
  1059. };
  1060. xmlhttp.open('GET', Config.REMOTE_URI + '&path=' + escape(path) + '&nc=' + new Date().getTime(), true);
  1061. xmlhttp.send(null);
  1062. return true;
  1063. }
  1064. };
  1065. var UI = {
  1066. boxes: [],
  1067. boxOffsetX: 35,
  1068. boxOffsetY: 30,
  1069. zIndex: 9999,
  1070. __dragTargetId: null,
  1071. statusMsg: function(msg, cls) {
  1072. UI.clearStatusMsg();
  1073. var target = UI.__getBox();
  1074. if (!target) {
  1075. var box = Util.createElement('div', 'chameleon-status-msg');
  1076. box.appendChild(document.createTextNode(msg));
  1077. box.style.zIndex = ++UI.zIndex;
  1078. UI.addToDoc(box);
  1079. } else {
  1080. var statusTable = Util.createElement('table', 'chameleon-status-msg');
  1081. var statusTableBody = Util.createElement('tbody');
  1082. var statusRow = Util.createElement('tr');
  1083. var statusIconCell = Util.createElement('td');
  1084. var statusMsgCell = Util.createElement('td');
  1085. var statusBtnCell = Util.createElement('td');
  1086. if (cls) {
  1087. statusIconCell.className = cls;
  1088. }
  1089. statusMsgCell.appendChild(document.createTextNode(msg));
  1090. statusBtnCell.appendChild(UI.createButton('chameleon-status-msg-btn', 'OK',

Large files files are truncated, but you can click here to view the full file