PageRenderTime 39ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/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
  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', 'Clear this message', UI.clearStatusMsg));
  1091. statusRow.appendChild(statusIconCell);
  1092. statusRow.appendChild(statusMsgCell);
  1093. statusRow.appendChild(statusBtnCell);
  1094. statusTableBody.appendChild(statusRow);
  1095. statusTable.appendChild(statusTableBody);
  1096. target.appendChild(statusTable);
  1097. }
  1098. },
  1099. clearStatusMsg: function() {
  1100. var obj = document.getElementById('chameleon-status-msg');
  1101. if (obj) {
  1102. Util.removeElement(obj);
  1103. }
  1104. },
  1105. addToDoc: function(content) {
  1106. document.getElementsByTagName('body')[0].appendChild(content);
  1107. },
  1108. makeDraggableBox: function(id, x, y) {
  1109. if ((x + 500) > screen.width) {
  1110. var offset = x + 525 - screen.width;
  1111. x -= offset;
  1112. }
  1113. var box = Util.createElement('div', id);
  1114. box.style.left = x + 'px';
  1115. box.style.top = y + 'px';
  1116. box.style.zIndex = ++UI.zIndex;
  1117. var topBar = Util.createElement('div', id + '-handle');
  1118. var closeBtn = Util.createElement('div', id + '-close');
  1119. closeBtn.appendChild(document.createTextNode('x'));
  1120. closeBtn.setAttribute('title', 'Close');
  1121. topBar.setAttribute('title', 'Drag me!');
  1122. UI.__dragTargetId = id + '-handle';
  1123. Util.addEvent(closeBtn, 'click', UI.closeBoxes);
  1124. Util.addEvent(topBar, 'mousedown', UI.__startDrag);
  1125. Util.addEvent(topBar, 'mousedown', UI.__bringToFront);
  1126. Util.addEvent(topBar, 'mouseup', UI.__stopDrag);
  1127. topBar.appendChild(closeBtn);
  1128. box.appendChild(topBar);
  1129. UI.boxes.push(id);
  1130. return box;
  1131. },
  1132. closeAllBoxes: function() {
  1133. var n = UI.boxes.length;
  1134. while (n--) {
  1135. Util.removeElement(document.getElementById(UI.boxes[n]));
  1136. UI.boxes.splice(n, 1);
  1137. }
  1138. UI.__dragTargetId = null;
  1139. },
  1140. closeBoxes: function(e, box) {
  1141. if (!box) {
  1142. var target = e.target || e.srcElement;
  1143. var box = target.parentNode.parentNode;
  1144. }
  1145. var n = UI.boxes.length;
  1146. while (n--) {
  1147. if (UI.boxes[n] == box.id) {
  1148. break;
  1149. }
  1150. Util.removeElement(document.getElementById(UI.boxes[n]));
  1151. UI.boxes.splice(n, 1);
  1152. }
  1153. Util.removeElement(box);
  1154. UI.boxes.splice(n, 1);
  1155. UI.__dragTargetId = (UI.boxes.length) ? UI.boxes[UI.boxes.length - 1] + '-handle' : null;
  1156. },
  1157. __startDrag: function(e) {
  1158. var target = e.target || e.srcElement;
  1159. var mouseCoords = Pos.getMouse(e);
  1160. var elementCoords = Pos.getElement(target);
  1161. target.mouseX = mouseCoords.x - elementCoords.x;
  1162. target.mouseY = mouseCoords.y - elementCoords.y;
  1163. UI.__dragTargetId = target.id;
  1164. Util.addEvent(document, 'mousemove', UI.__drag);
  1165. },
  1166. __stopDrag: function(e) {
  1167. Util.removeEvent(document, 'mousemove', UI.__drag);
  1168. },
  1169. __drag: function(e) {
  1170. var target = document.getElementById(UI.__dragTargetId);
  1171. var mouseCoords = Pos.getMouse(e);
  1172. target.parentNode.style.left = (mouseCoords.x - target.mouseX) + 'px';
  1173. target.parentNode.style.top = (mouseCoords.y - target.mouseY) + 'px';
  1174. if (e.preventDefault) {
  1175. e.preventDefault();
  1176. } else if (window.event) {
  1177. window.event.returnValue = false;
  1178. }
  1179. },
  1180. __bringToFront: function(e) {
  1181. var target = e.target || e.srcElement;
  1182. target.parentNode.style.zIndex = ++UI.zIndex;
  1183. },
  1184. __getBox: function() {
  1185. var obj = document.getElementById(UI.__dragTargetId);
  1186. if (obj && obj.parentNode) {
  1187. return obj.parentNode;
  1188. }
  1189. return false;
  1190. },
  1191. setupPane: function(tabs, parentId, tabId, active) {
  1192. for (var i = 0; i < tabs.length; ++i) {
  1193. var obj = document.getElementById(tabId + '-tab-' + tabs[i]);
  1194. if (obj) {
  1195. obj.className = tabId + ((active == tabs[i]) ? '-tab-active' : '-tab');
  1196. }
  1197. }
  1198. var parent = document.getElementById(parentId);
  1199. if (parent && parent.firstChild) {
  1200. Util.removeElement(parent.firstChild);
  1201. }
  1202. return parent;
  1203. },
  1204. setupButtons: function() {
  1205. var parentId = arguments[0];
  1206. var parent = document.getElementById(parentId);
  1207. if (!parent) return;
  1208. var btns = parent.getElementsByTagName('input');
  1209. for (var i = 0; i < btns.length; ++i) {
  1210. btns[i].style.display = 'none';
  1211. }
  1212. for (var i = 1; i < arguments.length; ++i) {
  1213. var id = parentId + '-' + arguments[i];
  1214. var btn = document.getElementById(id);
  1215. if (btn) {
  1216. btn.style.display = 'inline';
  1217. }
  1218. }
  1219. },
  1220. createButton: function(id, value, title, fn, hidden) {
  1221. var btn = Util.createElement('input', id);
  1222. btn.setAttribute('type', 'submit');
  1223. btn.setAttribute('value', value);
  1224. btn.setAttribute('title', title);
  1225. btn.className = 'chameleon-btn';
  1226. if (hidden) {
  1227. btn.style.display = 'none';
  1228. }
  1229. Util.addEvent(btn, 'click', fn);
  1230. return btn;
  1231. },
  1232. setOverflow: function(obj, height, forced) {
  1233. if (obj.offsetHeight > height || forced) {
  1234. obj.style.height = height + 'px';
  1235. obj.style.overflow = 'scroll';
  1236. }
  1237. }
  1238. };
  1239. UI.Selector = {
  1240. controlsId: 'chameleon-selector-controls',
  1241. viewedProp: null,
  1242. displayPropWatch: false,
  1243. sections: ['choose', 'overview', 'free-edit'],
  1244. editWindow: function(e) {
  1245. if (!e.shiftKey) {
  1246. return;
  1247. }
  1248. var target = e.target || e.srcElement;
  1249. var tmpStruct = climbTree(target);
  1250. if (typeof tmpStruct == 'string') {
  1251. return;
  1252. }
  1253. hotspotMode = false;
  1254. var box = document.getElementById('chameleon-selector-box');
  1255. if (box) UI.closeBoxes(true, box);
  1256. struct = tmpStruct;
  1257. CSS.Selector.reset();
  1258. var coords = Pos.getMouse(e);
  1259. var box = UI.makeDraggableBox('chameleon-selector-box', coords.x, coords.y);
  1260. var instructions = Util.createElement('p');
  1261. instructions.appendChild(document.createTextNode('Create a CSS selector to edit, browse an overview of your edited styles or edit your complete stylesheet by hand.'));
  1262. instructions.className = 'chameleon-instructions';
  1263. box.appendChild(instructions);
  1264. var tabsContainer = Util.createElement('table', 'chameleon-selector-tabs');
  1265. var tabsBody = Util.createElement('tbody');
  1266. var tabs = Util.createElement('tr');
  1267. tabs.appendChild(UI.Selector.__createTab('Choose', UI.Selector.__editSelector, true, 'Choose'));
  1268. tabs.appendChild(UI.Selector.__createTab('Overview', UI.Selector.__displayOverview, false, 'Overview'));
  1269. tabs.appendChild(UI.Selector.__createTab('Free Edit', UI.Selector.__editCode, false, 'Free Edit'));
  1270. tabsBody.appendChild(tabs);
  1271. tabsContainer.appendChild(tabsBody);
  1272. box.appendChild(tabsContainer);
  1273. var styleControls = Util.createElement('div', UI.Selector.controlsId);
  1274. box.appendChild(styleControls);
  1275. box.appendChild(UI.Selector.__addButtons());
  1276. UI.addToDoc(box);
  1277. UI.Selector.__editSelector();
  1278. if (e.preventDefault) {
  1279. e.preventDefault();
  1280. } else if (window.event) {
  1281. window.event.returnValue = false;
  1282. }
  1283. },
  1284. __listProps: function(e) {
  1285. var target = e.target || e.srcElement;
  1286. Util.removeElement(document.getElementById('chameleon-selector-element-list'));
  1287. UI.Selector.viewedProp = target.options[target.selectedIndex].value;
  1288. if (!document.getElementById('chameleon-selector-list')) {
  1289. target.parentNode.parentNode.appendChild(UI.Selector.__elementList(target.options[target.selectedIndex].value));
  1290. } else {
  1291. target.parentNode.parentNode.insertBefore(UI.Selector.__elementList(target.options[target.selectedIndex].value), document.getElementById('chameleon-selector-list'));
  1292. }
  1293. },
  1294. __editSelector: function() {
  1295. var parent = UI.setupPane(UI.Selector.sections, UI.Selector.controlsId, 'chameleon-selector', 'choose');
  1296. UI.setupButtons('chameleon-selector-buttons', 'edit', 'check');
  1297. var container = Util.createElement('div');
  1298. var instructions = Util.createElement('p');
  1299. instructions.appendChild(document.createTextNode('Please choose the element you wish to style.'));
  1300. container.appendChild(instructions);
  1301. var options = Util.createElement('p');
  1302. if (UI.Selector.__displayPropWatch) {
  1303. var selectProp = Util.createElement('select', 'chameleon-selector-prop-select');
  1304. var optionProp = Util.createElement('option');
  1305. optionProp.appendChild(document.createTextNode('Select a CSS property to view'));
  1306. optionProp.setAttribute('value', '');
  1307. selectProp.appendChild(optionProp);
  1308. for (var i = 0; i < Config.PROPS_LIST.length; ++i) {
  1309. optionProp = Util.createElement('option');
  1310. optionProp.setAttribute('value', Config.PROPS_LIST[i]);
  1311. if (UI.Selector.viewedProp == Config.PROPS_LIST[i]) {
  1312. optionProp.setAttribute('selected', 'selected');
  1313. }
  1314. optionProp.appendChild(document.createTextNode(Config.PROPS_LIST[i]));
  1315. selectProp.appendChild(optionProp);
  1316. }
  1317. Util.addEvent(selectProp, 'change', UI.Selector.__listProps);
  1318. options.appendChild(selectProp);
  1319. }
  1320. var togglePropWatch = Util.createElement('a');
  1321. togglePropWatch.setAttribute('title', 'The property inspector allows you to check the current value of a range of CSS properties for these elements');
  1322. togglePropWatch.appendChild(document.createTextNode(' (' + (UI.Selector.__displayPropWatch ? 'Hide property inspector' : 'Show property inspector') + ')'));
  1323. Util.addEvent(togglePropWatch, 'click', UI.Selector.__togglePropWatch);
  1324. options.appendChild(togglePropWatch);
  1325. container.appendChild(options);
  1326. container.appendChild(UI.Selector.__elementList());
  1327. parent.appendChild(container);
  1328. UI.Selector.displaySelector(CSS.Selector.trimmed);
  1329. },
  1330. __togglePropWatch: function() {
  1331. UI.Selector.__displayPropWatch = !UI.Selector.__displayPropWatch;
  1332. UI.Selector.__editSelector();
  1333. },
  1334. __displayOverview: function(e, selectors, selector) {
  1335. var parent = UI.setupPane(UI.Selector.sections, UI.Selector.controlsId, 'chameleon-selector', 'overview');
  1336. UI.setupButtons('chameleon-selector-buttons');
  1337. var container = Util.createElement('div', 'chameleon-style-overview-container');
  1338. parent.appendChild(container); // doing it this way is much faster than creating the table then applying the overflow
  1339. UI.setOverflow(container, 350, true);
  1340. var overviewTable = Util.createElement('table', 'chameleon-style-overview');
  1341. var overviewTableBody = Util.createElement('tbody');
  1342. if (!selectors) {
  1343. for (var sel in CSS.__localCSS) {
  1344. var overviewTableRow = Util.createElement('tr');
  1345. var overviewTableCell = Util.createElement('th');
  1346. overviewTableCell.className = 'selector';
  1347. overviewTableCell.appendChild(document.createTextNode(sel));
  1348. overviewTableRow.appendChild(overviewTableCell);
  1349. overviewTableCell = Util.createElement('td');
  1350. var overviewEditLink = Util.createElement('a');
  1351. overviewEditLink.value = sel;
  1352. overviewEditLink.appendChild(document.createTextNode('[edit]'));
  1353. Util.addEvent(overviewEditLink, 'click', UI.CSS.launchEditWindow);
  1354. overviewTableCell.className = 'selector';
  1355. overviewTableCell.appendChild(overviewEditLink);
  1356. overviewTableRow.appendChild(overviewTableCell);
  1357. overviewTableBody.appendChild(overviewTableRow);
  1358. for (var prop in CSS.__localCSS[sel]) {
  1359. overviewTableRow = Util.createElement('tr');
  1360. overviewTableCell = Util.createElement('td');
  1361. overviewTableCell.className = 'prop';
  1362. overviewTableCell.appendChild(document.createTextNode(prop));
  1363. overviewTableRow.appendChild(overviewTableCell);
  1364. overviewTableCell = Util.createElement('td');
  1365. overviewTableCell.className = 'value';
  1366. overviewTableCell.appendChild(document.createTextNode(CSS.__localCSS[sel][prop]));
  1367. overviewTableRow.appendChild(overviewTableCell);
  1368. overviewTableBody.appendChild(overviewTableRow);
  1369. }
  1370. }
  1371. } else {
  1372. var n = selectors.length;
  1373. if (!CSS.__localCSS[selector]) {
  1374. var overviewTableRow = Util.createElement('tr');
  1375. var overviewTableCell = Util.createElement('th');
  1376. overviewTableCell.className = 'current-selector';
  1377. overviewTableCell.appendChild(document.createTextNode(selector));
  1378. overviewTableRow.appendChild(overviewTableCell);
  1379. overviewTableCell = Util.createElement('td');
  1380. var overviewEditLink = Util.createElement('a');
  1381. overviewEditLink.value = selector;
  1382. overviewEditLink.appendChild(document.createTextNode('[edit]'));
  1383. Util.addEvent(overviewEditLink, 'click', UI.CSS.launchEditWindow);
  1384. overviewTableCell.className = 'current-selector';
  1385. overviewTableCell.appendChild(overviewEditLink);
  1386. overviewTableRow.appendChild(overviewTableCell);
  1387. overviewTableBody.appendChild(overviewTableRow);
  1388. }
  1389. for (var i = 0; i < n; ++i) {
  1390. var sel = selectors[i];
  1391. var overviewTableRow = Util.createElement('tr');
  1392. var overviewTableCell = Util.createElement('th');
  1393. overviewTableCell.className = (sel == selector) ? 'current-selector' : 'selector';
  1394. overviewTableCell.appendChild(document.createTextNode(sel));
  1395. overviewTableRow.appendChild(overviewTableCell);
  1396. overviewTableCell = Util.createElement('td');
  1397. var overviewEditLink = Util.createElement('a');
  1398. overviewEditLink.value = sel;
  1399. overviewEditLink.appendChild(document.createTextNode('[edit]'));
  1400. Util.addEvent(overviewEditLink, 'click', UI.CSS.launchEditWindow);
  1401. overviewTableCell.className = (sel == selector) ? 'current-selector' : 'selector';
  1402. overviewTableCell.appendChild(overviewEditLink);
  1403. overviewTableRow.appendChild(overviewTableCell);
  1404. overviewTableBody.appendChild(overviewTableRow);
  1405. for (var prop in CSS.__localCSS[sel]) {
  1406. overviewTableRow = Util.createElement('tr');
  1407. overviewTableCell = Util.createElement('td');
  1408. overviewTableCell.className = 'prop';
  1409. overviewTableCell.appendChild(document.createTextNode(prop));
  1410. overviewTableRow.appendChild(overviewTableCell);
  1411. overviewTableCell = Util.createElement('td');
  1412. overviewTableCell.className = 'value';
  1413. overviewTableCell.appendChild(document.createTextNode(CSS.__localCSS[sel][prop]));
  1414. overviewTableRow.appendChild(overviewTableCell);
  1415. overviewTableBody.appendChild(overviewTableRow);
  1416. }
  1417. }
  1418. }
  1419. overviewTable.appendChild(overviewTableBody);
  1420. container.appendChild(overviewTable);
  1421. },
  1422. __elementList: function(showComputedStyle) {
  1423. if (!showComputedStyle && UI.Selector.viewedProp) {
  1424. showComputedStyle = UI.Selector.viewedProp;
  1425. }
  1426. var list = Util.createElement('ol', 'chameleon-selector-element-list');
  1427. var n = struct.length;
  1428. var classStr = '';
  1429. var idStr = '';
  1430. var pseudoClasses = ['link', 'active', 'visited', 'hover', 'focus'];
  1431. while (n--) {
  1432. var row = n % 2;
  1433. var item = Util.createElement('li');
  1434. item.className = 'row' + row;
  1435. var tag = Util.createElement('span', 'chameleon-tag-name-' + n);
  1436. tag.appendChild(document.createTextNode(struct[n].tagname));
  1437. tag.selectorValue = struct[n].tagname;
  1438. tag.position = n;
  1439. UI.Selector.__autoHighlight(tag);
  1440. Util.addEvent(tag, 'click', CSS.Selector.modify);
  1441. item.appendChild(tag);
  1442. if (idStr = struct[n].id) {
  1443. var id = Util.createElement('span', 'chameleon-id-attr-' + n);
  1444. id.selectorValue = struct[n].tagname + '#' + idStr;
  1445. id.position = n;
  1446. id.appendChild(document.createTextNode('#' + idStr));
  1447. UI.Selector.__autoHighlight(id);
  1448. Util.addEvent(id, 'click', CSS.Selector.modify);
  1449. item.appendChild(id);
  1450. }
  1451. if (struct[n].classname) {
  1452. var classArr = struct[n].classname.split(' ');
  1453. for (var i = 0; i < classArr.length; ++i) {
  1454. var cn = Util.createElement('span', 'chameleon-class-attr-' + n + '-' + i);
  1455. cn.selectorValue = struct[n].tagname + '.' + classArr[i];
  1456. cn.position = n;
  1457. cn.appendChild(document.createTextNode('.' + classArr[i]));
  1458. UI.Selector.__autoHighlight(cn);
  1459. Util.addEvent(cn, 'click', CSS.Selector.modify);
  1460. item.appendChild(cn);
  1461. }
  1462. }
  1463. if (struct[n].tagname == 'a') {
  1464. for (var i = 0; i < pseudoClasses.length; ++i) {
  1465. var pc = Util.createElement('span', 'chameleon-pseudo-class' + n + '-' + i);
  1466. pc.selectorValue = struct[n].tagname + ':' + pseudoClasses[i];
  1467. pc.position = n;
  1468. pc.appendChild(document.createTextNode(':' + pseudoClasses[i]));
  1469. UI.Selector.__autoHighlight(pc);
  1470. Util.addEvent(pc, 'click', CSS.Selector.modify);
  1471. item.appendChild(pc);
  1472. }
  1473. }
  1474. if (showComputedStyle) {
  1475. var sides = ['top', 'right', 'bottom', 'left'];
  1476. if (document.defaultView && document.defaultView.getComputedStyle) {
  1477. if (showComputedStyle == 'margin' || showComputedStyle == 'padding') {
  1478. var styleVal = [];
  1479. for (var i = 0; i < 4; ++i) {
  1480. styleVal.push(document.defaultView.getComputedStyle(struct[n].el, null).getPropertyValue(showComputedStyle + '-' + sides[i]))
  1481. }
  1482. if (styleVal[0] == styleVal[1] && styleVal[1] == styleVal[2] && styleVal[2] == styleVal[3]) {
  1483. styleVal = styleVal[0];
  1484. } else if (styleVal[0] == styleVal[2] && styleVal[1] == styleVal[3]) {
  1485. styleVal = styleVal[0] + ' ' + styleVal[1];
  1486. } else if (styleVal[1] == styleVal[3]) {
  1487. styleVal = styleVal[0] + ' ' + styleVal[1] + ' ' + styleVal[2];
  1488. } else {
  1489. styleVal = styleVal.join(' ');
  1490. }
  1491. } else {
  1492. var styleVal = document.defaultView.getComputedStyle(struct[n].el, null).getPropertyValue(showComputedStyle);
  1493. }
  1494. if (styleVal.indexOf('rgb') != -1) {
  1495. styleVal = UI.Selector.__formatColor(styleVal);
  1496. }
  1497. } else if (struct[n].el.currentStyle) {
  1498. var propBits = showComputedStyle.split('-');
  1499. for (var i = 1; i < propBits.length; ++i) {
  1500. propBits[i] = propBits[i].charAt(0).toUpperCase() + propBits[i].substring(1);
  1501. }
  1502. var styleVal = struct[n].el.currentStyle[propBits.join('')];
  1503. }
  1504. var sp = Util.createElement('span');
  1505. sp.className = 'prop-value';
  1506. sp.appendChild(document.createTextNode(styleVal));
  1507. item.appendChild(sp);
  1508. }
  1509. list.appendChild(item);
  1510. }
  1511. return list;
  1512. },
  1513. __formatColor: function(color) {
  1514. var newColor = '';
  1515. colorBits = color.replace(/rgb\(|[ \)]/g, '').split(',');
  1516. var hexCol = (colorBits[0] << 16 | colorBits[1] << 8 | colorBits[2]).toString(16);
  1517. while (hexCol.length < 6) {
  1518. hexCol = '0' + hexCol;
  1519. }
  1520. return '#' + hexCol;
  1521. },
  1522. __editCode: function() {
  1523. var parent = UI.setupPane(UI.Selector.sections, UI.Selector.controlsId, 'chameleon-selector', 'free-edit');
  1524. UI.setupButtons('chameleon-selector-buttons', 'revert', 'save-local', 'save-server');
  1525. var container = Util.createElement('div');
  1526. var textarea = Util.createElement('textarea', 'chameleon-free-edit-all-field');
  1527. textarea.style.width = '100%';
  1528. textarea.style.height = '350px';
  1529. Util.addEvent(textarea, 'blur', CSS.FreeEdit.saveComplete);
  1530. container.appendChild(textarea);
  1531. parent.appendChild(container);
  1532. textarea.value = CSS.toString(); // avoid Konqueror bug
  1533. },
  1534. __selectorList: function() {
  1535. return Util.createElement('ol', 'chameleon-selector-list');
  1536. },
  1537. __createTab: function(str, fn, active, title) {
  1538. var id = 'chameleon-selector-tab-' + str.replace(/ +/, '-').toLowerCase();
  1539. var tab = Util.createElement('td', id);
  1540. tab.appendChild(document.createTextNode(((title) ? title : str)));
  1541. tab.className = (active) ? 'chameleon-selector-tab-active' : 'chameleon-selector-tab';
  1542. Util.addEvent(tab, 'click', fn);
  1543. return tab;
  1544. },
  1545. __addButtons: function() {
  1546. var p = Util.createElement('p', 'chameleon-selector-buttons');
  1547. p.style.textAlign = 'right';
  1548. p.appendChild(UI.createButton('chameleon-selector-buttons-check', 'Compare', 'Check for other similar selectors already in your styles', CSS.checkSpec));
  1549. p.appendChild(UI.createButton('chameleon-selector-buttons-revert', 'Revert', 'Revert to the version currently on the server', CSS.hardReset));
  1550. p.appendChild(UI.createButton('chameleon-selector-buttons-save-local', 'Save Temp', 'Save these changes to a temporary file on the server', CSS.updateTemp));
  1551. p.appendChild(UI.createButton('chameleon-selector-buttons-save-server', 'Save Server', 'Save these changes to the server', CSS.updateRemote))
  1552. p.appendChild(UI.createButton('chameleon-selector-buttons-edit', 'Set Styles', 'Create and edit styles for this CSS selector', UI.CSS.editWindow));
  1553. return p;
  1554. },
  1555. __autoHighlight: function(el) {
  1556. if (CSS.Selector.full[el.position] && CSS.Selector.full[el.position].val == el.selectorValue) {
  1557. UI.Selector.highlight(el);
  1558. } else {
  1559. UI.Selector.unhighlight(el);
  1560. }
  1561. },
  1562. highlight: function(el) {
  1563. UI.Selector.unhighlight(el);
  1564. el.className += 'active-selector';
  1565. },
  1566. unhighlight: function(el) {
  1567. el.className = el.className.replace(/\bactive-selector\b/, '');
  1568. },
  1569. displaySelector: function(selector) {
  1570. var n = selector.length;
  1571. var list = document.getElementById('chameleon-selector-list');
  1572. if (!list && n != 0) {
  1573. var parent = document.getElementById(UI.Selector.controlsId).firstChild;
  1574. list = UI.Selector.__selectorList();
  1575. parent.appendChild(list);
  1576. } else if (list && n == 0) {
  1577. Util.removeElement(list);
  1578. } else if (list) {
  1579. while (list.hasChildNodes()) {
  1580. Util.removeElement(list.firstChild);
  1581. }
  1582. }
  1583. if (n == 0) return;
  1584. var item = Util.createElement('li');
  1585. item.appendChild(document.createTextNode('Style ' + UI.Selector.__describe(selector[--n])));
  1586. list.appendChild(item);
  1587. while (n--) {
  1588. item = Util.createElement('li');
  1589. item.appendChild(document.createTextNode('That are descended from ' + UI.Selector.__describe(selector[n])));
  1590. list.appendChild(item);
  1591. }
  1592. UI.setOverflow(list, 100);
  1593. },
  1594. __describe: function(txt) {
  1595. if (!txt) return '';
  1596. if (txt.indexOf(':') != -1) {
  1597. var parts = txt.split(':');
  1598. var pc = ' the "' + parts.pop() + '" state of ';
  1599. txt = parts.shift();
  1600. } else {
  1601. var pc = '';
  1602. }
  1603. if (txt.indexOf('#') != -1) {
  1604. var parts = txt.split('#');
  1605. return pc + parts[0] + ' tags with the id "' + parts[1] + '"';
  1606. }
  1607. if (txt.indexOf('.') != -1) {
  1608. var parts = txt.split('.');
  1609. return pc + parts[0] + ' tags with the class "' + parts[1] + '"';
  1610. }
  1611. return pc + txt + ' tags';
  1612. }
  1613. };
  1614. UI.CSS = {
  1615. redraw: null,
  1616. colorType: null,
  1617. controlsId: 'chameleon-style-controls',
  1618. sections: ['text', 'backgrounds', 'borders-all', 'borders-separate', 'free-edit'],
  1619. __borderEditGroup: true,
  1620. editWindow: function(e) {
  1621. if (CSS.Selector.get() == '') {
  1622. UI.statusMsg('First you have to choose which item to style!', 'chameleon-notice');
  1623. return;
  1624. }
  1625. var box = document.getElementById('chameleon-style-box');
  1626. if (box) UI.closeBoxes(true, box);
  1627. var coords = Pos.getElement(document.getElementById('chameleon-selector-box'));
  1628. var box = UI.makeDraggableBox('chameleon-style-box', coords.x + UI.boxOffsetX, coords.y + UI.boxOffsetY);
  1629. var instructions = Util.createElement('p');
  1630. if (!hotspotMode) {
  1631. instructions.appendChild(document.createTextNode('Add/Edit styles for the CSS selector "' + CSS.Selector.get() + '"'));
  1632. } else {
  1633. instructions.appendChild(document.createTextNode('Add/Edit styles for ' + UI.HotSpots.getString()));
  1634. }
  1635. instructions.className = 'chameleon-instructions';
  1636. box.appendChild(instructions);
  1637. var tabsContainer = Util.createElement('table', 'chameleon-style-tabs');
  1638. var tabsBody = Util.createElement('tbody');
  1639. var tabs = Util.createElement('tr');
  1640. tabs.appendChild(UI.CSS.__createTab('Text', UI.CSS.__editText, true, 'Text'));
  1641. tabs.appendChild(UI.CSS.__createTab('Backgrounds', UI.CSS.__editBackgrounds, false, 'Backgrounds'));
  1642. tabs.appendChild(UI.CSS.__createTab('Borders (All)', UI.CSS.__editBordersAll, false, 'Borders (All)'));
  1643. tabs.appendChild(UI.CSS.__createTab('Borders (Separate)', UI.CSS.__editBordersSeparate, false, 'Borders (Separate)'));
  1644. tabs.appendChild(UI.CSS.__createTab('Free Edit', UI.CSS.__editCode, false, 'Free Edit'));
  1645. tabsBody.appendChild(tabs);
  1646. tabsContainer.appendChild(tabsBody);
  1647. box.appendChild(tabsContainer);
  1648. var styleControls = Util.createElement('div', UI.CSS.controlsId);
  1649. box.appendChild(styleControls);
  1650. box.appendChild(UI.CSS.__addButtons());
  1651. UI.addToDoc(box);
  1652. UI.CSS.__editText();
  1653. },
  1654. launchEditWindow: function(e) {
  1655. var target = e.target || e.srcElement;
  1656. CSS.Selector.set(target.value);
  1657. UI.CSS.editWindow(e);
  1658. },
  1659. __editText: function(e, redraw) {
  1660. UI.CSS.redraw = arguments.callee;
  1661. UI.CSS.colorType = 'color';
  1662. var containerTable = document.getElementById('chameleon-style-edit-text-container');
  1663. if (!containerTable) {
  1664. var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'text');
  1665. containerTable = Util.createElement('table', 'chameleon-style-edit-text-container');
  1666. var container = Util.createElement('tbody');
  1667. var row = UI.CSS.__inputField('color', '-input-color', Check.color);
  1668. container.appendChild(row.node);
  1669. row = UI.CSS.__selectBox('font-family', '-select-font-family', Check.fontFamily, Config.FONTS_LIST);
  1670. container.appendChild(row.node);
  1671. row = UI.CSS.__inputField('font-family', '-input-font-family', Check.fontFamily, !row.meta.sel);
  1672. container.appendChild(row.node);
  1673. row = UI.CSS.__inputField('font-size', '-input-font-size', Check.fontSize);
  1674. container.appendChild(row.node);
  1675. row = UI.CSS.__inputField('line-height', '-input-line-height', Check.lineHeight);
  1676. container.appendChild(row.node);
  1677. row = UI.CSS.__selectBox('font-weight', '-select-font-weight', Check.fontWeight, Config.FONT_WEIGHTS);
  1678. container.appendChild(row.node);
  1679. row = UI.CSS.__selectBox('font-style', '-select-font-style', Check.fontStyle, Config.FONT_STYLES);
  1680. container.appendChild(row.node);
  1681. row = UI.CSS.__selectBox('text-align', '-select-text-align', Check.textAlign, Config.TEXT_ALIGN);
  1682. container.appendChild(row.node);
  1683. row = UI.CSS.__selectBox('text-decoration', '-select-text-decoration', Check.textDecoration, Config.TEXT_DECORATION);
  1684. container.appendChild(row.node);
  1685. containerTable.appendChild(container);
  1686. parent.appendChild(containerTable);
  1687. } else {
  1688. if (redraw == 'color') {
  1689. UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
  1690. }
  1691. }
  1692. },
  1693. __editBackgrounds: function(e, redraw) {
  1694. UI.CSS.redraw = arguments.callee;
  1695. UI.CSS.colorType = 'background-color';
  1696. var containerTable = document.getElementById('chameleon-style-edit-backgrounds-container');
  1697. if (!containerTable) {
  1698. var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'backgrounds');
  1699. containerTable = Util.createElement('table', 'chameleon-style-edit-backgrounds-container');
  1700. var container = Util.createElement('tbody');
  1701. var row = UI.CSS.__inputField('background-color', '-input-background-color', Check.color);
  1702. container.appendChild(row.node);
  1703. row = UI.CSS.__inputField('background-image', '-input-background-image', Check.backgroundImage);
  1704. container.appendChild(row.node);
  1705. var extraFields = row.meta;
  1706. row = UI.CSS.__selectBox('background-repeat', '-select-background-repeat', Check.backgroundRepeat, Config.REPEAT_LIST, !extraFields);
  1707. container.appendChild(row.node);
  1708. row = UI.CSS.__selectBox('background-position', '-select-background-position', Check.backgroundPosition, Config.POSITION_LIST, !extraFields);
  1709. container.appendChild(row.node);
  1710. containerTable.appendChild(container);
  1711. parent.appendChild(containerTable);
  1712. } else {
  1713. if (redraw == 'color') {
  1714. UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
  1715. } else if (redraw == 'image') {
  1716. var val = UI.CSS.__getPropValue('background-image');
  1717. UI.CSS.__setImageDisplay(val);
  1718. if (val == 'none' || val == '') {
  1719. document.getElementById(UI.CSS.controlsId + '-row-select-background-repeat').style.display = 'none';
  1720. document.getElementById(UI.CSS.controlsId + '-row-select-background-position').style.display = 'none';
  1721. } else {
  1722. try {
  1723. document.getElementById(UI.CSS.controlsId + '-row-select-background-repeat').style.display = 'table-row';
  1724. document.getElementById(UI.CSS.controlsId + '-row-select-background-position').style.display = 'table-row';
  1725. } catch(e) {
  1726. document.getElementById(UI.CSS.controlsId + '-row-select-background-repeat').style.display = 'block';
  1727. document.getElementById(UI.CSS.controlsId + '-row-select-background-position').style.display = 'block';
  1728. }
  1729. }
  1730. }
  1731. }
  1732. var imgPreview = document.getElementById('chameleon-image-preview');
  1733. if (imgPreview) {
  1734. imgPreview.setAttribute('width', '20');
  1735. imgPreview.setAttribute('height', '20');
  1736. }
  1737. },
  1738. __editBordersAll: function(e, redraw) {
  1739. UI.CSS.redraw = arguments.callee;
  1740. UI.CSS.colorType = 'border-color';
  1741. var containerTable = document.getElementById('chameleon-style-edit-borders-all-container');
  1742. if (!containerTable) {
  1743. var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'borders-all');
  1744. containerTable = Util.createElement('table', 'chameleon-style-edit-borders-all-container');
  1745. var container = Util.createElement('tbody');
  1746. var row = UI.CSS.__inputField('border-width', '-input-border-width', Check.borderWidth);
  1747. container.appendChild(row.node);
  1748. row = UI.CSS.__inputField('border-color', '-input-border-color', Check.color);
  1749. container.appendChild(row.node);
  1750. row = UI.CSS.__selectBox('border-style', '-select-border-style', Check.borderStyle, Config.BORDER_LIST);
  1751. container.appendChild(row.node);
  1752. containerTable.appendChild(container);
  1753. parent.appendChild(containerTable);
  1754. } else {
  1755. if (redraw == 'color') {
  1756. UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
  1757. }
  1758. }
  1759. },
  1760. __editBordersSeparate: function(e, redraw) {
  1761. UI.CSS.redraw = arguments.callee;
  1762. var containerTable = document.getElementById('chameleon-style-edit-borders-separate-container');
  1763. if (!containerTable) {
  1764. var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'borders-separate');
  1765. containerTable = Util.createElement('table', 'chameleon-style-edit-borders-separate-container');
  1766. var container = Util.createElement('tbody');
  1767. var row = UI.CSS.__inputField('border-top-width', '-input-border-top-width', Check.borderWidth);
  1768. container.appendChild(row.node);
  1769. row = UI.CSS.__inputField('border-top-color', '-input-border-top-color', Check.color, false, UI.CSS.__setColorType);
  1770. container.appendChild(row.node);
  1771. row = UI.CSS.__selectBox('border-top-style', '-select-border-top-style', Check.borderStyle, Config.BORDER_LIST);
  1772. container.appendChild(row.node);
  1773. row = UI.CSS.__inputField('border-right-width', '-input-border-right-width', Check.borderWidth);
  1774. container.appendChild(row.node);
  1775. row = UI.CSS.__inputField('border-right-color', '-input-border-right-color', Check.color, false, UI.CSS.__setColorType);
  1776. container.appendChild(row.node);
  1777. row = UI.CSS.__selectBox('border-right-style', '-select-border-right-style', Check.borderStyle, Config.BORDER_LIST);
  1778. container.appendChild(row.node);
  1779. row = UI.CSS.__inputField('border-bottom-width', '-input-border-bottom-width', Check.borderWidth);
  1780. container.appendChild(row.node);
  1781. row = UI.CSS.__inputField('border-bottom-color', '-input-border-bottom-color', Check.color, false, UI.CSS.__setColorType);
  1782. container.appendChild(row.node);
  1783. row = UI.CSS.__selectBox('border-bottom-style', '-select-border-bottom-style', Check.borderStyle, Config.BORDER_LIST);
  1784. container.appendChild(row.node);
  1785. row = UI.CSS.__inputField('border-left-width', '-input-border-left-width', Check.borderWidth);
  1786. container.appendChild(row.node);
  1787. row = UI.CSS.__inputField('border-left-color', '-input-border-left-color', Check.color, false, UI.CSS.__setColorType);
  1788. container.appendChild(row.node);
  1789. row = UI.CSS.__selectBox('border-left-style', '-select-border-left-style', Check.borderStyle, Config.BORDER_LIST);
  1790. container.appendChild(row.node);
  1791. containerTable.appendChild(container);
  1792. parent.appendChild(containerTable);
  1793. } else {
  1794. if (redraw == 'color') {
  1795. UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
  1796. }
  1797. }
  1798. },
  1799. __editCode: function(e) {
  1800. UI.CSS.redraw = arguments.callee;
  1801. var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'free-edit');
  1802. var container = Util.createElement('div');
  1803. var textarea = Util.createElement('textarea', 'chameleon-free-edit-field');
  1804. textarea.style.width = '100%';
  1805. textarea.style.height = '350px';
  1806. Util.addEvent(textarea, 'focus', CSS.FreeEdit.setInitial);
  1807. Util.addEvent(textarea, 'blur', CSS.FreeEdit.saveSelector);
  1808. container.appendChild(textarea);
  1809. parent.appendChild(container);
  1810. textarea.value = CSS.getSelectorCSS(); // avoid Konqueror bug
  1811. },
  1812. __getPropValue: function(prop) {
  1813. var val = UI.CSS.__getBorderPropValue(prop);
  1814. if (val === '') {
  1815. return false;
  1816. }
  1817. if (val === false) {
  1818. val = CSS.getPropValue(prop);
  1819. }
  1820. return val;
  1821. },
  1822. __setColorDisplay: function(prop, value, field, picker) {
  1823. if (!field) var field = document.getElementById(UI.CSS.controlsId + '-input-' + prop);
  1824. if (!picker) var picker = document.getElementById(UI.CSS.controlsId + '-color-picker-' + prop);
  1825. if (!field || !picker) return;
  1826. field.value = value;
  1827. try {
  1828. picker.style.backgroundColor = (value != '') ? value.replace(/[ ]*\!important/, '') : '#000';
  1829. if (!picker.style.backgroundColor) {
  1830. UI.statusMsg(value + ' is an Invalid color!', 'chameleon-error');
  1831. }
  1832. } catch(e) {
  1833. UI.statusMsg(value + ' is an Invalid color!', 'chameleon-error');
  1834. }
  1835. },
  1836. __setImageDisplay: function(value, field, picker) {
  1837. if (!field) var field = document.getElementById(UI.CSS.controlsId + '-input-background-image');
  1838. if (!picker) var picker = document.getElementById(UI.CSS.controlsId + '-background-image-picker');
  1839. var preview = document.getElementById('chameleon-image-preview');
  1840. if (!field || !picker) return;
  1841. field.value = value;
  1842. if (value != '') {
  1843. if (!preview) {
  1844. preview = Util.createElement('img', 'chameleon-image-preview');
  1845. picker.appendChild(preview);
  1846. }
  1847. if (field.value != 'none') {
  1848. preview.setAttribute('src', CSS.fixPath(value.replace(/[ ]*\!important/, '')));
  1849. } else {
  1850. preview.setAttribute('src', CSS.fixPath('ui/images/none.gif'));
  1851. }
  1852. preview.setAttribute('title', 'Open image picker');
  1853. Util.addEvent(preview, 'click', UI.CSS.__loadImagePicker);
  1854. picker.style.backgroundColor = 'transparent';
  1855. } else {
  1856. if (preview) {
  1857. Util.removeElement(preview);
  1858. }
  1859. picker.style.backgroundColor = '#000';
  1860. picker.setAttribute('title', 'Open image picker');
  1861. Util.addEvent(picker, 'click', UI.CSS.__loadImagePicker);
  1862. }
  1863. },
  1864. __shorthandWarningIcon: function() {
  1865. var img = Util.createElement('img');
  1866. img.setAttribute('src', CSS.fixPath('ui/images/notice.gif'));
  1867. img.style.margin = '0 2px -5px 0';
  1868. img.setAttribute('title', 'Currently this property has specific values set for one or more individual sides. Updating the value here will set this property for all sides, overwriting these individual values.');
  1869. return img;
  1870. },
  1871. __inputField: function(prop, id, validate, hidden, init) {
  1872. var row = Util.createElement('tr', UI.CSS.controlsId + '-row' + id);
  1873. id = UI.CSS.controlsId + id;
  1874. var labelCell = Util.createElement('td');
  1875. var fieldCell = Util.createElement('td');
  1876. var field = Util.createElement('input', id);
  1877. field.setAttribute('type', 'text');
  1878. field.className = 'chameleon-input-text';
  1879. var val = UI.CSS.__getPropValue(prop);
  1880. if (val !== false) {
  1881. field.value = val;
  1882. } else {
  1883. labelCell.appendChild(UI.CSS.__shorthandWarningIcon());
  1884. }
  1885. Util.addEvent(field, 'blur', validate);
  1886. if (init) {
  1887. Util.addEvent(field, 'focus', init);
  1888. }
  1889. labelCell.appendChild(document.createTextNode(UI.CSS.__formatProp(prop) + ': '));
  1890. labelCell.className = 'label';
  1891. fieldCell.appendChild(field);
  1892. row.appendChild(labelCell);
  1893. row.appendChild(fieldCell);
  1894. if (prop == 'color' || prop.indexOf('-color') != -1) {
  1895. var colorCell = Util.createElement('td');
  1896. var colorPicker = Util.createElement('div', UI.CSS.controlsId + '-color-picker-' + prop);
  1897. colorPicker.setAttribute('title', 'Open color picker');
  1898. UI.CSS.__setColorDisplay(prop, field.value, field, colorPicker);
  1899. Util.addEvent(colorPicker, 'click', UI.CSS.__displayColorPicker);
  1900. if (init) {
  1901. Util.addEvent(colorPicker, 'click', init);
  1902. }
  1903. colorCell.appendChild(colorPicker);
  1904. row.appendChild(colorCell);
  1905. } else if (prop.indexOf('-image') != -1) {
  1906. var imgCell = Util.createElement('td');
  1907. var imgPicker = Util.createElement('div', UI.CSS.controlsId + '-background-image-picker');
  1908. UI.CSS.__setImageDisplay(field.value, field, imgPicker);
  1909. imgCell.appendChild(imgPicker);
  1910. row.appendChild(imgCell);
  1911. } else {
  1912. fieldCell.setAttribute('colspan', '2');
  1913. }
  1914. if (hidden) {
  1915. row.style.display = 'none';
  1916. }
  1917. return {node: row, meta: (field.value == 'none') ? false : field.value};
  1918. },
  1919. __selectBox: function(prop, id, validate, src, hidden) {
  1920. var row = Util.createElement('tr', UI.CSS.controlsId + '-row' + id);
  1921. id = UI.CSS.controlsId + id;
  1922. var labelCell = Util.createElement('td');
  1923. var fieldCell = Util.createElement('td');
  1924. fieldCell.setAttribute('colspan', '2');
  1925. var currentValue = UI.CSS.__getPropValue(prop);
  1926. if (currentValue === false) {
  1927. labelCell.appendChild(UI.CSS.__shorthandWarningIcon());
  1928. currentValue = '';
  1929. }
  1930. labelCell.appendChild(document.createTextNode(UI.CSS.__formatProp(prop) + ': '));
  1931. labelCell.className = 'label';
  1932. var field = Util.createElement('select', id);
  1933. var op = Util.createElement('option');
  1934. op.setAttribute('value', '');
  1935. op.appendChild(document.createTextNode('Please select'));
  1936. field.appendChild(op);
  1937. var selected = false;
  1938. var otherSelected = false;
  1939. for (var i = 0; i < src.length; ++i) {
  1940. op = Util.createElement('option');
  1941. op.setAttribute('value', src[i]);
  1942. op.appendChild(document.createTextNode(src[i]));
  1943. if (src[i] != 'other' && src[i] == currentValue) {
  1944. op.setAttribute('selected', 'selected');
  1945. selected = true;
  1946. } else if (src[i].toLowerCase() == 'other' && currentValue != '' && !selected) {
  1947. op.setAttribute('selected', 'selected');
  1948. selected = true;
  1949. otherSelected = true;
  1950. }
  1951. field.appendChild(op);
  1952. }
  1953. Util.addEvent(field, 'change', validate);
  1954. fieldCell.appendChild(field);
  1955. row.appendChild(labelCell);
  1956. row.appendChild(fieldCell);
  1957. if (hidden) {
  1958. row.style.display = 'none';
  1959. }
  1960. return {node: row, meta: {sel: otherSelected, value: currentValue}};
  1961. },
  1962. __createTab: function(str, fn, active, title) {
  1963. var id = 'chameleon-style-tab-' + str.replace(/[\( ]+/, '-').replace(/[\)]+/, '').toLowerCase();
  1964. var tab = Util.createElement('td', id);
  1965. tab.appendChild(document.createTextNode((title) ? title : str));
  1966. tab.className = (active) ? 'chameleon-style-tab-active' : 'chameleon-style-tab';
  1967. Util.addEvent(tab, 'click', fn);
  1968. return tab;
  1969. },
  1970. __addButtons: function() {
  1971. var p = Util.createElement('p', 'chameleon-style-buttons');
  1972. p.style.textAlign = 'right';
  1973. p.appendChild(UI.createButton('chameleon-style-buttons-revert', 'Revert', 'Discard all temporarily saved changes', CSS.hardReset));
  1974. p.appendChild(UI.createButton('chameleon-style-buttons-save-local', 'Save Temp', 'Save these changes in a temporary file on the server', CSS.updateTemp));
  1975. p.appendChild(UI.createButton('chameleon-style-buttons-save-server', 'Save Server', 'Save these changes to the server', CSS.updateRemote));
  1976. return p;
  1977. },
  1978. __formatProp: function(txt) {
  1979. if (txt.length > 15 && txt.indexOf('-') != -1) {
  1980. return txt.split('-').slice(1).join('-');
  1981. }
  1982. return txt;
  1983. },
  1984. __loadImagePicker: function(e) {
  1985. var target = e.target || e.srcElement;
  1986. if (target.value) {
  1987. UI.statusMsg('Loading file list for ' + target.value + '...', 'chameleon-working');
  1988. FileHandler.getFiles(target.value);
  1989. } else {
  1990. UI.statusMsg('Loading file list...', 'chameleon-working');
  1991. FileHandler.getFiles('root');
  1992. }
  1993. },
  1994. displayImagePicker: function(xmldata) {
  1995. UI.clearStatusMsg();
  1996. var box = document.getElementById('chameleon-file-box');
  1997. if (box) UI.closeBoxes(true, box);
  1998. var coords = Pos.getElement(document.getElementById('chameleon-style-box'));
  1999. box = UI.makeDraggableBox('chameleon-file-box', coords.x + UI.boxOffsetX, coords.y + UI.boxOffsetY);
  2000. if (xmldata.firstChild.nodeName.toLowerCase() == 'chameleon_error') {
  2001. UI.statusMsg('There was an error reading files from the server:\n' + xmldata.firstChild.firstChild.nodeValue + '.', 'chameleon-error');
  2002. return;
  2003. }
  2004. var files = xmldata.firstChild;
  2005. var hasFiles = false;
  2006. var infoTable = Util.createElement('table');
  2007. var infoTableBody = Util.createElement('tbody');
  2008. var infoTableRow = Util.createElement('tr');
  2009. var path = files.getAttribute('path');
  2010. if (path.indexOf('/') != -1) {
  2011. var parentPath = path.substring(0, path.lastIndexOf('/'));
  2012. var parentCell = Util.createElement('td');
  2013. var parentLink = Util.createElement('p', 'chameleon-files-parent');
  2014. parentLink.value = parentPath;
  2015. parentLink.className = 'chameleon-image-folder';
  2016. parentLink.appendChild(document.createTextNode('Parent folder'));
  2017. Util.addEvent(parentLink, 'click', UI.CSS.__loadImagePicker);
  2018. parentCell.appendChild(parentLink);
  2019. infoTableRow.appendChild(parentCell);
  2020. }
  2021. var location = Util.createElement('td', 'chameleon-files-location');
  2022. var locationPara = Util.createElement('p');
  2023. var locationTxt = Util.createElement('span');
  2024. locationTxt.appendChild(document.createTextNode('Location: '));
  2025. locationPara.appendChild(locationTxt);
  2026. locationPara.appendChild(document.createTextNode(path));
  2027. location.appendChild(locationPara);
  2028. infoTableRow.appendChild(location);
  2029. infoTableBody.appendChild(infoTableRow);
  2030. infoTable.appendChild(infoTableBody);
  2031. box.appendChild(infoTable);
  2032. var fileList = Util.createElement('div');
  2033. for (var i = 0; i < files.childNodes.length; ++i) {
  2034. if (files.childNodes[i].nodeType != Node.ELEMENT_NODE) {
  2035. continue;
  2036. }
  2037. hasFiles = true;
  2038. var fileItemContainer = Util.createElement('p');
  2039. var fileItem = Util.createElement('span');
  2040. fileItem.value = files.childNodes[i].firstChild.nodeValue;
  2041. fileItem.appendChild(document.createTextNode(fileItem.value.split('/').pop()));
  2042. if (files.childNodes[i].getAttribute('type') == 'img') {
  2043. Util.addEvent(fileItem, 'click', Check.backgroundImage);
  2044. } else {
  2045. fileItemContainer.className = 'chameleon-image-folder';
  2046. Util.addEvent(fileItem, 'click', UI.CSS.__loadImagePicker);
  2047. }
  2048. fileItemContainer.appendChild(fileItem);
  2049. fileList.appendChild(fileItemContainer);
  2050. }
  2051. if (!hasFiles) {
  2052. var fileItem = Util.createElement('p');
  2053. fileItem.appendChild(document.createTextNode('No images were found in this folder'));
  2054. fileList.appendChild(fileItem);
  2055. }
  2056. box.appendChild(fileList);
  2057. UI.addToDoc(box);
  2058. UI.setOverflow(fileList, 350);
  2059. },
  2060. __displayColorPicker: function(e) {
  2061. var box = document.getElementById('chameleon-color-box');
  2062. if (box) UI.closeBoxes(true, box);
  2063. var extraColors = ['000000', '333333', '666666', '999999', 'cccccc', 'ffffff', 'ff0000', '00ff00', '0000ff', 'ffff00', 'ff00ff', '00ffff'];
  2064. var coords = Pos.getElement(document.getElementById('chameleon-style-box'));
  2065. box = UI.makeDraggableBox('chameleon-color-box', coords.x + UI.boxOffsetX, coords.y + UI.boxOffsetY);
  2066. var container = Util.createElement('div', 'chameleon-color-palette');
  2067. box.appendChild(container);
  2068. var x = 0; var y = 0; var xx = 0; var yi = 0;
  2069. for (var r = 0; r < 256; r += 51) {
  2070. for (var g = 0; g < 256; g += 51) {
  2071. for (var b = 0; b < 256; b += 51) {
  2072. var col = (r << 16 | g << 8 | b).toString(16);
  2073. while (col.length < 6) {
  2074. col = '0' + col;
  2075. }
  2076. yi = (xx > 17) ? 5 : 0;
  2077. var colorTab = Util.createElement('div');
  2078. colorTab.style.position = 'absolute';
  2079. colorTab.style.left = ((15 * x) + 17) + 'px';
  2080. colorTab.style.top = (15 * (yi + y)) + 'px';
  2081. colorTab.style.width = colorTab.style.height = '15px';
  2082. colorTab.style.backgroundColor = colorTab.value = '#' + col;
  2083. colorTab.setAttribute('title', '#' + col);
  2084. container.appendChild(colorTab);
  2085. if (x == 17) {
  2086. x = 0;
  2087. if (xx == 35) {
  2088. xx = 0;
  2089. } else {
  2090. ++xx;
  2091. ++y;
  2092. }
  2093. } else {
  2094. ++x;
  2095. ++xx;
  2096. }
  2097. }
  2098. }
  2099. }
  2100. for (var i = 0; i < extraColors.length; ++i) {
  2101. var colorTab = Util.createElement('div');
  2102. colorTab.style.position = 'absolute';
  2103. colorTab.style.left = '0px';
  2104. colorTab.style.top = (15 * i) + 'px';
  2105. colorTab.style.width = colorTab.style.height = '15px';
  2106. colorTab.style.backgroundColor = colorTab.value = '#' + extraColors[i];
  2107. colorTab.setAttribute('title', '#' + extraColors[i]);
  2108. container.appendChild(colorTab);
  2109. }
  2110. Util.addEvent(container, 'click', Check.color);
  2111. container.style.height = (((y + yi) * 15) + 20) + 'px';
  2112. UI.addToDoc(box);
  2113. },
  2114. __setColorType: function(e) {
  2115. var target = e.target || e.srcElement;
  2116. UI.CSS.colorType = UI.CSS.getBorderProp(target.id);
  2117. },
  2118. getBorderProp: function(id) {
  2119. var separators = ['color-picker', 'input', 'select'];
  2120. for (var i = 0; i < separators.length; ++i) {
  2121. if (id.indexOf('-' + separators[i] + '-') != -1) {
  2122. return id.split('-' + separators[i] + '-').pop();
  2123. }
  2124. }
  2125. return '';
  2126. },
  2127. __getBorderPropValue: function(prop) {
  2128. var matches = prop.match(/^border\-([^\-]+)$/);
  2129. if (matches) {
  2130. var p1 = CSS.getPropValue('border-left-' + matches[1]);
  2131. var p2 = CSS.getPropValue('border-right-' + matches[1]);
  2132. var p3 = CSS.getPropValue('border-top-' + matches[1]);
  2133. var p4 = CSS.getPropValue('border-bottom-' + matches[1]);
  2134. if (!p1 && !p2 && !p3 && !p4) {
  2135. return false;
  2136. }
  2137. if (!(p1 && p2 && p3 && p4)) {
  2138. return '';
  2139. }
  2140. return (p1 == p2 && p2 == p3 && p3 == p4) ? p1 : '';
  2141. }
  2142. return false;
  2143. }
  2144. };
  2145. UI.HotSpots = {
  2146. __selectors: null,
  2147. __counter: 0,
  2148. __lookup: {},
  2149. init: function() {
  2150. var box = Util.createElement('div', 'chameleon-launch-hotspots');
  2151. box.appendChild(document.createTextNode('Load hotspots'));
  2152. box.style.zIndex = ++UI.zIndex;
  2153. box.hotSpotsOn = false;
  2154. Util.addEvent(box, 'click', UI.HotSpots.__load);
  2155. UI.addToDoc(box);
  2156. },
  2157. getString: function() {
  2158. var sel = CSS.Selector.get();
  2159. if (UI.HotSpots.__selectors[sel]) {
  2160. return UI.HotSpots.__selectors[sel] + '.';
  2161. }
  2162. return '"' + sel + '"';
  2163. },
  2164. __load: function(e) {
  2165. var target = e.target || e.srcElement;
  2166. target.hotSpotsOn = !target.hotSpotsOn;
  2167. UI.HotSpots.__counter = 0;
  2168. UI.HotSpots.__lookup = {};
  2169. if (!target.hotSpotsOn) {
  2170. target.firstChild.nodeValue = 'Show hotspots';
  2171. UI.HotSpots.__clear();
  2172. return;
  2173. }
  2174. target.firstChild.nodeValue = 'Hide hotspots';
  2175. if (!UI.HotSpots.__selectors) {
  2176. UI.HotSpots.__selectors = {};
  2177. UI.HotSpots.__selectors['body'] = 'The body of the page (all pages)';
  2178. UI.HotSpots.__selectors['body#site-index'] = 'The body of the homepage';
  2179. UI.HotSpots.__selectors['body#course-view'] = 'The body of the course index page';
  2180. UI.HotSpots.__selectors['div#header'] = 'The page header';
  2181. UI.HotSpots.__selectors['div#header-home'] = 'The page header on the homepage';
  2182. UI.HotSpots.__selectors['div#header-home h1.headermain'] = 'The header text on the homepage';
  2183. UI.HotSpots.__selectors['div#header h1.headermain'] = 'The header text';
  2184. UI.HotSpots.__selectors['div.sideblock'] = 'Blocks';
  2185. UI.HotSpots.__selectors['td#right-column div.sideblock'] = 'Blocks in the right hand column';
  2186. UI.HotSpots.__selectors['td#left-column div.sideblock'] = 'Blocks in the left hand column';
  2187. UI.HotSpots.__selectors['div.sideblock div.header'] = 'The block headings';
  2188. UI.HotSpots.__selectors['td#right-column div.sideblock div.header'] = 'The block headings in the right hand column';
  2189. UI.HotSpots.__selectors['td#left-column div.sideblock div.header'] = 'The block headings in the left hand column';
  2190. UI.HotSpots.__selectors['div.sideblock div.title'] = 'The text in the block headings';
  2191. UI.HotSpots.__selectors['td#right-column div.sideblock div.title'] = 'The text in the block headings in the right hand column';
  2192. UI.HotSpots.__selectors['td#left-column div.sideblock div.title'] = 'The text in the block headings in the left hand column';
  2193. UI.HotSpots.__selectors['div.headingblock'] = 'The heading at the top of the middle column';
  2194. UI.HotSpots.__selectors['table.topics'] = 'The topic sections in a course';
  2195. UI.HotSpots.__selectors['table.topics td.side'] = 'The sides of the topic sections';
  2196. UI.HotSpots.__selectors['table.topics td.left'] = 'The left side of the topic sections';
  2197. UI.HotSpots.__selectors['table.topics td.right'] = 'The right side of the topic sections';
  2198. UI.HotSpots.__selectors['table.topics tr.current div.summary'] = 'The summary of the highlighted topic';
  2199. UI.HotSpots.__selectors['table.topics tr.current td.content'] = 'The content of the highlighted topic';
  2200. UI.HotSpots.__selectors['a'] = 'Links';
  2201. UI.HotSpots.__selectors['a.dimmed'] = 'Greyed out links';
  2202. UI.HotSpots.__selectors['div#footer'] = 'The footer of the page';
  2203. UI.HotSpots.__selectors['div.logininfo'] = 'The "You are logged in as..." text';
  2204. UI.HotSpots.__selectors['div.navbar'] = 'The navigation bar';
  2205. UI.HotSpots.__selectors['div.breadcrumb'] = 'The navigation trail';
  2206. UI.HotSpots.__selectors['table.generaltable tr.r0'] = 'Odd numbered table rows';
  2207. UI.HotSpots.__selectors['table.generaltable tr.r1'] = 'Even numbered table rows';
  2208. }
  2209. UI.HotSpots.__parse();
  2210. },
  2211. __parse: function() {
  2212. var pos = {};
  2213. for (var sel in UI.HotSpots.__selectors) {
  2214. var matches = cssQuery(sel);
  2215. var nm = matches.length;
  2216. if (!nm) {
  2217. continue;
  2218. }
  2219. for (var j = 0; j < nm; ++j) {
  2220. if (matches[j].hasAttribute && matches[j].hasAttribute('id') && matches[j].getAttribute('id').indexOf('chameleon') != -1) {
  2221. continue;
  2222. }
  2223. if (!matches[j].chameleonHotspotId) {
  2224. var coords = Pos.getElement(matches[j]);
  2225. coords.x = 20 * Math.round(coords.x / 20);
  2226. coords.y = 20 * Math.round(coords.y / 20);
  2227. while (pos[coords.x + '-' + coords.y]) {
  2228. coords.x += 20;
  2229. }
  2230. pos[coords.x + '-' + coords.y] = true;
  2231. var button = UI.HotSpots.__makeButton(UI.HotSpots.__selectors[sel], coords.x, coords.y);
  2232. UI.addToDoc(button);
  2233. matches[j].chameleonHotspotId = button.id;
  2234. UI.HotSpots.__lookup[button.id] = sel;
  2235. break;
  2236. } else {
  2237. UI.HotSpots.__lookup[matches[j].chameleonHotspotId] += '|' + sel;
  2238. document.getElementById(matches[j].chameleonHotspotId).title += ", " + UI.HotSpots.__selectors[sel];
  2239. break;
  2240. }
  2241. }
  2242. }
  2243. pos = null;
  2244. matches = null;
  2245. },
  2246. __clear: function() {
  2247. for (var sel in UI.HotSpots.__selectors) {
  2248. var matches = cssQuery(sel);
  2249. var nm = matches.length;
  2250. if (!nm) {
  2251. continue;
  2252. }
  2253. for (var j = 0; j < nm; ++j) {
  2254. if (matches[j].chameleonHotspotId) {
  2255. UI.HotSpots.__lookup[matches[j].chameleonHotspotId] = null;
  2256. Util.removeElement(document.getElementById(matches[j].chameleonHotspotId));
  2257. matches[j].chameleonHotspotId = null;
  2258. break;
  2259. }
  2260. }
  2261. }
  2262. },
  2263. __makeButton: function(title, x, y) {
  2264. var d = Util.createElement('img', 'chameleon-hotspot-' + ++UI.HotSpots.__counter);
  2265. d.style.width = d.style.height = '20px';
  2266. d.style.position = 'absolute';
  2267. d.style.left = (x - 5) + 'px';
  2268. d.style.top = (y + 15) + 'px';
  2269. d.style.cursor = 'pointer';
  2270. d.setAttribute('src', CSS.fixPath('ui/images/hotspot.gif'));
  2271. d.setAttribute('title', title);
  2272. Util.addEvent(d, 'click', UI.HotSpots.__launch);
  2273. return d;
  2274. },
  2275. __launch: function(e) {
  2276. var target = e.target || e.srcElement;
  2277. var selectors = UI.HotSpots.__lookup[target.id].split('|');
  2278. var coords = Pos.getMouse(e);
  2279. hotspotMode = true;
  2280. var box = document.getElementById('chameleon-selector-box');
  2281. if (box) UI.closeBoxes(true, box);
  2282. var box = UI.makeDraggableBox('chameleon-selector-box', coords.x, coords.y);
  2283. if (selectors.length > 1) {
  2284. var instructions = Util.createElement('p');
  2285. instructions.appendChild(document.createTextNode('This element matches more than one selector, please choose which you would like to style.'));
  2286. instructions.className = 'chameleon-instructions';
  2287. box.appendChild(instructions);
  2288. }
  2289. var selList = Util.createElement('ul');
  2290. for (var i = 0; i < selectors.length; ++i) {
  2291. var item = Util.createElement('li');
  2292. var itemLink = Util.createElement('a');
  2293. itemLink.appendChild(document.createTextNode('Add/Edit styles for ' + UI.HotSpots.__selectors[selectors[i]]));
  2294. itemLink.value = selectors[i];
  2295. Util.addEvent(itemLink, 'click', UI.HotSpots.__launchCSSEditor);
  2296. item.appendChild(itemLink);
  2297. selList.appendChild(item);
  2298. box.appendChild(selList);
  2299. }
  2300. UI.addToDoc(box);
  2301. },
  2302. __launchCSSEditor: function(e, value) {
  2303. var target = e.target || e.srcElement;
  2304. if (!value) {
  2305. var value = target.value;
  2306. }
  2307. CSS.Selector.set(value);
  2308. UI.CSS.editWindow(e);
  2309. }
  2310. };
  2311. var Check = {
  2312. color: function(e) {
  2313. var target = e.target || e.srcElement;
  2314. if (e.type == 'click' && !target.value) return;
  2315. var originalColor = UI.CSS.__getPropValue(UI.CSS.colorType);
  2316. if (originalColor != target.value) {
  2317. CSS.setPropValue(UI.CSS.colorType, target.value);
  2318. UI.CSS.redraw.call(null, null, 'color');
  2319. }
  2320. if (e.type == 'click') {
  2321. UI.closeBoxes(true, target.parentNode.parentNode);
  2322. }
  2323. },
  2324. backgroundImage: function(e) {
  2325. var target = e.target || e.srcElement;
  2326. CSS.setPropValue('background-image', target.value);
  2327. UI.CSS.redraw.call(null, null, 'image');
  2328. if (e.type == 'click') {
  2329. UI.closeBoxes(true, document.getElementById('chameleon-file-box'));
  2330. }
  2331. },
  2332. backgroundRepeat: function(e) {
  2333. var target = e.target || e.srcElement;
  2334. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2335. CSS.setPropValue('background-repeat', value);
  2336. },
  2337. backgroundPosition: function(e) {
  2338. var target = e.target || e.srcElement;
  2339. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2340. CSS.setPropValue('background-position', value);
  2341. },
  2342. borderWidth: function(e) {
  2343. var target = e.target || e.srcElement;
  2344. var hasUnits = false;
  2345. for (var i = 0; i < Config.UNITS.length; ++i) {
  2346. if (target.value.indexOf(Config.UNITS[i]) > 0) {
  2347. hasUnits = true;
  2348. break;
  2349. }
  2350. }
  2351. var val = parseInt(target.value);
  2352. if (isNaN(val)) {
  2353. if (!target.value.match(/thin|medium|thick/)) {
  2354. target.value = '';
  2355. }
  2356. } else if (!hasUnits) {
  2357. target.value = val + 'px';
  2358. }
  2359. CSS.setPropValue(UI.CSS.getBorderProp(target.id), target.value);
  2360. },
  2361. borderStyle: function(e) {
  2362. var target = e.target || e.srcElement;
  2363. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2364. CSS.setPropValue(UI.CSS.getBorderProp(target.id), value);
  2365. },
  2366. fontStyle: function(e) {
  2367. var target = e.target || e.srcElement;
  2368. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2369. CSS.setPropValue('font-style', value);
  2370. },
  2371. fontWeight: function(e) {
  2372. var target = e.target || e.srcElement;
  2373. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2374. CSS.setPropValue('font-weight', value);
  2375. },
  2376. fontSize: function(e) {
  2377. var target = e.target || e.srcElement;
  2378. CSS.setPropValue('font-size', target.value);
  2379. },
  2380. lineHeight: function(e) {
  2381. var target = e.target || e.srcElement;
  2382. CSS.setPropValue('line-height', target.value);
  2383. },
  2384. fontFamily: function(e) {
  2385. var target = e.target || e.srcElement;
  2386. var n = target.nodeName.toLowerCase();
  2387. if (n == 'select') {
  2388. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2389. var fontFamilyInputRow = target.parentNode.parentNode.nextSibling;
  2390. if (value == 'other') {
  2391. try {
  2392. fontFamilyInputRow.style.display = 'table-row';
  2393. } catch(e) {
  2394. fontFamilyInputRow.style.display = 'block';
  2395. }
  2396. } else {
  2397. if (value != '') {
  2398. fontFamilyInputRow.style.display = 'none';
  2399. }
  2400. CSS.setPropValue('font-family', value);
  2401. }
  2402. } else {
  2403. CSS.setPropValue('font-family', target.value);
  2404. }
  2405. },
  2406. textDecoration: function(e) {
  2407. var target = e.target || e.srcElement;
  2408. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2409. CSS.setPropValue('text-decoration', value);
  2410. },
  2411. textAlign: function(e) {
  2412. var target = e.target || e.srcElement;
  2413. var value = target.options[target.options.selectedIndex].value.toLowerCase();
  2414. CSS.setPropValue('text-align', value);
  2415. }
  2416. };
  2417. var debugMsg = function(msg) {
  2418. //if (window.opera) window.opera.postError(msg);
  2419. };
  2420. var climbTree = function(src) {
  2421. var struct = [];
  2422. while (src.parentNode) {
  2423. if (src.nodeType == Node.ELEMENT_NODE) {
  2424. if (src.getAttribute && src.getAttribute('id') && src.getAttribute('id').indexOf('chameleon-') != -1) {
  2425. return src.getAttribute('id');
  2426. }
  2427. var elementObj = {tagname: src.nodeName.toLowerCase()};
  2428. if (src.getAttribute && src.getAttribute('id')) {
  2429. elementObj.id = src.getAttribute('id');
  2430. }
  2431. if (src.className) {
  2432. elementObj.classname = src.className;
  2433. }
  2434. elementObj.el = src;
  2435. struct.push(elementObj);
  2436. }
  2437. src = src.parentNode;
  2438. }
  2439. return struct;
  2440. };
  2441. var setup = function() {
  2442. UI.clearStatusMsg();
  2443. // UI.HotSpots.init();
  2444. var crumb = new cookie('chameleon_server_save_required');
  2445. if (crumb.read() == 1) {
  2446. CSS.requireRemoteSave();
  2447. }
  2448. Util.addEvent(window, 'unload', CSS.unloadPrompt);
  2449. Util.addEvent(window, 'unload', Util.cleanUp);
  2450. Util.addEvent(document, 'mousedown', UI.Selector.editWindow);
  2451. //CSS.clearTheme();
  2452. };
  2453. var startSetup = function() {
  2454. UI.statusMsg('Chameleon is loading...');
  2455. if (!CSS.loadRemote(true)) {
  2456. alert('Your browser must support XMLHttpRequest! Supported browsers include Internet Explorer, Mozilla Firefox, Safari and Opera');
  2457. }
  2458. };
  2459. Util.addEvent(window, 'load', startSetup);
  2460. })();