adding some strings
[moodle-linuxchix.git] / theme / custom_corners / ui / chameleon_js.php
blob94c3e8208cd63d71fd6af6444c5e2bd17922576a
1 <?php
3 header("Content-type: text/plain; charset=utf-8");
5 $chameleon_theme_root = explode('/', $_SERVER['PHP_SELF']);
6 array_pop($chameleon_theme_root);
7 array_pop($chameleon_theme_root);
8 $chameleon_theme_root = implode('/', $chameleon_theme_root);
12 if (!window.Node) {
13 var Node = {
14 ELEMENT_NODE: 1,
15 ATTRIBUTE_NODE: 2,
16 TEXT_NODE: 3,
17 CDATA_SECTION_NODE: 4,
18 ENTITY_REFERENCE_NODE: 5,
19 ENTITY_NODE: 6,
20 PROCESSING_INSTRUCTIONS_NODE: 7,
21 COMMENT_NODE: 8,
22 DOCUMENT_NODE: 9,
23 DOCUMENT_TYPE_NODE: 10,
24 DOCUMENT_FRAGMENT_NODE: 11,
25 NOTATION_NODE: 12
31 String.prototype.trim = function() {
32 return this.replace(/^\s+|\s+$/g, '');
36 (function() {
38 var struct = [];
39 var hotspotMode = null;
41 var Config = {
42 THEME_ROOT: '<?php echo $chameleon_theme_root; ?>',
43 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'; ?>',
44 FONTS_LIST: ['verdana, arial, helvetica, sans-serif', '"trebuchet ms", verdana, sans-serif', 'georgia, "trebuchet ms", times, serif', 'Other'],
45 FONT_WEIGHTS: ['normal', 'bold'],
46 FONT_STYLES: ['normal', 'italic'],
47 TEXT_DECORATION: ['none', 'underline', 'overline', 'line-through'],
48 TEXT_ALIGN: ['left', 'right', 'center', 'justify'],
49 REPEAT_LIST: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'],
50 POSITION_LIST: ['left top', 'left center', 'left bottom', 'center top', 'center center', 'center bottom', 'right top', 'right center', 'right bottom'],
51 BORDER_LIST: ['solid', 'dotted', 'dashed', 'none'],
52 UNITS: ['px', 'pt', 'em', '%'],
53 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']
58 var Util = {
59 __registry: {},
60 __uniqueId: 0,
62 createElement: function(tag, id) {
63 if (!id) var id = 'chameleon-element-' + ++Util.__uniqueId;
64 var obj = document.createElement(tag);
65 obj.setAttribute('id', id);
66 return obj;
69 removeElement: function(obj) {
70 if (!obj || !obj.parentNode) return false;
72 var kids = obj.getElementsByTagName('*');
73 if (!kids.length && typeof obj.all != 'undefined') {
74 kids = obj.all;
77 var n = kids.length;
78 while (n--) {
79 if (kids[n].id && Util.__registry[kids[n].id]) {
80 Util.__removeAllEvents(kids[n]);
83 if (Util.__registry[obj.id]) {
84 Util.__removeAllEvents(obj);
86 obj.parentNode.removeChild(obj);
89 clearElement: function(obj) {
90 while (obj.hasChildNodes()) {
91 obj.removeChild(obj.firstChild);
93 },
95 addEvent: function(obj, ev, fn) {
96 if (!Util.__addToRegistry(obj, ev, fn)) return;
98 if (obj.addEventListener) {
99 obj.addEventListener(ev, fn, false);
100 } else if (obj.attachEvent) {
101 obj['e' + ev + fn] = fn;
102 obj[ev + fn] = function() {
103 obj['e' + ev + fn](window.event);
105 obj.attachEvent('on' + ev, obj[ev + fn]);
108 removeEvent: function(obj, ev, fn) {
109 if (!Util.__removeFromRegistry(obj, ev, fn)) return;
111 if (obj.removeEventListener) {
112 obj.removeEventListener(ev, fn, false);
113 } else if (obj.detachEvent) {
114 obj.detachEvent('on' + ev, obj[ev + fn]);
115 obj[ev + fn] = null;
119 __getEventId: function(obj) {
120 if (obj == document) return 'chameleon-doc';
121 if (obj == window) return 'chameleon-win';
122 if (obj.id) return obj.id;
123 return false;
125 __findEvent: function(id, ev, fn) {
126 var i = Util.__registry[id][ev].length;
127 while (i--) {
128 if (Util.__registry[id][ev][i] == fn) {
129 return i;
132 return -1;
134 __addToRegistry: function(obj, ev, fn) {
135 var id = Util.__getEventId(obj);
137 if (!id) return false;
139 if (!Util.__registry[id]) {
140 Util.__registry[id] = {};
142 if (!Util.__registry[id][ev]) {
143 Util.__registry[id][ev] = [];
145 if (Util.__findEvent(id, ev, fn) == -1) {
146 Util.__registry[id][ev].push(fn);
147 return true;
149 return false;
151 __removeFromRegistry: function(obj, ev, fn) {
152 var id = Util.__getEventId(obj);
154 if (!id) return false;
156 var pos = Util.__findEvent(id, ev, fn);
157 if (pos != -1) {
158 Util.__registry[id][ev].splice(pos, 1);
159 return true;
161 return false;
163 __removeAllEvents: function(obj) {
164 for (var event in Util.__registry[obj.id]) {
165 var n = Util.__registry[obj.id][event].length;
166 while (n--) {
167 Util.removeEvent(obj, event, Util.__registry[obj.id][event][n]);
172 cleanUp: function() {
173 struct = null;
174 UI.closeAllBoxes();
182 var Pos = {
183 getElement: function(obj) {
184 var x = 0; var y = 0;
185 if (obj.offsetParent) {
186 while (obj.offsetParent) {
187 x += obj.offsetLeft;
188 y += obj.offsetTop;
189 obj = obj.offsetParent;
192 return {x: x, y: y};
194 getMouse: function(e) {
195 var x = 0; var y = 0;
196 if (e.pageX || e.pageY) {
197 x = e.pageX;
198 y = e.pageY;
199 } else if (e.clientX || e.clientY) {
200 x = e.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
201 y = e.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
203 return {x: x, y: y};
213 var CSS = {
215 __localCSS: {},
216 __remoteCSS: {},
218 __localSaveRequired: false,
219 __remoteSaveRequired: false,
222 requireRemoteSave: function() {
223 CSS.__remoteSaveRequired = true;
226 clearTheme: function() {
227 /*var links = document.getElementsByTagName('link');
228 var n = links.length;
229 while (n--) {
230 if (links[n].href && links[n].href.indexOf('<?php echo $chameleon_theme_root . "/styles.php"; ?>') != -1) {
231 links[n].parentNode.removeChild(links[n]);
232 break;
238 loadRemote: function(doSetup) {
239 if (!Sarissa.IS_ENABLED_XMLHTTP) {
240 return false;
242 var xmlhttp = new XMLHttpRequest();
243 xmlhttp.onreadystatechange = function() {
244 if (xmlhttp.readyState == 4) {
245 if (xmlhttp.responseText.indexOf('CHAMELEON_ERROR') != -1) {
246 alert('There was an error loading from the server:\n' + xmlhttp.responseText.replace(/CHAMELEON_ERROR /, '') + '.');
247 return;
250 CSS.__remoteCSS = CSS.toObject(xmlhttp.responseText);
251 CSS.__localCSS = CSS.__clone(CSS.__remoteCSS);
252 CSS.preview();
253 if (doSetup) {
254 setup();
256 xmlhttp = null;
259 xmlhttp.open('GET', Config.REMOTE_URI + '&nc=' + new Date().getTime(), true);
260 xmlhttp.send(null);
261 return true;
265 updateTemp: function(e, reset) {
266 if (!CSS.__localSaveRequired && !reset) {
267 UI.statusMsg('There are no changes that need saving!', 'chameleon-notice');
268 return;
271 if (!reset) {
272 UI.statusMsg('Updating temporary styles on the server...', 'chameleon-working');
273 } else {
274 UI.statusMsg('Deleting temporary styles from the server...', 'chameleon-working');
277 var css = CSS.toString();
278 var xmlhttp = new XMLHttpRequest();
279 xmlhttp.onreadystatechange = function() {
280 if (xmlhttp.readyState == 4) {
281 if (xmlhttp.responseText.indexOf('CHAMELEON_ERROR') != -1) {
282 UI.statusMsg('There was an error saving to the server:\n' + xmlhttp.responseText.replace(/CHAMELEON_ERROR /, '') + '.', 'chameleon-error');
284 } else {
285 CSS.__localSaveRequired = false;
286 if (!reset) {
287 UI.statusMsg('Temporary styles have been updated.', 'chameleon-ok');
288 } else {
289 UI.statusMsg('Temporary styles have been cleared.', 'chameleon-ok');
292 xmlhttp = null;
295 xmlhttp.open('POST', Config.REMOTE_URI + '&temp=1', true);
296 xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
297 xmlhttp.send('css=' + css);
301 updateRemote: function() {
302 if (!CSS.__remoteSaveRequired) {
303 UI.statusMsg('There are no changes that need saving!', 'chameleon-notice');
304 return;
307 var css = CSS.toString(CSS.__localCSS);
309 UI.statusMsg('Updating styles on the server...', 'chameleon-working');
310 var xmlhttp = new XMLHttpRequest();
311 xmlhttp.onreadystatechange = function() {
312 if (xmlhttp.readyState == 4) {
313 if (xmlhttp.responseText.indexOf('CHAMELEON_ERROR') != -1) {
314 UI.statusMsg('There was an error saving to the server:\n' + xmlhttp.responseText.replace(/CHAMELEON_ERROR /, '') + '.', 'chameleon-error');
315 } else {
316 CSS.__remoteCSS = CSS.toObject(css);
317 CSS.__localSaveRequired = false;
318 CSS.__remoteSaveRequired = false;
319 UI.statusMsg('Styles have been saved to the server.', 'chameleon-ok');
321 xmlhttp = null;
324 xmlhttp.open('POST', Config.REMOTE_URI, true);
325 xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
326 xmlhttp.send('css=' + css);
334 hardReset: function(e, noPrompt) {
335 if (noPrompt || confirm('Are you sure? This will erase all styles that have not been permanently saved to the server.')) {
336 CSS.__localCSS = {};
337 CSS.updateTemp(null, true);
339 CSS.__localCSS = CSS.__clone(CSS.__remoteCSS);
340 CSS.__localSaveRequired = false;
341 CSS.__remoteSaveRequired = false;
342 CSS.preview();
348 setPropValue: function(prop, value, selector) {
349 if (!selector) var selector = CSS.Selector.get();
351 if (!CSS.__localCSS[selector]) {
352 CSS.__localCSS[selector] = {};
355 var matches = prop.match(/^border\-([^\-]+)$/);
356 if (value) {
357 var func = CSS.__requiresFunction(prop);
358 if (func && value != 'none') {
359 CSS.__localCSS[selector][prop] = func + '(' + value + ')';
360 } else if (matches) {
361 CSS.__localCSS[selector]['border-left-' + matches[1]] = value;
362 CSS.__localCSS[selector]['border-right-' + matches[1]] = value;
363 CSS.__localCSS[selector]['border-top-' + matches[1]] = value;
364 CSS.__localCSS[selector]['border-bottom-' + matches[1]] = value;
365 } else {
366 CSS.__localCSS[selector][prop] = value;
368 } else {
369 if (matches) {
370 CSS.unsetProp('border-left-' + matches[1], selector);
371 CSS.unsetProp('border-right-' + matches[1], selector);
372 CSS.unsetProp('border-top-' + matches[1], selector);
373 CSS.unsetProp('border-bottom-' + matches[1], selector);
374 } else {
375 CSS.unsetProp(prop, selector);
379 CSS.__localSaveRequired = true;
380 CSS.__remoteSaveRequired = true;
381 CSS.preview(selector);
384 getPropValue: function(prop, selector) {
385 if (!selector) var selector = CSS.Selector.get();
387 if (!CSS.__localCSS[selector] || !CSS.__localCSS[selector][prop]) {
388 return '';
390 return CSS.__cleanFunctions(CSS.__localCSS[selector][prop]);
393 unsetProp: function(prop, selector) {
394 if (!selector) var selector = CSS.Selector.get();
396 if (!CSS.__localCSS[selector] || !CSS.__localCSS[selector][prop]) return;
398 CSS.__localCSS[selector][prop] = null;
399 delete CSS.__localCSS[selector][prop];
401 if (!CSS.__hasProps(selector)) {
402 CSS.__localCSS[selector] = null;
403 delete CSS.__localCSS[selector];
408 __hasProps: function(selector) {
409 for (var prop in CSS.__localCSS[selector]) {
410 if (prop) {
411 return true;
414 return false;
420 __cleanFunctions: function(val) {
421 var toClean = ['url'];
422 for (var i = 0; i < toClean.length; ++i) {
423 var start = val.indexOf(toClean[i] + '(');
424 var end = val.indexOf(')', start);
425 if (start == -1 || end == -1) {
426 continue;
428 val = val.slice(start + toClean[i].length + 1, end);
430 return val;
433 __requiresFunction: function(prop) {
434 var fnProps = {};
435 fnProps['background-image'] = 'url';
436 if (fnProps[prop]) {
437 return fnProps[prop];
439 return false;
445 fixPath: function(val) {
446 if (val == 'none') return val;
448 var tmp = val.split('(');
449 if (tmp.length > 1) {
450 tmp[1] = Config.THEME_ROOT + '/' + tmp[1];
451 return tmp.join('(');
453 return Config.THEME_ROOT + '/' + val;
458 preview: function(sel) {
459 var styleId = 'chameleon-preview-styles';
461 var h = document.getElementsByTagName('head')[0];
462 var s = document.getElementById(styleId);
464 if (!s) {
465 var s = Util.createElement('style', styleId);
466 s.setAttribute('type', 'text/css');
467 h.appendChild(s);
470 if (navigator.userAgent.toLowerCase().indexOf('msie') != -1 && !window.opera && document.styleSheets && document.styleSheets.length > 0) {
471 var lastStyle = document.styleSheets[document.styleSheets.length - 1];
473 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
474 var ieWarning = false;
476 if (sel) {
477 var matchedSelectors = [];
478 if (typeof sel == 'string') {
479 sel = [sel];
481 var n = lastStyle.rules.length;
482 while (n--) {
483 var ns = sel.length;
484 if (ns == 0) {
485 break;
487 while (ns--) {
488 if (sel[ns].match(ieCrashProtector)) {
489 ieWarning = true;
490 sel.splice(ns, 1);
491 break;
494 if (lastStyle.rules[n].selectorText.toLowerCase() == sel[ns].toLowerCase()) {
495 matchedSelectors.push(sel[ns]);
496 sel.splice(ns, 1);
497 lastStyle.removeRule(n);
498 break;
502 matchedSelectors = matchedSelectors.concat(sel);
503 var sl = matchedSelectors.length;
504 while (sl--) {
505 lastStyle.addRule(matchedSelectors[sl], CSS.__propsToString(CSS.__localCSS[matchedSelectors[sl]], true));
507 } else {
508 var n = lastStyle.rules.length;
509 while (n--) {
510 lastStyle.removeRule(n);
513 for (var sel in CSS.__localCSS) {
514 if (sel.match(ieCrashProtector)) {
515 ieWarning = true;
516 continue;
518 var dec = CSS.__propsToString(CSS.__localCSS[sel], true);
519 lastStyle.addRule(sel, dec);
523 if (ieWarning) {
524 UI.statusMsg('The edited CSS contains content that can not be previewed by Internet Explorer', 'chameleon-notice');
527 } else {
528 Util.clearElement(s);
529 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)
535 __merge: function() {
536 var merged = {};
537 for (var i = 0; i < arguments.length; ++i) {
538 for (var sel in arguments[i]) {
539 var newSelector = false;
540 if (!merged[sel]) {
541 merged[sel] = {};
542 newSelector = true;
544 for (var prop in arguments[i][sel]) {
545 merged[sel][prop] = arguments[i][sel][prop];
548 if (i > 0 && !newSelector) {
549 for (var prop in merged[sel]) {
550 if (!arguments[i][sel][prop]) {
551 merged[sel][prop] = null;
552 delete merged[sel][prop];
557 if (i > 0) {
558 for (var sel in merged) {
559 if (!arguments[i][sel]) {
560 merged[sel] = null;
561 delete merged[sel];
566 return merged;
569 __clone: function(src) {
570 var cloned = {};
571 for (var sel in src) {
572 if (!cloned[sel]) {
573 cloned[sel] = {};
575 for (var prop in src[sel]) {
576 cloned[sel][prop] = src[sel][prop];
579 return cloned;
583 toString: function(css, fixpath) {
584 if (!css) var css = CSS.__localCSS;
586 var dec = '';
587 for (var sel in css) {
588 dec += sel + ' ' + CSS.__propsToString(css[sel], fixpath, sel);
590 return dec;
593 __propsToString: function(css, fixpath) {
594 CSS.__Shorthand.border = {};
596 var hasBorder = false;
597 var col = false;
598 var importantBorders = [];
600 var dec = '{\n';
601 for (var prop in css) {
603 var includeProp = true;
605 if (prop.indexOf('border') != -1 && prop.indexOf('spacing') == -1 && prop.indexOf('collapse') == -1) {
606 if (css[prop].indexOf('!important') == -1) {
607 CSS.__Shorthand.recordBorder(prop, css[prop]);
608 } else {
609 importantBorders.push({prop: prop, css: css[prop]});
611 includeProp = false;
612 hasBorder = true;
615 if (prop == 'color') {
616 col = css[prop];
619 if (includeProp) {
620 if (fixpath && (CSS.__requiresFunction(prop) == 'url') && css[prop] != 'none') {
621 dec += ' ' + prop + ': ' + CSS.fixPath(css[prop]) + ';\n';
622 } else {
623 dec += ' ' + prop + ': ' + css[prop] + ';\n';
628 if (hasBorder) {
629 dec += CSS.__Shorthand.getBorderString(col);
631 var n;
632 if (n = importantBorders.length) {
633 while (n--) {
634 dec += ' ' + importantBorders[n].prop + ': ' + importantBorders[n].css + ';\n';
638 dec += '}\n';
639 return dec;
645 toObject: function(css) {
646 var cssObj = {};
647 var end;
649 while (end = css.indexOf('}'), end != -1) {
650 var cssRule = css.substr(0, end);
651 var parts = cssRule.split('{');
652 var selector = parts.shift()
653 if (selector.indexOf(',') != -1) {
654 var selectorArr = selector.split(',');
655 } else {
656 var selectorArr = [selector];
659 var rules = parts.pop().trim();
660 rules = rules.split(';');
661 for (var i = 0; i < rules.length; ++i) {
662 if (rules[i].indexOf(':') == -1) {
663 break;
665 var rule = rules[i].split(':');
666 var prop = rule.shift().trim();
667 var val = rule.pop().trim();
669 for (var j = 0; j < selectorArr.length; ++j) {
670 var noFontPropReset = {};
672 selector = selectorArr[j].trim();
673 if (!cssObj[selector]) {
674 cssObj[selector] = {};
677 if (prop != 'font' && (prop.indexOf('font') != -1 || prop == 'line-height')) {
678 noFontPropReset[prop] = true;
681 if (prop == 'background') {
682 CSS.__Shorthand.setBackground(cssObj, selector, val);
683 } else if (prop == 'font') {
684 CSS.__Shorthand.setFont(cssObj, selector, val, noFontPropReset);
685 } else if ((prop == 'border' || prop.match(/^border\-([^-]+)$/)) && prop.indexOf('spacing') == -1 && prop.indexOf('collapse') == -1) {
686 CSS.__Shorthand.setBorder(cssObj, selector, val, prop);
687 } else {
688 cssObj[selector][prop] = val;
692 css = css.substring(end + 1);
694 return cssObj;
701 getSelectorCSS: function(selector, asObject) {
702 if (!selector) var selector = CSS.Selector.get();
704 var css = (CSS.__localCSS[selector]) ? CSS.__localCSS[selector] : {};
705 if (asObject) {
706 return css;
708 return selector + ' ' + CSS.__propsToString(css);
713 saveRequired: function() {
714 return CSS.__localSaveRequired || CSS.__serverSaveRequired;
718 checkSpec: function(e, selector) {
719 if (!selector) var selector = CSS.Selector.get();
720 if (selector == '') {
721 UI.statusMsg('First you have to choose which item to style!', 'chameleon-notice');
722 return;
725 var splitSelector = function(selector) {
726 var selectorEnd = selector.split(' ').pop();
727 selectorEnd = selectorEnd.replace(/([\.:#])/g, '|$1');
728 return selectorEnd.split('|');
731 var similar = [];
733 var selectorBits = splitSelector(selector);
735 for (var sel in CSS.__localCSS) {
736 var selBits = splitSelector(sel);
738 var n = selectorBits.length;
740 while (n--) {
741 var match = selectorBits[n];
742 var m = selBits.length;
743 while (m--) {
744 if (selBits[m] == match) {
745 var l = similar.length;
746 var add = true;
747 while (l--) {
748 if (similar[l] == sel) {
749 add = false;
750 break;
753 if (add) {
754 similar.push(sel);
756 break;
762 if (similar.length) {
763 UI.Selector.__displayOverview(null, similar, selector);
764 } else {
765 UI.statusMsg('Your file currently contains no selectors that appear similar to "' + selector + '"', 'chameleon-notice');
770 unloadPrompt: function() {
771 if (CSS.__localSaveRequired) {
772 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.')) {
773 CSS.updateTemp();
776 var cookieVal = (CSS.__remoteSaveRequired) ? 1 : 0;
777 var crumb = new cookie('chameleon_server_save_required', cookieVal, 30, '/', null, null);
778 crumb.set();
785 CSS.Selector = {
787 trimmed: [],
788 full: [],
789 selector: '',
791 create: function() {
792 CSS.Selector.trimmed = [];
794 var n = struct.length;
795 while (n--) {
796 if (CSS.Selector.full[n]) {
797 CSS.Selector.trimmed.push(CSS.Selector.full[n].val);
800 CSS.Selector.set(CSS.Selector.trimmed.join(' '));
803 modify: function(e) {
804 var target = e.target || e.srcElement;
805 var p = target.position;
807 var sel = CSS.Selector.full;
809 if (!sel[p]) {
810 UI.Selector.highlight(target);
811 sel[p] = {val: target.selectorValue, id: target.id};
812 } else if (sel[p].val != target.selectorValue) {
813 UI.Selector.highlight(target);
814 UI.Selector.unhighlight(document.getElementById(sel[p].id));
815 sel[p] = {val: target.selectorValue, id: target.id};
816 } else {
817 UI.Selector.unhighlight(target);
818 sel[p] = null;
821 CSS.Selector.create();
822 UI.Selector.displaySelector(CSS.Selector.trimmed);
825 set: function(sel) {
826 CSS.Selector.selector = sel;
829 get: function() {
830 return CSS.Selector.selector;
833 reset: function() {
834 CSS.Selector.trimmed = [];
835 CSS.Selector.full = [];
836 CSS.Selector.set('');
842 CSS.__Shorthand = {
843 border: {},
845 recordBorder: function(prop, value) {
846 var pr = prop.split('-')
847 var p = pr.pop();
848 var s = pr.pop();
849 if (!CSS.__Shorthand.border[p]) {
850 CSS.__Shorthand.border[p] = [];
852 if (!CSS.__Shorthand.border[s]) {
853 CSS.__Shorthand.border[s] = {};
855 if (!CSS.__Shorthand.border[s][p]) {
856 CSS.__Shorthand.border[s][p] = [];
858 CSS.__Shorthand.border[p].push({prop: prop, value: value});
859 CSS.__Shorthand.border[s][p] = value;
862 getBorderString: function(col) {
863 var cb = CSS.__Shorthand.border;
865 var useHowManyProps = function(prop) {
866 if (!cb['top'] || !cb['right'] || !cb['bottom'] || !cb['left']) {
867 return false;
870 if (!(cb['top'][prop] && cb['right'][prop] && cb['bottom'][prop] && cb['left'][prop])) {
871 return false;
874 if (cb['top'][prop] == cb['right'][prop] && cb['top'][prop] == cb['bottom'][prop] && cb['top'][prop] == cb['left'][prop]) {
875 return 1;
877 if (cb['top'][prop] == cb['bottom'][prop] && cb['right'][prop] == cb['left'][prop]) {
878 return 2;
880 if (cb['right'][prop] == cb['left'][prop]) {
881 return 3;
883 return 4;
886 var getPropShorthand = function(prop) {
887 var num = useHowManyProps(prop);
888 if (!num) {
889 return '';
892 if (prop.indexOf('color') != -1) {
893 var l = inheritColor(cb['left'][prop]);
894 var r = inheritColor(cb['right'][prop]);
895 var t = inheritColor(cb['top'][prop]);
896 var b = inheritColor(cb['bottom'][prop]);
897 } else {
898 var l = cb['left'][prop];
899 var r = cb['right'][prop];
900 var t = cb['top'][prop];
901 var b = cb['bottom'][prop];
904 var propShorthand = '';
905 if (num == 1) {
906 propShorthand += ' border-' + prop + ': ' + l;
907 } else if (num == 2) {
908 propShorthand += ' border-' + prop + ': ' + t + ' ' + l;
909 } else if (num == 3) {
910 propShorthand += ' border-' + prop + ': ' + t + ' ' + l + ' ' + b;
911 } else {
912 propShorthand += ' border-' + prop + ': ' + t + ' ' + r + ' ' + b + ' ' + l;
914 return propShorthand + ';\n';
917 var propsStr = function(props) {
918 var str = '';
919 for (var i = 0; i < props.length; ++i) {
920 str += ' ' + props[i].prop + ': ' + ((props[i].prop.indexOf('color') != -1) ? inheritColor(props[i].value) : props[i].value) + ';\n';
922 return str;
925 var inheritColor = function(val) {
926 if (!col || val != 'inherit') return val;
927 return col;
930 var setImportant = function(str) {
931 if (!str) return '';
932 if (str.indexOf('!important') == -1) return str;
933 str = str.replace(/ *\!important */g, ' ');
934 return str.substr(0, str.lastIndexOf(';')) + ' !important;\n';
937 var widthEqual = (cb['width']) ? CSS.__Shorthand.__allPropsEqual(cb['width']) : false;
938 var styleEqual = (cb['style']) ? CSS.__Shorthand.__allPropsEqual(cb['style']) : false;
939 var colorEqual = (cb['color']) ? CSS.__Shorthand.__allPropsEqual(cb['color']) : false;
941 if (widthEqual && styleEqual && colorEqual) {
942 var propStr = setImportant(cb['width'][0].value + ' ' + cb['style'][0].value + ' ' + inheritColor(cb['color'][0].value) + ';\n');
943 if (cb['left'] && cb['top'] && cb['right'] && cb['bottom']) {
944 return ' border: ' + propStr;
947 var sideShorthand = '';
948 if (cb['top']) {
949 sideShorthand += ' border-top: ' + propStr;
951 if (cb['right']) {
952 sideShorthand += ' border-right: ' + propStr;
954 if (cb['bottom']) {
955 sideShorthand += ' border-bottom: ' + propStr;
957 if (cb['left']) {
958 sideShorthand += ' border-left: ' + propStr;
960 return sideShorthand;
963 var widthProps = getPropShorthand('width');
964 if (!widthProps) {
965 widthProps = (cb['width']) ? propsStr(cb['width']) : '';
967 var styleProps = getPropShorthand('style');
968 if (!styleProps) {
969 styleProps = (cb['style']) ? propsStr(cb['style']) : '';
971 var colorProps = getPropShorthand('color');
972 if (!colorProps) {
973 colorProps = (cb['color']) ? propsStr(cb['color']) : '';
976 return setImportant(widthProps) + setImportant(styleProps) + setImportant(colorProps);
984 setBorder: function(css, selector, value, prop) {
985 var props = {};
986 var p = '';
988 props['width'] = {
989 regexp: /^(thin|medium|thick|0|(\d+(([^%\d]+)|%)))$/,
990 def: 'medium'
992 props['style'] = {
993 regexp: /none|dotted|dashed|solid|double|groove|ridge|inset|outset/,
994 def: 'none'
996 props['color'] = {
997 regexp: /^((rgb\(\d{1,3} *, *\d{1,3} *, *\d{1,3} *\))|(#[A-F0-9]{3}([A-F0-9]{3})?)|([a-z]+))$/i,
998 def: 'inherit'
1001 var bits = value.split(' ');
1002 var imp = (bits[bits.length - 1] == '!important') ? ' ' + bits.pop() : '';
1004 if (prop == 'border') {
1005 for (var i in props) {
1006 css[selector]['border-top-' + i] = props[i].def;
1007 css[selector]['border-right-' + i] = props[i].def;
1008 css[selector]['border-bottom-' + i] = props[i].def;
1009 css[selector]['border-left-' + i] = props[i].def;
1010 var j = bits.length;
1011 while (j--) {
1012 if (bits[j].match(props[i].regexp)) {
1013 css[selector]['border-top-' + i] = bits[j];
1014 css[selector]['border-right-' + i] = bits[j];
1015 css[selector]['border-bottom-' + i] = bits[j];
1016 css[selector]['border-left-' + i] = bits[j];
1017 bits.splice(j, 1);
1018 break;
1022 } else if (prop == 'border-left' || prop == 'border-right' || prop == 'border-top' || prop == 'border-bottom') {
1023 for (var i in props) {
1024 css[selector][prop + '-' + i] = props[i].def;
1025 var j = bits.length;
1026 while (j--) {
1027 if (bits[j].match(props[i].regexp)) {
1028 css[selector][prop + '-' + i] = bits[j] + imp;
1029 bits.splice(j, 1);
1030 break;
1034 imp = '';
1036 } else if (prop == 'border-width' || prop == 'border-style' || prop == 'border-color') {
1037 var p = prop.split('-').pop();
1038 var num = bits.length;
1039 if (num == 1) {
1040 css[selector]['border-top-' + p] = bits[0];
1041 css[selector]['border-right-' + p] = bits[0];
1042 css[selector]['border-bottom-' + p] = bits[0];
1043 css[selector]['border-left-' + p] = bits[0];
1044 } else if (num == 2) {
1045 css[selector]['border-top-' + p] = bits[0];
1046 css[selector]['border-right-' + p] = bits[1];
1047 css[selector]['border-bottom-' + p] = bits[0];
1048 css[selector]['border-left-' + p] = bits[1];
1049 } else if (num == 3) {
1050 css[selector]['border-top-' + p] = bits[0];
1051 css[selector]['border-right-' + p] = bits[1];
1052 css[selector]['border-bottom-' + p] = bits[2];
1053 css[selector]['border-left-' + p] = bits[1];
1054 } else if (num == 4) {
1055 css[selector]['border-top-' + p] = bits[0];
1056 css[selector]['border-right-' + p] = bits[1];
1057 css[selector]['border-bottom-' + p] = bits[2];
1058 css[selector]['border-left-' + p] = bits[3];
1062 if (imp != '') {
1063 var sides = ['top', 'right', 'bottom', 'left'];
1064 for (var i = 0; i < 4; ++i) {
1065 for (var j in props) {
1066 if (p != '' && p != j) {
1067 continue;
1070 if (css[selector]['border-' + sides[i] + '-' + j]) {
1071 css[selector]['border-' + sides[i] + '-' + j] += imp;
1082 setBackground: function(css, selector, value) {
1083 var imp = (value.indexOf('!important') != -1) ? ' !important' : '';
1084 if (imp != '') {
1085 value = value.replace(/ *\!important */g, '');
1088 var urlPos = value.indexOf('url(');
1089 if (urlPos == -1 && value.indexOf('none') == -1) {
1090 css[selector]['background-color'] = value + imp;
1091 return;
1092 } else if (urlPos == -1 && value.indexOf(' none') != -1) {
1093 var bits = value.split(' ');
1094 css[selector]['background-color'] = bits[0] + imp;
1095 css[selector]['background-image'] = bits[1] + imp;
1096 return;
1097 } else if (value == 'none') {
1098 css[selector]['background-image'] = value + imp;
1099 return;
1101 var bits = value.split('url(');
1102 var endImg = bits[1].indexOf(')');
1103 if (endImg == -1) {
1104 return;
1106 css[selector]['background-image'] = 'url(' + bits[1].substr(0, endImg).replace(/["']+/g, '') + ')' + imp; //"
1108 var pos = [];
1110 var bgOptions = bits[1].substring(endImg + 1).split(' ');
1111 var n = bgOptions.length;
1113 for (var i = 0; i < n; ++i) {
1114 var opt = bgOptions[i].trim();
1115 if (opt.indexOf('repeat') != -1) {
1116 css[selector]['background-repeat'] = opt + imp;
1117 } else if (opt == 'fixed' || opt == 'scroll') {
1118 css[selector]['background-attachment'] = opt + imp;
1119 } else if (opt != '') {
1120 pos.push(opt);
1123 if (pos.length == 2) {
1124 css[selector]['background-position'] = pos.join(' ') + imp;
1126 var col = bits[0].trim();
1127 if (col != '') {
1128 css[selector]['background-color'] = col + imp;
1132 setFont: function(css, selector, value, noreset) {
1133 var imp = (value.indexOf('!important') != -1) ? ' !important' : '';
1134 if (imp != '') {
1135 value = value.replace(/ *\!important */g, '');
1138 var order = ['font-style', 'font-variant', 'font-weight', 'font-size', 'font-family'];
1139 var numProps = order.length;
1140 var allowedVals = {};
1141 allowedVals['font-style'] = /(normal|italic|oblique|inherit)/;
1142 allowedVals['font-variant'] = /(normal|small\-caps|inherit)/;
1143 allowedVals['font-weight'] = /(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit)/;
1144 allowedVals['font-size'] = /([^ ]+)/;
1145 allowedVals['font-family'] = /(.+$)/;
1147 if (!noreset['font-style']) css[selector]['font-style'] = 'normal';
1148 if (!noreset['font-variant']) css[selector]['font-variant'] = 'normal';
1149 if (!noreset['font-weight']) css[selector]['font-weight'] = 'normal';
1150 if (!noreset['font-size']) css[selector]['font-size'] = 'medium';
1151 if (!noreset['line-height']) css[selector]['line-height'] = 'normal';
1153 var expandShorthand = function(bits) {
1154 var numBits = bits.length;
1155 var startProp = 0;
1156 for (var i = 0; i < numBits; ++i) {
1157 if (i > numProps - 1) {
1158 return;
1160 for (var j = startProp; j < numProps; ++j) {
1161 if (bits[i].match(allowedVals[order[j]])) {
1162 if (order[j] == 'font-size' && bits[i].indexOf('/') != -1) {
1163 var fsLh = bits[i].split('/');
1164 css[selector]['font-size'] = fsLh[0] + imp;
1165 css[selector]['line-height'] = fsLh[1] + imp;
1166 } else {
1167 css[selector][order[j]] = bits[i] + imp;
1169 startProp = j + 1;
1170 break;
1176 var removeCommaListSpaces = function(str) {
1177 var comma = str.indexOf(',');
1178 if (comma != -1) {
1179 return str.substr(0, comma) + str.substring(comma).replace(/ +/g, '');
1181 return str;
1184 var hasQuote = value.match(/(["'])/); //"
1185 if (hasQuote) {
1186 var tmp = value.split(hasQuote[1]);
1187 var bits = removeCommaListSpaces(tmp.shift()).split(' ');
1188 var startFont = bits.pop();
1190 expandShorthand(bits);
1192 css[selector]['font-family'] = startFont + hasQuote[1] + tmp.join(hasQuote[1]) + imp;
1193 } else {
1194 value = removeCommaListSpaces(value);
1195 expandShorthand(value.split(' '));
1202 __allPropsEqual: function(props) {
1203 var num = props.length - 1;
1204 if (num < 3) return false;
1206 for (var i = 0; i < num; ++i) {
1207 if (props[i].value != props[i + 1].value) {
1208 return false;
1211 return true;
1217 CSS.FreeEdit = {
1219 __initial: {},
1221 setInitial: function(e) {
1222 var target = e.target || e.srcElement;
1224 CSS.FreeEdit.__initial = CSS.toObject(target.value);
1227 saveComplete: function(e) {
1228 var target = e.target || e.srcElement;
1229 target.value = CSS.FreeEdit.__stripComments(target.value);
1231 CSS.__localCSS = CSS.__merge(CSS.__localCSS, CSS.toObject(target.value));
1233 CSS.__localSaveRequired = true;
1234 CSS.__remoteSaveRequired = true;
1236 CSS.preview();
1239 saveSelector: function(e) {
1240 var target = e.target || e.srcElement;
1241 target.value = CSS.FreeEdit.__stripComments(target.value);
1243 var changedSelectors = [];
1244 var css = CSS.toObject(target.value);
1245 for (var sel in css) {
1246 changedSelectors.push(sel);
1247 if (!CSS.__localCSS[sel]) {
1248 CSS.__localCSS[sel] = {};
1250 for (var prop in css[sel]) {
1251 CSS.__localCSS[sel][prop] = css[sel][prop];
1255 for (var sel in CSS.FreeEdit.__initial) {
1256 if (!css[sel] && CSS.__localCSS[sel]) {
1257 changedSelectors.push(sel);
1258 CSS.__localCSS[sel] = null;
1259 delete CSS.__localCSS[sel];
1260 continue;
1262 for (var prop in CSS.FreeEdit.__initial[sel]) {
1263 if (!css[sel][prop] && CSS.__localCSS[sel][prop]) {
1264 CSS.__localCSS[sel][prop] = null;
1265 delete CSS.__localCSS[sel][prop];
1270 CSS.__localSaveRequired = true;
1271 CSS.__remoteSaveRequired = true;
1272 CSS.preview(changedSelectors);
1275 __stripComments: function(str) {
1276 return str.replace(/\/\*([\s\S])*?\*\//g, '');
1286 var FileHandler = {
1288 getFiles: function(path) {
1289 if (!path) path = '';
1290 var xmlhttp = new XMLHttpRequest();
1291 xmlhttp.onreadystatechange = function() {
1292 if (xmlhttp.readyState == 4) {
1293 UI.CSS.displayImagePicker(xmlhttp.responseXML);
1294 xmlhttp = null;
1297 xmlhttp.open('GET', Config.REMOTE_URI + '&path=' + escape(path) + '&nc=' + new Date().getTime(), true);
1298 xmlhttp.send(null);
1299 return true;
1307 var UI = {
1308 boxes: [],
1309 boxOffsetX: 35,
1310 boxOffsetY: 30,
1311 zIndex: 9999,
1313 __dragTargetId: null,
1315 statusMsg: function(msg, cls) {
1316 UI.clearStatusMsg();
1318 var target = UI.__getBox();
1319 if (!target) {
1320 var box = Util.createElement('div', 'chameleon-status-msg');
1321 box.appendChild(document.createTextNode(msg));
1322 box.style.zIndex = ++UI.zIndex;
1323 UI.addToDoc(box);
1324 } else {
1326 var statusTable = Util.createElement('table', 'chameleon-status-msg');
1327 var statusTableBody = Util.createElement('tbody');
1328 var statusRow = Util.createElement('tr');
1329 var statusIconCell = Util.createElement('td');
1330 var statusMsgCell = Util.createElement('td');
1331 var statusBtnCell = Util.createElement('td');
1333 if (cls) {
1334 statusIconCell.className = cls;
1336 statusMsgCell.appendChild(document.createTextNode(msg));
1337 statusBtnCell.appendChild(UI.createButton('chameleon-status-msg-btn', 'OK', 'Clear this message', UI.clearStatusMsg));
1339 statusRow.appendChild(statusIconCell);
1340 statusRow.appendChild(statusMsgCell);
1341 statusRow.appendChild(statusBtnCell);
1342 statusTableBody.appendChild(statusRow);
1343 statusTable.appendChild(statusTableBody);
1345 target.appendChild(statusTable);
1349 clearStatusMsg: function() {
1350 var obj = document.getElementById('chameleon-status-msg');
1351 if (obj) {
1352 Util.removeElement(obj);
1356 addToDoc: function(content) {
1357 document.getElementsByTagName('body')[0].appendChild(content);
1360 makeDraggableBox: function(id, x, y) {
1361 if ((x + 500) > screen.width) {
1362 var offset = x + 525 - screen.width;
1363 x -= offset;
1366 var box = Util.createElement('div', id);
1367 box.style.left = x + 'px';
1368 box.style.top = y + 'px';
1369 box.style.zIndex = ++UI.zIndex;
1371 var topBar = Util.createElement('div', id + '-handle');
1372 var closeBtn = Util.createElement('div', id + '-close');
1373 closeBtn.appendChild(document.createTextNode('x'));
1374 closeBtn.setAttribute('title', 'Close');
1375 topBar.setAttribute('title', 'Drag me!');
1377 UI.__dragTargetId = id + '-handle';
1379 Util.addEvent(closeBtn, 'click', UI.closeBoxes);
1380 Util.addEvent(topBar, 'mousedown', UI.__startDrag);
1381 Util.addEvent(topBar, 'mousedown', UI.__bringToFront);
1382 Util.addEvent(topBar, 'mouseup', UI.__stopDrag);
1384 topBar.appendChild(closeBtn);
1385 box.appendChild(topBar);
1387 UI.boxes.push(id);
1389 return box;
1392 closeAllBoxes: function() {
1393 var n = UI.boxes.length;
1394 while (n--) {
1395 Util.removeElement(document.getElementById(UI.boxes[n]));
1396 UI.boxes.splice(n, 1);
1398 UI.__dragTargetId = null;
1401 closeBoxes: function(e, box) {
1402 if (!box) {
1403 var target = e.target || e.srcElement;
1404 var box = target.parentNode.parentNode;
1407 var n = UI.boxes.length;
1408 while (n--) {
1409 if (UI.boxes[n] == box.id) {
1410 break;
1412 Util.removeElement(document.getElementById(UI.boxes[n]));
1413 UI.boxes.splice(n, 1);
1415 Util.removeElement(box);
1416 UI.boxes.splice(n, 1);
1417 UI.__dragTargetId = (UI.boxes.length) ? UI.boxes[UI.boxes.length - 1] + '-handle' : null;
1420 __startDrag: function(e) {
1421 var target = e.target || e.srcElement;
1422 var mouseCoords = Pos.getMouse(e);
1423 var elementCoords = Pos.getElement(target);
1424 target.mouseX = mouseCoords.x - elementCoords.x;
1425 target.mouseY = mouseCoords.y - elementCoords.y;
1427 UI.__dragTargetId = target.id;
1429 Util.addEvent(document, 'mousemove', UI.__drag);
1432 __stopDrag: function(e) {
1433 Util.removeEvent(document, 'mousemove', UI.__drag);
1436 __drag: function(e) {
1437 var target = document.getElementById(UI.__dragTargetId);
1439 var mouseCoords = Pos.getMouse(e);
1440 target.parentNode.style.left = (mouseCoords.x - target.mouseX) + 'px';
1441 target.parentNode.style.top = (mouseCoords.y - target.mouseY) + 'px';
1443 if (e.preventDefault) {
1444 e.preventDefault();
1445 } else if (window.event) {
1446 window.event.returnValue = false;
1450 __bringToFront: function(e) {
1451 var target = e.target || e.srcElement;
1452 target.parentNode.style.zIndex = ++UI.zIndex;
1455 __getBox: function() {
1456 var obj = document.getElementById(UI.__dragTargetId);
1457 if (obj && obj.parentNode) {
1458 return obj.parentNode;
1460 return false;
1466 setupPane: function(tabs, parentId, tabId, active) {
1467 for (var i = 0; i < tabs.length; ++i) {
1468 var obj = document.getElementById(tabId + '-tab-' + tabs[i]);
1469 if (obj) {
1470 obj.className = tabId + ((active == tabs[i]) ? '-tab-active' : '-tab');
1474 var parent = document.getElementById(parentId);
1475 if (parent && parent.firstChild) {
1476 Util.removeElement(parent.firstChild);
1478 return parent;
1481 setupButtons: function() {
1482 var parentId = arguments[0];
1483 var parent = document.getElementById(parentId);
1484 if (!parent) return;
1486 var btns = parent.getElementsByTagName('input');
1487 for (var i = 0; i < btns.length; ++i) {
1488 btns[i].style.display = 'none';
1491 for (var i = 1; i < arguments.length; ++i) {
1492 var id = parentId + '-' + arguments[i];
1493 var btn = document.getElementById(id);
1494 if (btn) {
1495 btn.style.display = 'inline';
1500 createButton: function(id, value, title, fn, hidden) {
1501 var btn = Util.createElement('input', id);
1502 btn.setAttribute('type', 'submit');
1503 btn.setAttribute('value', value);
1504 btn.setAttribute('title', title);
1505 btn.className = 'chameleon-btn';
1506 if (hidden) {
1507 btn.style.display = 'none';
1510 Util.addEvent(btn, 'click', fn);
1511 return btn;
1514 setOverflow: function(obj, height, forced) {
1515 if (obj.offsetHeight > height || forced) {
1516 obj.style.height = height + 'px';
1517 obj.style.overflow = 'scroll';
1523 UI.Selector = {
1524 controlsId: 'chameleon-selector-controls',
1525 viewedProp: null,
1526 displayPropWatch: false,
1527 sections: ['choose', 'overview', 'free-edit'],
1530 editWindow: function(e) {
1531 if (!e.shiftKey) {
1532 return;
1535 var target = e.target || e.srcElement;
1536 var tmpStruct = climbTree(target);
1537 if (typeof tmpStruct == 'string') {
1538 return;
1541 hotspotMode = false;
1543 var box = document.getElementById('chameleon-selector-box');
1544 if (box) UI.closeBoxes(true, box);
1546 struct = tmpStruct;
1547 CSS.Selector.reset();
1549 var coords = Pos.getMouse(e);
1550 var box = UI.makeDraggableBox('chameleon-selector-box', coords.x, coords.y);
1553 var instructions = Util.createElement('p');
1554 instructions.appendChild(document.createTextNode('Create a CSS selector to edit, browse an overview of your edited styles or edit your complete stylesheet by hand.'));
1555 instructions.className = 'chameleon-instructions';
1556 box.appendChild(instructions);
1558 var tabsContainer = Util.createElement('table', 'chameleon-selector-tabs');
1559 var tabsBody = Util.createElement('tbody');
1560 var tabs = Util.createElement('tr');
1562 tabs.appendChild(UI.Selector.__createTab('Choose', UI.Selector.__editSelector, true, 'Choose'));
1563 tabs.appendChild(UI.Selector.__createTab('Overview', UI.Selector.__displayOverview, false, 'Overview'));
1564 tabs.appendChild(UI.Selector.__createTab('Free Edit', UI.Selector.__editCode, false, 'Free Edit'));
1566 tabsBody.appendChild(tabs);
1567 tabsContainer.appendChild(tabsBody);
1569 box.appendChild(tabsContainer);
1571 var styleControls = Util.createElement('div', UI.Selector.controlsId);
1572 box.appendChild(styleControls);
1573 box.appendChild(UI.Selector.__addButtons());
1575 UI.addToDoc(box);
1577 UI.Selector.__editSelector();
1579 if (e.preventDefault) {
1580 e.preventDefault();
1581 } else if (window.event) {
1582 window.event.returnValue = false;
1587 __listProps: function(e) {
1588 var target = e.target || e.srcElement;
1590 Util.removeElement(document.getElementById('chameleon-selector-element-list'));
1591 UI.Selector.viewedProp = target.options[target.selectedIndex].value;
1592 if (!document.getElementById('chameleon-selector-list')) {
1593 target.parentNode.parentNode.appendChild(UI.Selector.__elementList(target.options[target.selectedIndex].value));
1594 } else {
1595 target.parentNode.parentNode.insertBefore(UI.Selector.__elementList(target.options[target.selectedIndex].value), document.getElementById('chameleon-selector-list'));
1599 __editSelector: function() {
1600 var parent = UI.setupPane(UI.Selector.sections, UI.Selector.controlsId, 'chameleon-selector', 'choose');
1601 UI.setupButtons('chameleon-selector-buttons', 'edit', 'check');
1603 var container = Util.createElement('div');
1605 var instructions = Util.createElement('p');
1606 instructions.appendChild(document.createTextNode('Please choose the element you wish to style.'));
1607 container.appendChild(instructions);
1609 var options = Util.createElement('p');
1611 if (UI.Selector.__displayPropWatch) {
1613 var selectProp = Util.createElement('select', 'chameleon-selector-prop-select');
1614 var optionProp = Util.createElement('option');
1615 optionProp.appendChild(document.createTextNode('Select a CSS property to view'));
1616 optionProp.setAttribute('value', '');
1617 selectProp.appendChild(optionProp);
1619 for (var i = 0; i < Config.PROPS_LIST.length; ++i) {
1620 optionProp = Util.createElement('option');
1621 optionProp.setAttribute('value', Config.PROPS_LIST[i]);
1622 if (UI.Selector.viewedProp == Config.PROPS_LIST[i]) {
1623 optionProp.setAttribute('selected', 'selected');
1625 optionProp.appendChild(document.createTextNode(Config.PROPS_LIST[i]));
1626 selectProp.appendChild(optionProp);
1629 Util.addEvent(selectProp, 'change', UI.Selector.__listProps);
1631 options.appendChild(selectProp);
1635 var togglePropWatch = Util.createElement('a');
1636 togglePropWatch.setAttribute('title', 'The property inspector allows you to check the current value of a range of CSS properties for these elements');
1637 togglePropWatch.appendChild(document.createTextNode(' (' + (UI.Selector.__displayPropWatch ? 'Hide property inspector' : 'Show property inspector') + ')'));
1638 Util.addEvent(togglePropWatch, 'click', UI.Selector.__togglePropWatch);
1639 options.appendChild(togglePropWatch);
1642 container.appendChild(options);
1644 container.appendChild(UI.Selector.__elementList());
1646 parent.appendChild(container);
1648 UI.Selector.displaySelector(CSS.Selector.trimmed);
1651 __togglePropWatch: function() {
1652 UI.Selector.__displayPropWatch = !UI.Selector.__displayPropWatch;
1653 UI.Selector.__editSelector();
1656 __displayOverview: function(e, selectors, selector) {
1657 var parent = UI.setupPane(UI.Selector.sections, UI.Selector.controlsId, 'chameleon-selector', 'overview');
1658 UI.setupButtons('chameleon-selector-buttons');
1660 var container = Util.createElement('div', 'chameleon-style-overview-container');
1661 parent.appendChild(container); // doing it this way is much faster than creating the table then applying the overflow
1662 UI.setOverflow(container, 350, true);
1664 var overviewTable = Util.createElement('table', 'chameleon-style-overview');
1665 var overviewTableBody = Util.createElement('tbody');
1667 if (!selectors) {
1669 for (var sel in CSS.__localCSS) {
1670 var overviewTableRow = Util.createElement('tr');
1672 var overviewTableCell = Util.createElement('th');
1673 overviewTableCell.className = 'selector';
1674 overviewTableCell.appendChild(document.createTextNode(sel));
1675 overviewTableRow.appendChild(overviewTableCell);
1676 overviewTableCell = Util.createElement('td');
1678 var overviewEditLink = Util.createElement('a');
1679 overviewEditLink.value = sel;
1680 overviewEditLink.appendChild(document.createTextNode('[edit]'));
1681 Util.addEvent(overviewEditLink, 'click', UI.CSS.launchEditWindow);
1682 overviewTableCell.className = 'selector';
1683 overviewTableCell.appendChild(overviewEditLink);
1685 overviewTableRow.appendChild(overviewTableCell);
1686 overviewTableBody.appendChild(overviewTableRow);
1687 for (var prop in CSS.__localCSS[sel]) {
1688 overviewTableRow = Util.createElement('tr');
1689 overviewTableCell = Util.createElement('td');
1690 overviewTableCell.className = 'prop';
1691 overviewTableCell.appendChild(document.createTextNode(prop));
1692 overviewTableRow.appendChild(overviewTableCell);
1693 overviewTableCell = Util.createElement('td');
1694 overviewTableCell.className = 'value';
1695 overviewTableCell.appendChild(document.createTextNode(CSS.__localCSS[sel][prop]));
1696 overviewTableRow.appendChild(overviewTableCell);
1697 overviewTableBody.appendChild(overviewTableRow);
1700 } else {
1702 var n = selectors.length;
1704 if (!CSS.__localCSS[selector]) {
1705 var overviewTableRow = Util.createElement('tr');
1707 var overviewTableCell = Util.createElement('th');
1708 overviewTableCell.className = 'current-selector';
1709 overviewTableCell.appendChild(document.createTextNode(selector));
1710 overviewTableRow.appendChild(overviewTableCell);
1711 overviewTableCell = Util.createElement('td');
1713 var overviewEditLink = Util.createElement('a');
1714 overviewEditLink.value = selector;
1715 overviewEditLink.appendChild(document.createTextNode('[edit]'));
1716 Util.addEvent(overviewEditLink, 'click', UI.CSS.launchEditWindow);
1717 overviewTableCell.className = 'current-selector';
1718 overviewTableCell.appendChild(overviewEditLink);
1720 overviewTableRow.appendChild(overviewTableCell);
1721 overviewTableBody.appendChild(overviewTableRow);
1724 for (var i = 0; i < n; ++i) {
1725 var sel = selectors[i];
1727 var overviewTableRow = Util.createElement('tr');
1729 var overviewTableCell = Util.createElement('th');
1730 overviewTableCell.className = (sel == selector) ? 'current-selector' : 'selector';
1731 overviewTableCell.appendChild(document.createTextNode(sel));
1732 overviewTableRow.appendChild(overviewTableCell);
1733 overviewTableCell = Util.createElement('td');
1735 var overviewEditLink = Util.createElement('a');
1736 overviewEditLink.value = sel;
1737 overviewEditLink.appendChild(document.createTextNode('[edit]'));
1738 Util.addEvent(overviewEditLink, 'click', UI.CSS.launchEditWindow);
1739 overviewTableCell.className = (sel == selector) ? 'current-selector' : 'selector';
1740 overviewTableCell.appendChild(overviewEditLink);
1742 overviewTableRow.appendChild(overviewTableCell);
1743 overviewTableBody.appendChild(overviewTableRow);
1745 for (var prop in CSS.__localCSS[sel]) {
1746 overviewTableRow = Util.createElement('tr');
1747 overviewTableCell = Util.createElement('td');
1748 overviewTableCell.className = 'prop';
1749 overviewTableCell.appendChild(document.createTextNode(prop));
1750 overviewTableRow.appendChild(overviewTableCell);
1751 overviewTableCell = Util.createElement('td');
1752 overviewTableCell.className = 'value';
1753 overviewTableCell.appendChild(document.createTextNode(CSS.__localCSS[sel][prop]));
1754 overviewTableRow.appendChild(overviewTableCell);
1755 overviewTableBody.appendChild(overviewTableRow);
1761 overviewTable.appendChild(overviewTableBody);
1762 container.appendChild(overviewTable);
1765 __elementList: function(showComputedStyle) {
1766 if (!showComputedStyle && UI.Selector.viewedProp) {
1767 showComputedStyle = UI.Selector.viewedProp;
1770 var list = Util.createElement('ol', 'chameleon-selector-element-list');
1771 var n = struct.length;
1772 var classStr = '';
1773 var idStr = '';
1775 var pseudoClasses = ['link', 'active', 'visited', 'hover', 'focus'];
1777 while (n--) {
1778 var row = n % 2;
1780 var item = Util.createElement('li');
1781 item.className = 'row' + row;
1782 var tag = Util.createElement('span', 'chameleon-tag-name-' + n);
1783 tag.appendChild(document.createTextNode(struct[n].tagname));
1784 tag.selectorValue = struct[n].tagname;
1785 tag.position = n;
1787 UI.Selector.__autoHighlight(tag);
1789 Util.addEvent(tag, 'click', CSS.Selector.modify);
1791 item.appendChild(tag);
1793 if (idStr = struct[n].id) {
1794 var id = Util.createElement('span', 'chameleon-id-attr-' + n);
1795 id.selectorValue = struct[n].tagname + '#' + idStr;
1796 id.position = n;
1797 id.appendChild(document.createTextNode('#' + idStr));
1799 UI.Selector.__autoHighlight(id);
1801 Util.addEvent(id, 'click', CSS.Selector.modify);
1802 item.appendChild(id);
1805 if (struct[n].classname) {
1806 var classArr = struct[n].classname.split(' ');
1807 for (var i = 0; i < classArr.length; ++i) {
1808 var cn = Util.createElement('span', 'chameleon-class-attr-' + n + '-' + i);
1809 cn.selectorValue = struct[n].tagname + '.' + classArr[i];
1810 cn.position = n;
1811 cn.appendChild(document.createTextNode('.' + classArr[i]));
1813 UI.Selector.__autoHighlight(cn);
1815 Util.addEvent(cn, 'click', CSS.Selector.modify);
1816 item.appendChild(cn);
1819 if (struct[n].tagname == 'a') {
1820 for (var i = 0; i < pseudoClasses.length; ++i) {
1821 var pc = Util.createElement('span', 'chameleon-pseudo-class' + n + '-' + i);
1822 pc.selectorValue = struct[n].tagname + ':' + pseudoClasses[i];
1824 pc.position = n;
1825 pc.appendChild(document.createTextNode(':' + pseudoClasses[i]));
1827 UI.Selector.__autoHighlight(pc);
1829 Util.addEvent(pc, 'click', CSS.Selector.modify);
1830 item.appendChild(pc);
1834 if (showComputedStyle) {
1835 var sides = ['top', 'right', 'bottom', 'left'];
1837 if (document.defaultView && document.defaultView.getComputedStyle) {
1838 if (showComputedStyle == 'margin' || showComputedStyle == 'padding') {
1839 var styleVal = [];
1840 for (var i = 0; i < 4; ++i) {
1841 styleVal.push(document.defaultView.getComputedStyle(struct[n].el, null).getPropertyValue(showComputedStyle + '-' + sides[i]))
1844 if (styleVal[0] == styleVal[1] && styleVal[1] == styleVal[2] && styleVal[2] == styleVal[3]) {
1845 styleVal = styleVal[0];
1846 } else if (styleVal[0] == styleVal[2] && styleVal[1] == styleVal[3]) {
1847 styleVal = styleVal[0] + ' ' + styleVal[1];
1848 } else if (styleVal[1] == styleVal[3]) {
1849 styleVal = styleVal[0] + ' ' + styleVal[1] + ' ' + styleVal[2];
1850 } else {
1851 styleVal = styleVal.join(' ');
1853 } else {
1854 var styleVal = document.defaultView.getComputedStyle(struct[n].el, null).getPropertyValue(showComputedStyle);
1858 if (styleVal.indexOf('rgb') != -1) {
1859 styleVal = UI.Selector.__formatColor(styleVal);
1862 } else if (struct[n].el.currentStyle) {
1863 var propBits = showComputedStyle.split('-');
1864 for (var i = 1; i < propBits.length; ++i) {
1865 propBits[i] = propBits[i].charAt(0).toUpperCase() + propBits[i].substring(1);
1867 var styleVal = struct[n].el.currentStyle[propBits.join('')];
1870 var sp = Util.createElement('span');
1871 sp.className = 'prop-value';
1872 sp.appendChild(document.createTextNode(styleVal));
1874 item.appendChild(sp);
1878 list.appendChild(item);
1881 return list;
1885 __formatColor: function(color) {
1886 var newColor = '';
1887 colorBits = color.replace(/rgb\(|[ \)]/g, '').split(',');
1888 var hexCol = (colorBits[0] << 16 | colorBits[1] << 8 | colorBits[2]).toString(16);
1889 while (hexCol.length < 6) {
1890 hexCol = '0' + hexCol;
1892 return '#' + hexCol;
1896 __editCode: function() {
1897 var parent = UI.setupPane(UI.Selector.sections, UI.Selector.controlsId, 'chameleon-selector', 'free-edit');
1898 UI.setupButtons('chameleon-selector-buttons', 'revert', 'save-local', 'save-server');
1900 var container = Util.createElement('div');
1901 var textarea = Util.createElement('textarea', 'chameleon-free-edit-all-field');
1903 textarea.style.width = '100%';
1904 textarea.style.height = '350px';
1905 Util.addEvent(textarea, 'blur', CSS.FreeEdit.saveComplete);
1907 container.appendChild(textarea);
1909 parent.appendChild(container);
1910 textarea.value = CSS.toString(); // avoid Konqueror bug
1916 __selectorList: function() {
1917 return Util.createElement('ol', 'chameleon-selector-list');
1923 __createTab: function(str, fn, active, title) {
1924 var id = 'chameleon-selector-tab-' + str.replace(/ +/, '-').toLowerCase();
1925 var tab = Util.createElement('td', id);
1926 tab.appendChild(document.createTextNode(((title) ? title : str)));
1927 tab.className = (active) ? 'chameleon-selector-tab-active' : 'chameleon-selector-tab';
1928 Util.addEvent(tab, 'click', fn);
1929 return tab;
1932 __addButtons: function() {
1933 var p = Util.createElement('p', 'chameleon-selector-buttons');
1934 p.style.textAlign = 'right';
1936 p.appendChild(UI.createButton('chameleon-selector-buttons-check', 'Compare', 'Check for other similar selectors already in your styles', CSS.checkSpec));
1937 p.appendChild(UI.createButton('chameleon-selector-buttons-revert', 'Revert', 'Revert to the version currently on the server', CSS.hardReset));
1938 p.appendChild(UI.createButton('chameleon-selector-buttons-save-local', 'Save Temp', 'Save these changes to a temporary file on the server', CSS.updateTemp));
1939 p.appendChild(UI.createButton('chameleon-selector-buttons-save-server', 'Save Server', 'Save these changes to the server', CSS.updateRemote))
1940 p.appendChild(UI.createButton('chameleon-selector-buttons-edit', 'Set Styles', 'Create and edit styles for this CSS selector', UI.CSS.editWindow));
1942 return p;
1948 __autoHighlight: function(el) {
1949 if (CSS.Selector.full[el.position] && CSS.Selector.full[el.position].val == el.selectorValue) {
1950 UI.Selector.highlight(el);
1951 } else {
1952 UI.Selector.unhighlight(el);
1956 highlight: function(el) {
1957 UI.Selector.unhighlight(el);
1958 el.className += 'active-selector';
1961 unhighlight: function(el) {
1962 el.className = el.className.replace(/\bactive-selector\b/, '');
1968 displaySelector: function(selector) {
1969 var n = selector.length;
1971 var list = document.getElementById('chameleon-selector-list');
1972 if (!list && n != 0) {
1973 var parent = document.getElementById(UI.Selector.controlsId).firstChild;
1974 list = UI.Selector.__selectorList();
1975 parent.appendChild(list);
1976 } else if (list && n == 0) {
1977 Util.removeElement(list);
1978 } else if (list) {
1979 while (list.hasChildNodes()) {
1980 Util.removeElement(list.firstChild);
1984 if (n == 0) return;
1986 var item = Util.createElement('li');
1987 item.appendChild(document.createTextNode('Style ' + UI.Selector.__describe(selector[--n])));
1988 list.appendChild(item);
1989 while (n--) {
1990 item = Util.createElement('li');
1991 item.appendChild(document.createTextNode('That are descended from ' + UI.Selector.__describe(selector[n])));
1992 list.appendChild(item);
1995 UI.setOverflow(list, 100);
1998 __describe: function(txt) {
1999 if (!txt) return '';
2001 if (txt.indexOf(':') != -1) {
2002 var parts = txt.split(':');
2003 var pc = ' the "' + parts.pop() + '" state of ';
2004 txt = parts.shift();
2005 } else {
2006 var pc = '';
2009 if (txt.indexOf('#') != -1) {
2010 var parts = txt.split('#');
2011 return pc + parts[0] + ' tags with the id "' + parts[1] + '"';
2013 if (txt.indexOf('.') != -1) {
2014 var parts = txt.split('.');
2015 return pc + parts[0] + ' tags with the class "' + parts[1] + '"';
2017 return pc + txt + ' tags';
2023 UI.CSS = {
2024 redraw: null,
2025 colorType: null,
2026 controlsId: 'chameleon-style-controls',
2027 sections: ['text', 'backgrounds', 'borders-all', 'borders-separate', 'free-edit'],
2029 __borderEditGroup: true,
2031 editWindow: function(e) {
2032 if (CSS.Selector.get() == '') {
2033 UI.statusMsg('First you have to choose which item to style!', 'chameleon-notice');
2034 return;
2037 var box = document.getElementById('chameleon-style-box');
2038 if (box) UI.closeBoxes(true, box);
2040 var coords = Pos.getElement(document.getElementById('chameleon-selector-box'));
2041 var box = UI.makeDraggableBox('chameleon-style-box', coords.x + UI.boxOffsetX, coords.y + UI.boxOffsetY);
2043 var instructions = Util.createElement('p');
2044 if (!hotspotMode) {
2045 instructions.appendChild(document.createTextNode('Add/Edit styles for the CSS selector "' + CSS.Selector.get() + '"'));
2046 } else {
2047 instructions.appendChild(document.createTextNode('Add/Edit styles for ' + UI.HotSpots.getString()));
2049 instructions.className = 'chameleon-instructions';
2050 box.appendChild(instructions);
2052 var tabsContainer = Util.createElement('table', 'chameleon-style-tabs');
2053 var tabsBody = Util.createElement('tbody');
2054 var tabs = Util.createElement('tr');
2056 tabs.appendChild(UI.CSS.__createTab('Text', UI.CSS.__editText, true, 'Text'));
2057 tabs.appendChild(UI.CSS.__createTab('Backgrounds', UI.CSS.__editBackgrounds, false, 'Backgrounds'));
2058 tabs.appendChild(UI.CSS.__createTab('Borders (All)', UI.CSS.__editBordersAll, false, 'Borders (All)'));
2059 tabs.appendChild(UI.CSS.__createTab('Borders (Separate)', UI.CSS.__editBordersSeparate, false, 'Borders (Separate)'));
2060 tabs.appendChild(UI.CSS.__createTab('Free Edit', UI.CSS.__editCode, false, 'Free Edit'));
2062 tabsBody.appendChild(tabs);
2063 tabsContainer.appendChild(tabsBody);
2065 box.appendChild(tabsContainer);
2067 var styleControls = Util.createElement('div', UI.CSS.controlsId);
2068 box.appendChild(styleControls);
2069 box.appendChild(UI.CSS.__addButtons());
2071 UI.addToDoc(box);
2073 UI.CSS.__editText();
2078 launchEditWindow: function(e) {
2079 var target = e.target || e.srcElement;
2080 CSS.Selector.set(target.value);
2081 UI.CSS.editWindow(e);
2085 __editText: function(e, redraw) {
2086 UI.CSS.redraw = arguments.callee;
2087 UI.CSS.colorType = 'color';
2089 var containerTable = document.getElementById('chameleon-style-edit-text-container');
2090 if (!containerTable) {
2091 var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'text');
2092 containerTable = Util.createElement('table', 'chameleon-style-edit-text-container');
2093 var container = Util.createElement('tbody');
2095 var row = UI.CSS.__inputField('color', '-input-color', Check.color);
2096 container.appendChild(row.node);
2098 row = UI.CSS.__selectBox('font-family', '-select-font-family', Check.fontFamily, Config.FONTS_LIST);
2099 container.appendChild(row.node);
2101 row = UI.CSS.__inputField('font-family', '-input-font-family', Check.fontFamily, !row.meta.sel);
2102 container.appendChild(row.node);
2104 row = UI.CSS.__inputField('font-size', '-input-font-size', Check.fontSize);
2105 container.appendChild(row.node);
2107 row = UI.CSS.__inputField('line-height', '-input-line-height', Check.lineHeight);
2108 container.appendChild(row.node);
2110 row = UI.CSS.__selectBox('font-weight', '-select-font-weight', Check.fontWeight, Config.FONT_WEIGHTS);
2111 container.appendChild(row.node);
2113 row = UI.CSS.__selectBox('font-style', '-select-font-style', Check.fontStyle, Config.FONT_STYLES);
2114 container.appendChild(row.node);
2116 row = UI.CSS.__selectBox('text-align', '-select-text-align', Check.textAlign, Config.TEXT_ALIGN);
2117 container.appendChild(row.node);
2119 row = UI.CSS.__selectBox('text-decoration', '-select-text-decoration', Check.textDecoration, Config.TEXT_DECORATION);
2120 container.appendChild(row.node);
2122 containerTable.appendChild(container);
2123 parent.appendChild(containerTable);
2124 } else {
2125 if (redraw == 'color') {
2126 UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
2131 __editBackgrounds: function(e, redraw) {
2132 UI.CSS.redraw = arguments.callee;
2133 UI.CSS.colorType = 'background-color';
2135 var containerTable = document.getElementById('chameleon-style-edit-backgrounds-container');
2136 if (!containerTable) {
2137 var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'backgrounds');
2138 containerTable = Util.createElement('table', 'chameleon-style-edit-backgrounds-container');
2139 var container = Util.createElement('tbody');
2141 var row = UI.CSS.__inputField('background-color', '-input-background-color', Check.color);
2142 container.appendChild(row.node);
2144 row = UI.CSS.__inputField('background-image', '-input-background-image', Check.backgroundImage);
2145 container.appendChild(row.node);
2147 var extraFields = row.meta;
2149 row = UI.CSS.__selectBox('background-repeat', '-select-background-repeat', Check.backgroundRepeat, Config.REPEAT_LIST, !extraFields);
2150 container.appendChild(row.node);
2152 row = UI.CSS.__selectBox('background-position', '-select-background-position', Check.backgroundPosition, Config.POSITION_LIST, !extraFields);
2153 container.appendChild(row.node);
2155 containerTable.appendChild(container);
2156 parent.appendChild(containerTable);
2157 } else {
2158 if (redraw == 'color') {
2159 UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
2160 } else if (redraw == 'image') {
2161 var val = UI.CSS.__getPropValue('background-image');
2162 UI.CSS.__setImageDisplay(val);
2163 if (val == 'none' || val == '') {
2164 document.getElementById(UI.CSS.controlsId + '-row-select-background-repeat').style.display = 'none';
2165 document.getElementById(UI.CSS.controlsId + '-row-select-background-position').style.display = 'none';
2166 } else {
2167 try {
2168 document.getElementById(UI.CSS.controlsId + '-row-select-background-repeat').style.display = 'table-row';
2169 document.getElementById(UI.CSS.controlsId + '-row-select-background-position').style.display = 'table-row';
2170 } catch(e) {
2171 document.getElementById(UI.CSS.controlsId + '-row-select-background-repeat').style.display = 'block';
2172 document.getElementById(UI.CSS.controlsId + '-row-select-background-position').style.display = 'block';
2177 var imgPreview = document.getElementById('chameleon-image-preview');
2178 if (imgPreview) {
2179 imgPreview.setAttribute('width', '20');
2180 imgPreview.setAttribute('height', '20');
2184 __editBordersAll: function(e, redraw) {
2185 UI.CSS.redraw = arguments.callee;
2186 UI.CSS.colorType = 'border-color';
2188 var containerTable = document.getElementById('chameleon-style-edit-borders-all-container');
2189 if (!containerTable) {
2191 var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'borders-all');
2192 containerTable = Util.createElement('table', 'chameleon-style-edit-borders-all-container');
2193 var container = Util.createElement('tbody');
2195 var row = UI.CSS.__inputField('border-width', '-input-border-width', Check.borderWidth);
2196 container.appendChild(row.node);
2198 row = UI.CSS.__inputField('border-color', '-input-border-color', Check.color);
2199 container.appendChild(row.node);
2201 row = UI.CSS.__selectBox('border-style', '-select-border-style', Check.borderStyle, Config.BORDER_LIST);
2202 container.appendChild(row.node);
2204 containerTable.appendChild(container);
2205 parent.appendChild(containerTable);
2206 } else {
2207 if (redraw == 'color') {
2208 UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
2213 __editBordersSeparate: function(e, redraw) {
2214 UI.CSS.redraw = arguments.callee;
2216 var containerTable = document.getElementById('chameleon-style-edit-borders-separate-container');
2217 if (!containerTable) {
2218 var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'borders-separate');
2219 containerTable = Util.createElement('table', 'chameleon-style-edit-borders-separate-container');
2220 var container = Util.createElement('tbody');
2222 var row = UI.CSS.__inputField('border-top-width', '-input-border-top-width', Check.borderWidth);
2223 container.appendChild(row.node);
2225 row = UI.CSS.__inputField('border-top-color', '-input-border-top-color', Check.color, false, UI.CSS.__setColorType);
2226 container.appendChild(row.node);
2228 row = UI.CSS.__selectBox('border-top-style', '-select-border-top-style', Check.borderStyle, Config.BORDER_LIST);
2229 container.appendChild(row.node);
2232 row = UI.CSS.__inputField('border-right-width', '-input-border-right-width', Check.borderWidth);
2233 container.appendChild(row.node);
2235 row = UI.CSS.__inputField('border-right-color', '-input-border-right-color', Check.color, false, UI.CSS.__setColorType);
2236 container.appendChild(row.node);
2238 row = UI.CSS.__selectBox('border-right-style', '-select-border-right-style', Check.borderStyle, Config.BORDER_LIST);
2239 container.appendChild(row.node);
2242 row = UI.CSS.__inputField('border-bottom-width', '-input-border-bottom-width', Check.borderWidth);
2243 container.appendChild(row.node);
2245 row = UI.CSS.__inputField('border-bottom-color', '-input-border-bottom-color', Check.color, false, UI.CSS.__setColorType);
2246 container.appendChild(row.node);
2248 row = UI.CSS.__selectBox('border-bottom-style', '-select-border-bottom-style', Check.borderStyle, Config.BORDER_LIST);
2249 container.appendChild(row.node);
2252 row = UI.CSS.__inputField('border-left-width', '-input-border-left-width', Check.borderWidth);
2253 container.appendChild(row.node);
2255 row = UI.CSS.__inputField('border-left-color', '-input-border-left-color', Check.color, false, UI.CSS.__setColorType);
2256 container.appendChild(row.node);
2258 row = UI.CSS.__selectBox('border-left-style', '-select-border-left-style', Check.borderStyle, Config.BORDER_LIST);
2259 container.appendChild(row.node);
2261 containerTable.appendChild(container);
2262 parent.appendChild(containerTable);
2263 } else {
2264 if (redraw == 'color') {
2265 UI.CSS.__setColorDisplay(UI.CSS.colorType, UI.CSS.__getPropValue(UI.CSS.colorType));
2270 __editCode: function(e) {
2271 UI.CSS.redraw = arguments.callee;
2273 var parent = UI.setupPane(UI.CSS.sections, UI.CSS.controlsId, 'chameleon-style', 'free-edit');
2275 var container = Util.createElement('div');
2276 var textarea = Util.createElement('textarea', 'chameleon-free-edit-field');
2278 textarea.style.width = '100%';
2279 textarea.style.height = '350px';
2281 Util.addEvent(textarea, 'focus', CSS.FreeEdit.setInitial);
2282 Util.addEvent(textarea, 'blur', CSS.FreeEdit.saveSelector);
2284 container.appendChild(textarea);
2285 parent.appendChild(container);
2286 textarea.value = CSS.getSelectorCSS(); // avoid Konqueror bug
2295 __getPropValue: function(prop) {
2296 var val = UI.CSS.__getBorderPropValue(prop);
2297 if (val === '') {
2298 return false;
2301 if (val === false) {
2302 val = CSS.getPropValue(prop);
2304 return val;
2308 __setColorDisplay: function(prop, value, field, picker) {
2309 if (!field) var field = document.getElementById(UI.CSS.controlsId + '-input-' + prop);
2310 if (!picker) var picker = document.getElementById(UI.CSS.controlsId + '-color-picker-' + prop);
2312 if (!field || !picker) return;
2314 field.value = value;
2315 try {
2316 picker.style.backgroundColor = (value != '') ? value.replace(/[ ]*\!important/, '') : '#000';
2317 if (!picker.style.backgroundColor) {
2318 UI.statusMsg(value + ' is an Invalid color!', 'chameleon-error');
2320 } catch(e) {
2321 UI.statusMsg(value + ' is an Invalid color!', 'chameleon-error');
2325 __setImageDisplay: function(value, field, picker) {
2326 if (!field) var field = document.getElementById(UI.CSS.controlsId + '-input-background-image');
2327 if (!picker) var picker = document.getElementById(UI.CSS.controlsId + '-background-image-picker');
2329 var preview = document.getElementById('chameleon-image-preview');
2331 if (!field || !picker) return;
2333 field.value = value;
2334 if (value != '') {
2335 if (!preview) {
2336 preview = Util.createElement('img', 'chameleon-image-preview');
2337 picker.appendChild(preview);
2340 if (field.value != 'none') {
2341 preview.setAttribute('src', CSS.fixPath(value.replace(/[ ]*\!important/, '')));
2342 } else {
2343 preview.setAttribute('src', CSS.fixPath('ui/images/none.gif'));
2345 preview.setAttribute('title', 'Open image picker');
2346 Util.addEvent(preview, 'click', UI.CSS.__loadImagePicker);
2348 picker.style.backgroundColor = 'transparent';
2349 } else {
2350 if (preview) {
2351 Util.removeElement(preview);
2353 picker.style.backgroundColor = '#000';
2354 picker.setAttribute('title', 'Open image picker');
2355 Util.addEvent(picker, 'click', UI.CSS.__loadImagePicker);
2361 __shorthandWarningIcon: function() {
2362 var img = Util.createElement('img');
2363 img.setAttribute('src', CSS.fixPath('ui/images/notice.gif'));
2364 img.style.margin = '0 2px -5px 0';
2365 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.');
2366 return img;
2369 __inputField: function(prop, id, validate, hidden, init) {
2370 var row = Util.createElement('tr', UI.CSS.controlsId + '-row' + id);
2371 id = UI.CSS.controlsId + id;
2373 var labelCell = Util.createElement('td');
2374 var fieldCell = Util.createElement('td');
2376 var field = Util.createElement('input', id);
2377 field.setAttribute('type', 'text');
2378 field.className = 'chameleon-input-text';
2381 var val = UI.CSS.__getPropValue(prop);
2382 if (val !== false) {
2383 field.value = val;
2384 } else {
2385 labelCell.appendChild(UI.CSS.__shorthandWarningIcon());
2388 Util.addEvent(field, 'blur', validate);
2389 if (init) {
2390 Util.addEvent(field, 'focus', init);
2393 labelCell.appendChild(document.createTextNode(UI.CSS.__formatProp(prop) + ': '));
2394 labelCell.className = 'label';
2396 fieldCell.appendChild(field);
2398 row.appendChild(labelCell);
2399 row.appendChild(fieldCell);
2401 if (prop == 'color' || prop.indexOf('-color') != -1) {
2402 var colorCell = Util.createElement('td');
2403 var colorPicker = Util.createElement('div', UI.CSS.controlsId + '-color-picker-' + prop);
2405 colorPicker.setAttribute('title', 'Open color picker');
2406 UI.CSS.__setColorDisplay(prop, field.value, field, colorPicker);
2408 Util.addEvent(colorPicker, 'click', UI.CSS.__displayColorPicker);
2409 if (init) {
2410 Util.addEvent(colorPicker, 'click', init);
2413 colorCell.appendChild(colorPicker);
2414 row.appendChild(colorCell);
2415 } else if (prop.indexOf('-image') != -1) {
2416 var imgCell = Util.createElement('td');
2417 var imgPicker = Util.createElement('div', UI.CSS.controlsId + '-background-image-picker');
2419 UI.CSS.__setImageDisplay(field.value, field, imgPicker);
2421 imgCell.appendChild(imgPicker);
2422 row.appendChild(imgCell);
2424 } else {
2425 fieldCell.setAttribute('colspan', '2');
2427 if (hidden) {
2428 row.style.display = 'none';
2430 return {node: row, meta: (field.value == 'none') ? false : field.value};
2434 __selectBox: function(prop, id, validate, src, hidden) {
2435 var row = Util.createElement('tr', UI.CSS.controlsId + '-row' + id);
2436 id = UI.CSS.controlsId + id;
2438 var labelCell = Util.createElement('td');
2439 var fieldCell = Util.createElement('td');
2440 fieldCell.setAttribute('colspan', '2');
2442 var currentValue = UI.CSS.__getPropValue(prop);
2443 if (currentValue === false) {
2444 labelCell.appendChild(UI.CSS.__shorthandWarningIcon());
2445 currentValue = '';
2448 labelCell.appendChild(document.createTextNode(UI.CSS.__formatProp(prop) + ': '));
2449 labelCell.className = 'label';
2451 var field = Util.createElement('select', id);
2452 var op = Util.createElement('option');
2453 op.setAttribute('value', '');
2454 op.appendChild(document.createTextNode('Please select'));
2455 field.appendChild(op);
2457 var selected = false;
2458 var otherSelected = false;
2460 for (var i = 0; i < src.length; ++i) {
2461 op = Util.createElement('option');
2462 op.setAttribute('value', src[i]);
2463 op.appendChild(document.createTextNode(src[i]));
2464 if (src[i] != 'other' && src[i] == currentValue) {
2465 op.setAttribute('selected', 'selected');
2466 selected = true;
2467 } else if (src[i].toLowerCase() == 'other' && currentValue != '' && !selected) {
2468 op.setAttribute('selected', 'selected');
2469 selected = true;
2470 otherSelected = true;
2472 field.appendChild(op);
2475 Util.addEvent(field, 'change', validate);
2477 fieldCell.appendChild(field);
2478 row.appendChild(labelCell);
2479 row.appendChild(fieldCell);
2481 if (hidden) {
2482 row.style.display = 'none';
2485 return {node: row, meta: {sel: otherSelected, value: currentValue}};
2490 __createTab: function(str, fn, active, title) {
2491 var id = 'chameleon-style-tab-' + str.replace(/[\( ]+/, '-').replace(/[\)]+/, '').toLowerCase();
2492 var tab = Util.createElement('td', id);
2493 tab.appendChild(document.createTextNode((title) ? title : str));
2494 tab.className = (active) ? 'chameleon-style-tab-active' : 'chameleon-style-tab';
2495 Util.addEvent(tab, 'click', fn);
2496 return tab;
2499 __addButtons: function() {
2500 var p = Util.createElement('p', 'chameleon-style-buttons');
2501 p.style.textAlign = 'right';
2503 p.appendChild(UI.createButton('chameleon-style-buttons-revert', 'Revert', 'Discard all temporarily saved changes', CSS.hardReset));
2504 p.appendChild(UI.createButton('chameleon-style-buttons-save-local', 'Save Temp', 'Save these changes in a temporary file on the server', CSS.updateTemp));
2505 p.appendChild(UI.createButton('chameleon-style-buttons-save-server', 'Save Server', 'Save these changes to the server', CSS.updateRemote));
2507 return p;
2510 __formatProp: function(txt) {
2511 if (txt.length > 15 && txt.indexOf('-') != -1) {
2512 return txt.split('-').slice(1).join('-');
2514 return txt;
2520 __loadImagePicker: function(e) {
2521 var target = e.target || e.srcElement;
2523 if (target.value) {
2524 UI.statusMsg('Loading file list for ' + target.value + '...', 'chameleon-working');
2525 FileHandler.getFiles(target.value);
2526 } else {
2527 UI.statusMsg('Loading file list...', 'chameleon-working');
2528 FileHandler.getFiles('root');
2532 displayImagePicker: function(xmldata) {
2533 UI.clearStatusMsg();
2535 var box = document.getElementById('chameleon-file-box');
2536 if (box) UI.closeBoxes(true, box);
2538 var coords = Pos.getElement(document.getElementById('chameleon-style-box'));
2539 box = UI.makeDraggableBox('chameleon-file-box', coords.x + UI.boxOffsetX, coords.y + UI.boxOffsetY);
2541 if (xmldata.firstChild.nodeName.toLowerCase() == 'chameleon_error') {
2542 UI.statusMsg('There was an error reading files from the server:\n' + xmldata.firstChild.firstChild.nodeValue + '.', 'chameleon-error');
2543 return;
2546 var files = xmldata.firstChild;
2547 var hasFiles = false;
2549 var infoTable = Util.createElement('table');
2550 var infoTableBody = Util.createElement('tbody');
2551 var infoTableRow = Util.createElement('tr');
2553 var path = files.getAttribute('path');
2554 if (path.indexOf('/') != -1) {
2555 var parentPath = path.substring(0, path.lastIndexOf('/'));
2556 var parentCell = Util.createElement('td');
2557 var parentLink = Util.createElement('p', 'chameleon-files-parent');
2558 parentLink.value = parentPath;
2559 parentLink.className = 'chameleon-image-folder';
2560 parentLink.appendChild(document.createTextNode('Parent folder'));
2561 Util.addEvent(parentLink, 'click', UI.CSS.__loadImagePicker);
2562 parentCell.appendChild(parentLink);
2563 infoTableRow.appendChild(parentCell);
2566 var location = Util.createElement('td', 'chameleon-files-location');
2567 var locationPara = Util.createElement('p');
2568 var locationTxt = Util.createElement('span');
2569 locationTxt.appendChild(document.createTextNode('Location: '));
2570 locationPara.appendChild(locationTxt);
2571 locationPara.appendChild(document.createTextNode(path));
2572 location.appendChild(locationPara);
2574 infoTableRow.appendChild(location);
2575 infoTableBody.appendChild(infoTableRow);
2576 infoTable.appendChild(infoTableBody);
2577 box.appendChild(infoTable);
2579 var fileList = Util.createElement('div');
2581 for (var i = 0; i < files.childNodes.length; ++i) {
2582 if (files.childNodes[i].nodeType != Node.ELEMENT_NODE) {
2583 continue;
2585 hasFiles = true;
2587 var fileItemContainer = Util.createElement('p');
2588 var fileItem = Util.createElement('span');
2589 fileItem.value = files.childNodes[i].firstChild.nodeValue;
2590 fileItem.appendChild(document.createTextNode(fileItem.value.split('/').pop()));
2591 if (files.childNodes[i].getAttribute('type') == 'img') {
2592 Util.addEvent(fileItem, 'click', Check.backgroundImage);
2593 } else {
2594 fileItemContainer.className = 'chameleon-image-folder';
2595 Util.addEvent(fileItem, 'click', UI.CSS.__loadImagePicker);
2597 fileItemContainer.appendChild(fileItem);
2598 fileList.appendChild(fileItemContainer);
2601 if (!hasFiles) {
2602 var fileItem = Util.createElement('p');
2603 fileItem.appendChild(document.createTextNode('No images were found in this folder'));
2604 fileList.appendChild(fileItem);
2607 box.appendChild(fileList);
2608 UI.addToDoc(box);
2610 UI.setOverflow(fileList, 350);
2616 __displayColorPicker: function(e) {
2617 var box = document.getElementById('chameleon-color-box');
2618 if (box) UI.closeBoxes(true, box);
2620 var extraColors = ['000000', '333333', '666666', '999999', 'cccccc', 'ffffff', 'ff0000', '00ff00', '0000ff', 'ffff00', 'ff00ff', '00ffff'];
2622 var coords = Pos.getElement(document.getElementById('chameleon-style-box'));
2623 box = UI.makeDraggableBox('chameleon-color-box', coords.x + UI.boxOffsetX, coords.y + UI.boxOffsetY);
2625 var container = Util.createElement('div', 'chameleon-color-palette');
2626 box.appendChild(container);
2628 var x = 0; var y = 0; var xx = 0; var yi = 0;
2629 for (var r = 0; r < 256; r += 51) {
2630 for (var g = 0; g < 256; g += 51) {
2631 for (var b = 0; b < 256; b += 51) {
2632 var col = (r << 16 | g << 8 | b).toString(16);
2633 while (col.length < 6) {
2634 col = '0' + col;
2637 yi = (xx > 17) ? 5 : 0;
2639 var colorTab = Util.createElement('div');
2640 colorTab.style.position = 'absolute';
2641 colorTab.style.left = ((15 * x) + 17) + 'px';
2642 colorTab.style.top = (15 * (yi + y)) + 'px';
2643 colorTab.style.width = colorTab.style.height = '15px';
2644 colorTab.style.backgroundColor = colorTab.value = '#' + col;
2646 colorTab.setAttribute('title', '#' + col);
2648 container.appendChild(colorTab);
2650 if (x == 17) {
2651 x = 0;
2652 if (xx == 35) {
2653 xx = 0;
2654 } else {
2655 ++xx;
2656 ++y;
2658 } else {
2659 ++x;
2660 ++xx;
2666 for (var i = 0; i < extraColors.length; ++i) {
2667 var colorTab = Util.createElement('div');
2668 colorTab.style.position = 'absolute';
2669 colorTab.style.left = '0px';
2670 colorTab.style.top = (15 * i) + 'px';
2671 colorTab.style.width = colorTab.style.height = '15px';
2672 colorTab.style.backgroundColor = colorTab.value = '#' + extraColors[i];
2674 colorTab.setAttribute('title', '#' + extraColors[i]);
2676 container.appendChild(colorTab);
2679 Util.addEvent(container, 'click', Check.color);
2681 container.style.height = (((y + yi) * 15) + 20) + 'px';
2683 UI.addToDoc(box);
2688 __setColorType: function(e) {
2689 var target = e.target || e.srcElement;
2691 UI.CSS.colorType = UI.CSS.getBorderProp(target.id);
2695 getBorderProp: function(id) {
2696 var separators = ['color-picker', 'input', 'select'];
2697 for (var i = 0; i < separators.length; ++i) {
2698 if (id.indexOf('-' + separators[i] + '-') != -1) {
2699 return id.split('-' + separators[i] + '-').pop();
2702 return '';
2705 __getBorderPropValue: function(prop) {
2706 var matches = prop.match(/^border\-([^\-]+)$/);
2707 if (matches) {
2708 var p1 = CSS.getPropValue('border-left-' + matches[1]);
2709 var p2 = CSS.getPropValue('border-right-' + matches[1]);
2710 var p3 = CSS.getPropValue('border-top-' + matches[1]);
2711 var p4 = CSS.getPropValue('border-bottom-' + matches[1]);
2712 if (!p1 && !p2 && !p3 && !p4) {
2713 return false;
2716 if (!(p1 && p2 && p3 && p4)) {
2717 return '';
2720 return (p1 == p2 && p2 == p3 && p3 == p4) ? p1 : '';
2722 return false;
2729 UI.HotSpots = {
2730 __selectors: null,
2731 __counter: 0,
2732 __lookup: {},
2734 init: function() {
2735 var box = Util.createElement('div', 'chameleon-launch-hotspots');
2736 box.appendChild(document.createTextNode('Load hotspots'));
2737 box.style.zIndex = ++UI.zIndex;
2739 box.hotSpotsOn = false;
2740 Util.addEvent(box, 'click', UI.HotSpots.__load);
2742 UI.addToDoc(box);
2745 getString: function() {
2746 var sel = CSS.Selector.get();
2747 if (UI.HotSpots.__selectors[sel]) {
2748 return UI.HotSpots.__selectors[sel] + '.';
2750 return '"' + sel + '"';
2753 __load: function(e) {
2754 var target = e.target || e.srcElement;
2755 target.hotSpotsOn = !target.hotSpotsOn;
2757 UI.HotSpots.__counter = 0;
2758 UI.HotSpots.__lookup = {};
2760 if (!target.hotSpotsOn) {
2761 target.firstChild.nodeValue = 'Show hotspots';
2762 UI.HotSpots.__clear();
2763 return;
2765 target.firstChild.nodeValue = 'Hide hotspots';
2767 if (!UI.HotSpots.__selectors) {
2768 UI.HotSpots.__selectors = {};
2769 UI.HotSpots.__selectors['body'] = 'The body of the page (all pages)';
2770 UI.HotSpots.__selectors['body#site-index'] = 'The body of the homepage';
2771 UI.HotSpots.__selectors['body#course-view'] = 'The body of the course index page';
2772 UI.HotSpots.__selectors['div#header'] = 'The page header';
2773 UI.HotSpots.__selectors['div#header-home'] = 'The page header on the homepage';
2774 UI.HotSpots.__selectors['div#header-home h1.headermain'] = 'The header text on the homepage';
2775 UI.HotSpots.__selectors['div#header h1.headermain'] = 'The header text';
2776 UI.HotSpots.__selectors['div.sideblock'] = 'Blocks';
2777 UI.HotSpots.__selectors['td#right-column div.sideblock'] = 'Blocks in the right hand column';
2778 UI.HotSpots.__selectors['td#left-column div.sideblock'] = 'Blocks in the left hand column';
2779 UI.HotSpots.__selectors['div.sideblock div.header'] = 'The block headings';
2780 UI.HotSpots.__selectors['td#right-column div.sideblock div.header'] = 'The block headings in the right hand column';
2781 UI.HotSpots.__selectors['td#left-column div.sideblock div.header'] = 'The block headings in the left hand column';
2782 UI.HotSpots.__selectors['div.sideblock div.title'] = 'The text in the block headings';
2783 UI.HotSpots.__selectors['td#right-column div.sideblock div.title'] = 'The text in the block headings in the right hand column';
2784 UI.HotSpots.__selectors['td#left-column div.sideblock div.title'] = 'The text in the block headings in the left hand column';
2785 UI.HotSpots.__selectors['div.headingblock'] = 'The heading at the top of the middle column';
2786 UI.HotSpots.__selectors['table.topics'] = 'The topic sections in a course';
2787 UI.HotSpots.__selectors['table.topics td.side'] = 'The sides of the topic sections';
2788 UI.HotSpots.__selectors['table.topics td.left'] = 'The left side of the topic sections';
2789 UI.HotSpots.__selectors['table.topics td.right'] = 'The right side of the topic sections';
2790 UI.HotSpots.__selectors['table.topics tr.current div.summary'] = 'The summary of the highlighted topic';
2791 UI.HotSpots.__selectors['table.topics tr.current td.content'] = 'The content of the highlighted topic';
2792 UI.HotSpots.__selectors['a'] = 'Links';
2793 UI.HotSpots.__selectors['a.dimmed'] = 'Greyed out links';
2794 UI.HotSpots.__selectors['div#footer'] = 'The footer of the page';
2795 UI.HotSpots.__selectors['div.logininfo'] = 'The "You are logged in as..." text';
2796 UI.HotSpots.__selectors['div.navbar'] = 'The navigation bar';
2797 UI.HotSpots.__selectors['div.breadcrumb'] = 'The navigation trail';
2798 UI.HotSpots.__selectors['table.generaltable tr.r0'] = 'Odd numbered table rows';
2799 UI.HotSpots.__selectors['table.generaltable tr.r1'] = 'Even numbered table rows';
2802 UI.HotSpots.__parse();
2805 __parse: function() {
2806 var pos = {};
2808 for (var sel in UI.HotSpots.__selectors) {
2809 var matches = cssQuery(sel);
2810 var nm = matches.length;
2811 if (!nm) {
2812 continue;
2815 for (var j = 0; j < nm; ++j) {
2816 if (matches[j].hasAttribute && matches[j].hasAttribute('id') && matches[j].getAttribute('id').indexOf('chameleon') != -1) {
2817 continue;
2820 if (!matches[j].chameleonHotspotId) {
2821 var coords = Pos.getElement(matches[j]);
2822 coords.x = 20 * Math.round(coords.x / 20);
2823 coords.y = 20 * Math.round(coords.y / 20);
2825 while (pos[coords.x + '-' + coords.y]) {
2826 coords.x += 20;
2828 pos[coords.x + '-' + coords.y] = true;
2830 var button = UI.HotSpots.__makeButton(UI.HotSpots.__selectors[sel], coords.x, coords.y);
2831 UI.addToDoc(button);
2833 matches[j].chameleonHotspotId = button.id;
2834 UI.HotSpots.__lookup[button.id] = sel;
2835 break;
2836 } else {
2837 UI.HotSpots.__lookup[matches[j].chameleonHotspotId] += '|' + sel;
2838 document.getElementById(matches[j].chameleonHotspotId).title += ", " + UI.HotSpots.__selectors[sel];
2840 break;
2845 pos = null;
2846 matches = null;
2850 __clear: function() {
2851 for (var sel in UI.HotSpots.__selectors) {
2852 var matches = cssQuery(sel);
2853 var nm = matches.length;
2854 if (!nm) {
2855 continue;
2858 for (var j = 0; j < nm; ++j) {
2859 if (matches[j].chameleonHotspotId) {
2860 UI.HotSpots.__lookup[matches[j].chameleonHotspotId] = null;
2861 Util.removeElement(document.getElementById(matches[j].chameleonHotspotId));
2862 matches[j].chameleonHotspotId = null;
2863 break;
2870 __makeButton: function(title, x, y) {
2871 var d = Util.createElement('img', 'chameleon-hotspot-' + ++UI.HotSpots.__counter);
2872 d.style.width = d.style.height = '20px';
2873 d.style.position = 'absolute';
2874 d.style.left = (x - 5) + 'px';
2875 d.style.top = (y + 15) + 'px';
2876 d.style.cursor = 'pointer';
2878 d.setAttribute('src', CSS.fixPath('ui/images/hotspot.gif'));
2879 d.setAttribute('title', title);
2880 Util.addEvent(d, 'click', UI.HotSpots.__launch);
2881 return d;
2884 __launch: function(e) {
2885 var target = e.target || e.srcElement;
2886 var selectors = UI.HotSpots.__lookup[target.id].split('|');
2888 var coords = Pos.getMouse(e);
2890 hotspotMode = true;
2892 var box = document.getElementById('chameleon-selector-box');
2893 if (box) UI.closeBoxes(true, box);
2895 var box = UI.makeDraggableBox('chameleon-selector-box', coords.x, coords.y);
2897 if (selectors.length > 1) {
2898 var instructions = Util.createElement('p');
2899 instructions.appendChild(document.createTextNode('This element matches more than one selector, please choose which you would like to style.'));
2900 instructions.className = 'chameleon-instructions';
2901 box.appendChild(instructions);
2904 var selList = Util.createElement('ul');
2905 for (var i = 0; i < selectors.length; ++i) {
2906 var item = Util.createElement('li');
2907 var itemLink = Util.createElement('a');
2908 itemLink.appendChild(document.createTextNode('Add/Edit styles for ' + UI.HotSpots.__selectors[selectors[i]]));
2909 itemLink.value = selectors[i];
2910 Util.addEvent(itemLink, 'click', UI.HotSpots.__launchCSSEditor);
2912 item.appendChild(itemLink);
2914 selList.appendChild(item);
2916 box.appendChild(selList);
2918 UI.addToDoc(box);
2921 __launchCSSEditor: function(e, value) {
2922 var target = e.target || e.srcElement;
2924 if (!value) {
2925 var value = target.value;
2927 CSS.Selector.set(value);
2928 UI.CSS.editWindow(e);
2938 var Check = {
2939 color: function(e) {
2940 var target = e.target || e.srcElement;
2941 if (e.type == 'click' && !target.value) return;
2943 var originalColor = UI.CSS.__getPropValue(UI.CSS.colorType);
2944 if (originalColor != target.value) {
2945 CSS.setPropValue(UI.CSS.colorType, target.value);
2946 UI.CSS.redraw.call(null, null, 'color');
2948 if (e.type == 'click') {
2949 UI.closeBoxes(true, target.parentNode.parentNode);
2953 backgroundImage: function(e) {
2954 var target = e.target || e.srcElement;
2956 CSS.setPropValue('background-image', target.value);
2957 UI.CSS.redraw.call(null, null, 'image');
2958 if (e.type == 'click') {
2959 UI.closeBoxes(true, document.getElementById('chameleon-file-box'));
2963 backgroundRepeat: function(e) {
2964 var target = e.target || e.srcElement;
2965 var value = target.options[target.options.selectedIndex].value.toLowerCase();
2966 CSS.setPropValue('background-repeat', value);
2969 backgroundPosition: function(e) {
2970 var target = e.target || e.srcElement;
2971 var value = target.options[target.options.selectedIndex].value.toLowerCase();
2972 CSS.setPropValue('background-position', value);
2975 borderWidth: function(e) {
2976 var target = e.target || e.srcElement;
2978 var hasUnits = false;
2979 for (var i = 0; i < Config.UNITS.length; ++i) {
2980 if (target.value.indexOf(Config.UNITS[i]) > 0) {
2981 hasUnits = true;
2982 break;
2986 var val = parseInt(target.value);
2987 if (isNaN(val)) {
2988 if (!target.value.match(/thin|medium|thick/)) {
2989 target.value = '';
2991 } else if (!hasUnits) {
2992 target.value = val + 'px';
2994 CSS.setPropValue(UI.CSS.getBorderProp(target.id), target.value);
2997 borderStyle: function(e) {
2998 var target = e.target || e.srcElement;
2999 var value = target.options[target.options.selectedIndex].value.toLowerCase();
3000 CSS.setPropValue(UI.CSS.getBorderProp(target.id), value);
3003 fontStyle: function(e) {
3004 var target = e.target || e.srcElement;
3005 var value = target.options[target.options.selectedIndex].value.toLowerCase();
3006 CSS.setPropValue('font-style', value);
3009 fontWeight: function(e) {
3010 var target = e.target || e.srcElement;
3011 var value = target.options[target.options.selectedIndex].value.toLowerCase();
3012 CSS.setPropValue('font-weight', value);
3015 fontSize: function(e) {
3016 var target = e.target || e.srcElement;
3017 CSS.setPropValue('font-size', target.value);
3020 lineHeight: function(e) {
3021 var target = e.target || e.srcElement;
3022 CSS.setPropValue('line-height', target.value);
3025 fontFamily: function(e) {
3026 var target = e.target || e.srcElement;
3027 var n = target.nodeName.toLowerCase();
3029 if (n == 'select') {
3030 var value = target.options[target.options.selectedIndex].value.toLowerCase();
3031 var fontFamilyInputRow = target.parentNode.parentNode.nextSibling;
3032 if (value == 'other') {
3033 try {
3034 fontFamilyInputRow.style.display = 'table-row';
3035 } catch(e) {
3036 fontFamilyInputRow.style.display = 'block';
3038 } else {
3039 if (value != '') {
3040 fontFamilyInputRow.style.display = 'none';
3042 CSS.setPropValue('font-family', value);
3044 } else {
3045 CSS.setPropValue('font-family', target.value);
3049 textDecoration: function(e) {
3050 var target = e.target || e.srcElement;
3051 var value = target.options[target.options.selectedIndex].value.toLowerCase();
3052 CSS.setPropValue('text-decoration', value);
3055 textAlign: function(e) {
3056 var target = e.target || e.srcElement;
3057 var value = target.options[target.options.selectedIndex].value.toLowerCase();
3058 CSS.setPropValue('text-align', value);
3076 var debugMsg = function(msg) {
3077 //if (window.opera) window.opera.postError(msg);
3083 var climbTree = function(src) {
3084 var struct = [];
3085 while (src.parentNode) {
3086 if (src.nodeType == Node.ELEMENT_NODE) {
3087 if (src.getAttribute && src.getAttribute('id') && src.getAttribute('id').indexOf('chameleon-') != -1) {
3088 return src.getAttribute('id');
3090 var elementObj = {tagname: src.nodeName.toLowerCase()};
3091 if (src.getAttribute && src.getAttribute('id')) {
3092 elementObj.id = src.getAttribute('id');
3094 if (src.className) {
3095 elementObj.classname = src.className;
3097 elementObj.el = src;
3098 struct.push(elementObj);
3100 src = src.parentNode;
3102 return struct;
3107 var setup = function() {
3108 UI.clearStatusMsg();
3110 // UI.HotSpots.init();
3112 var crumb = new cookie('chameleon_server_save_required');
3113 if (crumb.read() == 1) {
3114 CSS.requireRemoteSave();
3117 Util.addEvent(window, 'unload', CSS.unloadPrompt);
3118 Util.addEvent(window, 'unload', Util.cleanUp);
3119 Util.addEvent(document, 'mousedown', UI.Selector.editWindow);
3121 //CSS.clearTheme();
3124 var startSetup = function() {
3125 UI.statusMsg('Chameleon is loading...');
3127 if (!CSS.loadRemote(true)) {
3128 alert('Your browser must support XMLHttpRequest! Supported browsers include Internet Explorer, Mozilla Firefox, Safari and Opera');
3132 Util.addEvent(window, 'load', startSetup);
3134 })();