17223554 : xquared upgrade to 0.7

git-svn-id: http://xe-core.googlecode.com/svn/sandbox@4968 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
haneul 2008-11-24 08:52:19 +00:00
parent 5956e254e7
commit 7c3b336e41
59 changed files with 34562 additions and 8454 deletions

View file

@ -0,0 +1,6 @@
/**
* @namespace UI Controls
*
* @requires Xquared.js
*/
xq.ui = {};

View file

@ -0,0 +1,404 @@
/**
* @namespace UI Controls
*
* @requires Xquared.js
* @requires ui/Base.js
*/
xq.ui.FormDialog = xq.Class(/** @lends xq.ui.FormDialog.prototype */ {
/**
* Displays given HTML form as a dialog.
*
* @constructs
* @param {xq.Editor} xed Dialog owner.
* @param {String} html HTML string which contains FORM.
* @param {Function} [onLoadHandler] callback function to be called when the form is loaded.
* @param {Function} [onCloseHandler] callback function to be called when the form is closed.
*/
initialize: function(xed, html, onLoadHandler, onCloseHandler) {
xq.addToFinalizeQueue(this);
this.xed = xed;
this.html = html;
this.onLoadHandler = onLoadHandler || function() {};
this.onCloseHandler = onCloseHandler || function() {};
this.form = null;
},
/**
* Shows dialog
*
* @param {Object} [options] collection of options
*/
show: function(options) {
options = options || {};
options.position = options.position || 'centerOfWindow';
options.mode = options.mode || 'modal';
options.cancelOnEsc = options.cancelOnEsc || true;
var self = this;
// create and append container
var container = document.createElement('DIV');
container.style.display = 'none';
document.body.appendChild(container);
// initialize form
container.innerHTML = this.html;
this.form = container.getElementsByTagName('FORM')[0];
this.form.onsubmit = function() {
self.onCloseHandler(xq.serializeForm(this));
self.close();
return false;
};
var cancelButton = xq.getElementsByClassName(this.form, 'cancel')[0];
cancelButton.onclick = function() {
self.onCloseHandler();
self.close();
};
if(options.mode === 'modal') {
this.dimmed = document.createElement('DIV');
this.dimmed.style.position = 'absolute';
this.dimmed.style.backgroundColor = 'black';
this.dimmed.style.opacity = 0.5;
this.dimmed.style.filter = 'alpha(opacity=50)';
this.dimmed.style.zIndex=902;
this.dimmed.style.top='0px';
this.dimmed.style.left='0px';
document.body.appendChild(this.dimmed);
this.resizeDimmedDiv = function(e) {
this.dimmed.style.display='none';
this.dimmed.style.width=document.documentElement.scrollWidth+'px';
this.dimmed.style.height=document.documentElement.scrollHeight+'px';
this.dimmed.style.display='block';
}.bind(this);
xq.observe(window, 'resize', this.resizeDimmedDiv);
this.resizeDimmedDiv();
}
// append dialog
document.body.appendChild(this.form);
container.parentNode.removeChild(container);
// place dialog to center of window
this.setPosition(options.position);
// give focus
var elementToFocus = xq.getElementsByClassName(this.form, 'initialFocus');
if(elementToFocus.length > 0) elementToFocus[0].focus();
// handle cancelOnEsc option
if(options.cancelOnEsc) {
xq.observe(this.form, 'keydown', function(e) {
if(e.keyCode === 27) {
this.onCloseHandler();
this.close();
}
}.bind(this));
}
this.onLoadHandler(this);
},
/**
* Closes dialog
*/
close: function() {
this.form.parentNode.removeChild(this.form);
if(this.dimmed) {
this.dimmed.parentNode.removeChild(this.dimmed);
this.dimmed = null;
xq.stopObserving(window, 'resize', this.resizeDimmedDiv);
this.resizeDimmedDiv = null;
}
},
/**
* Sets position of dialog
*
* @param {String} target "centerOfWindow" or "centerOfEditor"
*/
setPosition: function(target) {
var targetElement = null;
var left = 0;
var top = 0;
if(target === 'centerOfWindow') {
targetElement = document.documentElement;
left += targetElement.scrollLeft;
top += targetElement.scrollTop;
} else if(target === 'centerOfEditor') {
targetElement = this.xed.getCurrentEditMode() == 'wysiwyg' ? this.xed.wysiwygEditorDiv : this.xed.sourceEditorDiv;
var o = targetElement;
do {
left += o.offsetLeft;
top += o.offsetTop;
} while(o = o.offsetParent)
} else if(target === 'nearbyCaret') {
throw "Not implemented yet";
} else {
throw "Invalid argument: " + target;
}
var targetWidth = targetElement.clientWidth;
var targetHeight = targetElement.clientHeight;
var dialogWidth = this.form.clientWidth;
var dialogHeight = this.form.clientHeight;
left += parseInt((targetWidth - dialogWidth) / 2);
top += parseInt((targetHeight - dialogHeight) / 2);
this.form.style.left = left + "px";
this.form.style.top = top + "px";
}
})
xq.ui.QuickSearchDialog = xq.Class(/** @lends xq.ui.QuickSearchDialog.prototype */ {
/**
* Displays quick search dialog
*
* @constructs
* @param {xq.Editor} xed Dialog owner.
* @param {Object} param Parameters.
*/
initialize: function(xed, param) {
xq.addToFinalizeQueue(this);
this.xed = xed;
this.rdom = xq.rdom.Base.createInstance();
this.param = param;
if(!this.param.renderItem) this.param.renderItem = function(item) {
return this.rdom.getInnerText(item);
}.bind(this);
this.container = null;
},
getQuery: function() {
if(!this.container) return "";
return this._getInputField().value;
},
onSubmit: function(e) {
if(this.matchCount() > 0) {
this.param.onSelect(this.xed, this.list[this._getSelectedIndex()]);
}
this.close();
xq.stopEvent(e);
return false;
},
onCancel: function(e) {
if(this.param.onCancel) this.param.onCancel(this.xed);
this.close();
},
onBlur: function(e) {
// @WORKAROUND: Ugly
setTimeout(function() {this.onCancel(e)}.bind(this), 400);
},
onKey: function(e) {
var esc = new xq.Shortcut("ESC");
var enter = new xq.Shortcut("ENTER");
var up = new xq.Shortcut("UP");
var down = new xq.Shortcut("DOWN");
if(esc.matches(e)) {
this.onCancel(e);
} else if(enter.matches(e)) {
this.onSubmit(e);
} else if(up.matches(e)) {
this._moveSelectionUp();
} else if(down.matches(e)) {
this._moveSelectionDown();
} else {
this.updateList();
}
},
onClick: function(e) {
var target = e.srcElement || e.target;
if(target.nodeName === "LI") {
var index = this._getIndexOfLI(target);
this.param.onSelect(this.xed, this.list[index]);
}
},
onList: function(list) {
this.list = list;
this.renderList(list);
},
updateList: function() {
window.setTimeout(function() {
this.param.listProvider(this.getQuery(), this.xed, this.onList.bind(this));
}.bind(this), 0);
},
renderList: function(list)
{
var ol = this._getListContainer();
ol.innerHTML = "";
for(var i = 0; i < list.length; i++) {
var li = this.rdom.createElement('LI');
li.innerHTML = this.param.renderItem(list[i]);
ol.appendChild(li);
}
if(ol.hasChildNodes()) {
ol.firstChild.className = "selected";
}
},
show: function() {
if(!this.container) this.container = this._create();
var dialog = this.rdom.insertNodeAt(this.container, this.rdom.getRoot(), "end");
this.setPosition('centerOfEditor');
this.updateList();
this.focus();
},
close: function() {
this.rdom.deleteNode(this.container);
},
focus: function() {
this._getInputField().focus();
},
setPosition: function(target) {
var targetElement = null;
var left = 0;
var top = 0;
if(target === 'centerOfWindow') {
left += targetElement.scrollLeft;
top += targetElement.scrollTop;
targetElement = document.documentElement;
} else if(target === 'centerOfEditor') {
targetElement = this.xed.getCurrentEditMode() == 'wysiwyg' ? this.xed.wysiwygEditorDiv : this.xed.sourceEditorDiv;
var o = targetElement;
do {
left += o.offsetLeft;
top += o.offsetTop;
} while(o = o.offsetParent)
} else if(target === 'nearbyCaret') {
throw "Not implemented yet";
} else {
throw "Invalid argument: " + target;
}
var targetWidth = targetElement.clientWidth;
var targetHeight = targetElement.clientHeight;
var dialogWidth = this.container.clientWidth;
var dialogHeight = this.container.clientHeight;
left += parseInt((targetWidth - dialogWidth) / 2);
top += parseInt((targetHeight - dialogHeight) / 2);
this.container.style.left = left + "px";
this.container.style.top = top + "px";
},
matchCount: function() {
return this.list ? this.list.length : 0;
},
_create: function() {
// make container
var container = this.rdom.createElement("DIV");
container.className = "xqQuickSearch";
// make title
if(this.param.title) {
var title = this.rdom.createElement("H1");
title.innerHTML = this.param.title;
container.appendChild(title);
}
// make input field
var inputWrapper = this.rdom.createElement("DIV");
inputWrapper.className = "input";
var form = this.rdom.createElement("FORM");
var input = this.rdom.createElement("INPUT");
input.type = "text";
input.value = "";
form.appendChild(input);
inputWrapper.appendChild(form);
container.appendChild(inputWrapper);
// make list
var list = this.rdom.createElement("OL");
xq.observe(input, 'blur', this.onBlur.bindAsEventListener(this));
xq.observe(input, 'keypress', this.onKey.bindAsEventListener(this));
xq.observe(list, 'click', this.onClick.bindAsEventListener(this), true);
xq.observe(form, 'submit', this.onSubmit.bindAsEventListener(this));
xq.observe(form, 'reset', this.onCancel.bindAsEventListener(this));
container.appendChild(list);
return container;
},
_getInputField: function() {
return this.container.getElementsByTagName('INPUT')[0];
},
_getListContainer: function() {
return this.container.getElementsByTagName('OL')[0];
},
_getSelectedIndex: function() {
var ol = this._getListContainer();
for(var i = 0; i < ol.childNodes.length; i++) {
if(ol.childNodes[i].className === 'selected') return i;
}
},
_getIndexOfLI: function(li) {
var ol = this._getListContainer();
for(var i = 0; i < ol.childNodes.length; i++) {
if(ol.childNodes[i] === li) return i;
}
},
_moveSelectionUp: function() {
var count = this.matchCount();
if(count === 0) return;
var index = this._getSelectedIndex();
var ol = this._getListContainer();
ol.childNodes[index].className = "";
index--;
if(index < 0) index = count - 1;
ol.childNodes[index].className = "selected";
},
_moveSelectionDown: function() {
var count = this.matchCount();
if(count === 0) return;
var index = this._getSelectedIndex();
var ol = this._getListContainer();
ol.childNodes[index].className = "";
index++;
if(index >= count) index = 0;
ol.childNodes[index].className = "selected";
}
});

