rhymix/modules/editor/skins/xquared/javascripts/ui/Toolbar.js
haneul 7c3b336e41 17223554 : xquared upgrade to 0.7
git-svn-id: http://xe-core.googlecode.com/svn/sandbox@4968 201d5d3c-b55e-5fd7-737f-ddc643e51545
2008-11-24 08:52:19 +00:00

312 lines
No EOL
9.1 KiB
JavaScript

/**
* @requires Xquared.js
* @requires Browser.js
* @requires ui/Base.js
*/
xq.ui.Toolbar = xq.Class(/** @lends xq.ui.Toolbar.prototype */{
/**
* TODO: Add description
*
* @constructs
*/
initialize: function(xed, container, wrapper, buttonMap, imagePath, structureAndStyleCollector) {
xq.addToFinalizeQueue(this);
this.xed = xed;
if(typeof container === 'string') {
container = xq.$(container);
}
if(container && container.nodeType !== 1) {
throw "[container] is not an element";
}
this.wrapper = wrapper;
this.doc = this.wrapper.ownerDocument;
this.buttonMap = buttonMap;
this.imagePath = imagePath;
this.structureAndStyleCollector = structureAndStyleCollector;
this.buttons = null;
this.anchorsCache = [];
this._scheduledUpdate = null;
if(!container) {
this.create();
this._addStyleRules([
{selector:".xquared div.toolbar", rule:"background-image: url(" + imagePath + "toolbarBg.gif)"},
{selector:".xquared ul.buttons li", rule:"background-image: url(" + imagePath + "toolbarButtonBg.gif)"},
{selector:".xquared ul.buttons li.xq_separator", rule:"background-image: url(" + imagePath + "toolbarSeparator.gif)"}
]);
} else {
this.container = container;
}
},
finalize: function() {
for(var i = 0; i < this.anchorsCache.length; i++) {
// TODO remove dependency to Editor
this.anchorsCache[i].xed = null;
this.anchorsCache[i].handler = null;
this.anchorsCache[i] = null;
}
this.toolbarAnchorsCache = null;
},
triggerUpdate: function() {
if(this._scheduledUpdate) return;
this._scheduledUpdate = window.setTimeout(
function() {
this._scheduledUpdate = null;
var ss = this.structureAndStyleCollector();
if(ss) this.update(ss);
}.bind(this), 200
);
},
/**
* Updates all buttons' status. Override this to customize status L&F. Don't call this function directly. Use triggerUpdate() to call it indirectly.
*
* @param {Object} structure and style information. see xq.rdom.Base.collectStructureAndStyle()
*/
update: function(info) {
if(!this.container) return;
if(!this.buttons) {
var classNames = [
"emphasis", "strongEmphasis", "underline", "strike", "superscription", "subscription",
"justifyLeft", "justifyCenter", "justifyRight", "justifyBoth",
"unorderedList", "orderedList", "code",
"paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6"
];
this.buttons = {};
for(var i = 0; i < classNames.length; i++) {
var found = xq.getElementsByClassName(this.container, classNames[i]);
var button = found && found.length > 0 ? found[0] : null;
if(button) this.buttons[classNames[i]] = button;
}
}
var buttons = this.buttons;
this._updateButtonStatus('emphasis', info.em);
this._updateButtonStatus('strongEmphasis', info.strong);
this._updateButtonStatus('underline', info.underline);
this._updateButtonStatus('strike', info.strike);
this._updateButtonStatus('superscription', info.superscription);
this._updateButtonStatus('subscription', info.subscription);
this._updateButtonStatus('justifyLeft', info.justification === 'left');
this._updateButtonStatus('justifyCenter', info.justification === 'center');
this._updateButtonStatus('justifyRight', info.justification === 'right');
this._updateButtonStatus('justifyBoth', info.justification === 'justify');
this._updateButtonStatus('orderedList', info.list === 'OL');
this._updateButtonStatus('unorderedList', info.list === 'UL');
this._updateButtonStatus('code', info.list === 'CODE');
this._updateButtonStatus('paragraph', info.block === 'P');
this._updateButtonStatus('heading1', info.block === 'H1');
this._updateButtonStatus('heading2', info.block === 'H2');
this._updateButtonStatus('heading3', info.block === 'H3');
this._updateButtonStatus('heading4', info.block === 'H4');
this._updateButtonStatus('heading5', info.block === 'H5');
this._updateButtonStatus('heading6', info.block === 'H6');
},
/**
* Enables all buttons
*
* @param {Array} [exceptions] array of string containing classnames to exclude
*/
enableButtons: function(exceptions) {
if(!this.container) return;
this._execForAllButtons(exceptions, function(li, exception) {
li.firstChild.className = !exception ? '' : 'disabled';
});
// @WORKAROUND: Image icon disappears without following code:
if(xq.Browser.isIE6) {
this.container.style.display = 'none';
setTimeout(function() {this.container.style.display = 'block';}.bind(this), 0);
}
},
/**
* Disables all buttons
*
* @param {Array} [exceptions] array of string containing classnames to exclude
*/
disableButtons: function(exceptions) {
this._execForAllButtons(exceptions, function(li, exception) {
li.firstChild.className = exception ? '' : 'disabled';
});
},
/**
* Creates toolbar element
*/
create: function() {
// outmost container
this.container = this.doc.createElement('div');
this.container.className = 'toolbar';
// button container
var buttons = this.doc.createElement('ul');
buttons.className = 'buttons';
this.container.appendChild(buttons);
// Generate buttons from map and append it to button container
for(var i = 0; i < this.buttonMap.length; i++) {
for(var j = 0; j < this.buttonMap[i].length; j++) {
var buttonConfig = this.buttonMap[i][j];
var li = this.doc.createElement('li');
buttons.appendChild(li);
li.className = buttonConfig.className;
var span = this.doc.createElement('span');
li.appendChild(span);
if(buttonConfig.handler) {
this._createButton(buttonConfig, span);
} else {
this._createDropdown(buttonConfig, span);
}
if(j === 0 && i !== 0) li.className += ' xq_separator';
}
}
this.wrapper.appendChild(this.container);
},
_createButton: function(buttonConfig, span) {
var a = this.doc.createElement('a');
span.appendChild(a);
a.href = '#';
a.title = buttonConfig.title;
a.handler = buttonConfig.handler;
this.anchorsCache.push(a);
xq.observe(a, 'mousedown', xq.cancelHandler);
xq.observe(a, 'click', this._clickHandler.bindAsEventListener(this));
var img = this.doc.createElement('img');
a.appendChild(img);
img.src = this.imagePath + buttonConfig.className + '.gif';
},
_createDropdown: function(buttonConfig, span) {
var select = this.doc.createElement('select');
select.handlers = buttonConfig.list;
var xed = this.xed;
xq.observe(select, 'change', function(e) {
var src = e.target || e.srcElement;
if(src.value === "-1") {
src.selectedIndex = 0;
return true;
}
var handler = src.handlers[src.value].handler;
xed.focus();
var stop = (typeof handler === "function") ? handler(this) : eval(handler);
src.selectedIndex = 0;
if(stop) {
xq.stopEvent(e);
return false;
} else {
return true;
}
});
var option = this.doc.createElement('option');
option.innerHTML = buttonConfig.title;
option.value = -1;
select.appendChild(option);
option = this.doc.createElement('option');
option.innerHTML = '----';
option.value = -1;
select.appendChild(option);
for(var i = 0; i < buttonConfig.list.length; i++) {
option = this.doc.createElement('option');
option.innerHTML = buttonConfig.list[i].title;
option.value = i;
select.appendChild(option);
}
span.appendChild(select);
},
_clickHandler: function(e) {
var src = e.target || e.srcElement;
while(src.nodeName !== "A") src = src.parentNode;
if(xq.hasClassName(src.parentNode, 'disabled') || xq.hasClassName(this.container, 'disabled')) {
xq.stopEvent(e);
return false;
}
var handler = src.handler;
var xed = this.xed;
xed.focus();
if(typeof handler === "function") {
handler(this);
} else {
eval(handler);
}
xq.stopEvent(e);
return false;
},
_updateButtonStatus: function(className, selected) {
var button = this.buttons[className];
if(button) {
var newClassName = selected ? 'selected' : '';
var target = button.firstChild.firstChild;
if(target.className !== newClassName) target.className = newClassName;
}
},
_execForAllButtons: function(exceptions, exec) {
if(!this.container) return;
exceptions = exceptions || [];
var lis = this.container.getElementsByTagName('LI');
for(var i = 0; i < lis.length; i++) {
var className = lis[i].className.split(" ").find(function(name) {return name !== 'xq_separator'});
var exception = exceptions.indexOf(className) !== -1;
exec(lis[i], exception);
}
},
_addStyleRules: function(rules) {
if(!this.dynamicStyle) {
if(xq.Browser.isTrident) {
this.dynamicStyle = this.doc.createStyleSheet();
} else {
var style = this.doc.createElement('style');
this.doc.body.appendChild(style);
this.dynamicStyle = xq.$A(this.doc.styleSheets).last();
}
}
for(var i = 0; i < rules.length; i++) {
var rule = rules[i];
if(xq.Browser.isTrident) {
this.dynamicStyle.addRule(rules[i].selector, rules[i].rule);
} else {
this.dynamicStyle.insertRule(rules[i].selector + " {" + rules[i].rule + "}", this.dynamicStyle.cssRules.length);
}
}
}
});