View file

@ -0,0 +1,312 @@
/**
* @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);
}
}
}
});

View file

@ -0,0 +1,20 @@
if(!xq) xq = {};
if(!xq.ui_templates) xq.ui_templates = {};
xq.ui_templates.basicColorPickerDialog='<form action="#" class="xqFormDialog xqBasicColorPickerDialog">\n <div>\n <label>\n <input type="radio" class="initialFocus" name="color" value="black" checked="checked" />\n <span style="color: black;">Black</span>\n </label>\n <label>\n <input type="radio" name="color" value="red" />\n <span style="color: red;">Red</span>\n </label>\n <input type="radio" name="color" value="yellow" />\n <span style="color: yellow;">Yellow</span>\n </label>\n </label>\n <input type="radio" name="color" value="pink" />\n <span style="color: pink;">Pink</span>\n </label>\n <label>\n <input type="radio" name="color" value="blue" />\n <span style="color: blue;">Blue</span>\n </label>\n <label>\n <input type="radio" name="color" value="green" />\n <span style="color: green;">Green</span>\n </label>\n \n <input type="submit" value="Ok" />\n <input type="button" class="cancel" value="Cancel" />\n </div>\n </form>';
if(!xq) xq = {};
if(!xq.ui_templates) xq.ui_templates = {};
xq.ui_templates.basicIFrameDialog='<form action="#" class="xqFormDialog xqBasicIFrameDialog">\n <table>\n <tr>\n <td>IFrame src:</td>\n <td><input type="text" class="initialFocus" name="p_src" size="36" value="http://" /></td>\n </tr>\n <tr>\n <td>Width:</td>\n <td><input type="text" name="p_width" size="6" value="320" /></td>\n </tr>\n <tr>\n <td>Height:</td>\n <td><input type="text" name="p_height" size="6" value="200" /></td>\n </tr>\n <tr>\n <td>Frame border:</td>\n <td><select name="p_frameborder">\n <option value="0" selected="selected">No</option>\n <option value="1">Yes</option>\n </select></td>\n </tr>\n <tr>\n <td>Scrolling:</td>\n <td><select name="p_scrolling">\n <option value="0">No</option>\n <option value="1" selected="selected">Yes</option>\n </select></td>\n </tr>\n <tr>\n <td>ID(optional):</td>\n <td><input type="text" name="p_id" size="24" value="" /></td>\n </tr>\n <tr>\n <td>Class(optional):</td>\n <td><input type="text" name="p_class" size="24" value="" /></td>\n </tr>\n </table>\n <p>\n <input type="submit" value="Ok" />\n <input type="button" class="cancel" value="Cancel" />\n </p>\n </form>';
if(!xq) xq = {};
if(!xq.ui_templates) xq.ui_templates = {};
xq.ui_templates.basicLinkDialog='<form action="#" class="xqFormDialog xqBasicLinkDialog">\n <h3>Link</h3>\n <div>\n <input type="text" class="initialFocus" name="text" value="" />\n <input type="text" name="url" value="http://" />\n \n <input type="submit" value="Ok" />\n <input type="button" class="cancel" value="Cancel" />\n </div>\n </form>';
if(!xq) xq = {};
if(!xq.ui_templates) xq.ui_templates = {};
xq.ui_templates.basicMovieDialog='<form action="#" class="xqFormDialog xqBasicMovieDialog">\n <table>\n <tr>\n <td>Movie OBJECT tag:</td>\n <td><input type="text" class="initialFocus" name="html" size="36" value="" /></td>\n </tr>\n </table>\n <p>\n <input type="submit" value="Ok" />\n <input type="button" class="cancel" value="Cancel" />\n </p>\n </form>';
if(!xq) xq = {};
if(!xq.ui_templates) xq.ui_templates = {};
xq.ui_templates.basicScriptDialog='<form action="#" class="xqFormDialog xqBasicScriptDialog">\n <table>\n <tr>\n <td>Script URL:</td>\n <td><input type="text" class="initialFocus" name="url" size="36" value="http://" /></td>\n </tr>\n </table>\n <p>\n <input type="submit" value="Ok" />\n <input type="button" class="cancel" value="Cancel" />\n </p>\n </form>';