NicEdit/nicEdit.js

1614 lines
46 KiB
JavaScript

/**
* NicEdit - Micro Inline WYSIWYG
* Copyright 2007-2008 Brian Kirchoff, http://nicedit.com/
* Copyright 2012-2015 Vitaliy Filippov, http://yourcmc.ru/wiki/nicEdit
* Version: 2015-08-12
*
* NicEdit is distributed under the terms of the MIT license
* Do not remove this copyright message
*/
var bkExtend = function(){
var args = arguments;
if (args.length == 1) args = [this, args[0]];
for (var prop in args[1]) args[0][prop] = args[1][prop];
return args[0];
};
function bkClass() { }
bkClass.prototype.construct = function() {};
bkClass.extend = function(def) {
var classDef = function() {
if (arguments[0] !== bkClass) { return this.construct.apply(this, arguments); }
};
var proto = new this(bkClass);
bkExtend(proto,def);
classDef.prototype = proto;
classDef.extend = this.extend;
return classDef;
};
var bkElement = bkClass.extend({
construct : function(elm,d) {
if(typeof(elm) == "string") {
elm = (d || document).createElement(elm);
}
elm = $BK(elm);
return elm;
},
appendTo : function(elm) {
elm.appendChild(this);
return this;
},
appendBefore : function(elm) {
elm.parentNode.insertBefore(this,elm);
return this;
},
addEvent : function(type, fn) {
bkLib.addEvent(this,type,fn);
return this;
},
removeAllEvents : function() {
bkLib.removeAllEvents(this);
return this;
},
setContent : function(c) {
this.innerHTML = c;
return this;
},
pos : function() {
var curleft = curtop = 0;
var o = obj = this;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
var b = (!window.opera) ? parseInt(this.getStyle('border-width') || this.style.border) || 0 : 0;
return [curleft+b,curtop+b];
},
noSelect : function() {
bkLib.noSelect(this);
return this;
},
parentTag : function(t) {
var elm = this;
do {
if(elm && elm.nodeName && elm.nodeName.toUpperCase() == t) {
return elm;
}
elm = elm.parentNode;
} while(elm);
return false;
},
hasClass : function(cls) {
return this.className.match(new RegExp('(\\s|^)nicEdit-'+cls+'(\\s|$)'));
},
addClass : function(cls) {
if (!this.hasClass(cls)) { this.className += " nicEdit-"+cls };
return this;
},
removeClass : function(cls) {
if (this.hasClass(cls)) {
this.className = this.className.replace(new RegExp('(\\s|^)nicEdit-'+cls+'(\\s|$)'),' ');
}
return this;
},
setStyle : function(st) {
var elmStyle = this.style;
for(var itm in st) {
switch(itm) {
case 'float':
elmStyle['cssFloat'] = elmStyle['styleFloat'] = st[itm];
break;
case 'opacity':
elmStyle.opacity = st[itm];
elmStyle.filter = "alpha(opacity=" + Math.round(st[itm]*100) + ")";
break;
case 'className':
this.className = st[itm];
break;
default:
//if(document.compatMode || itm != "cursor") { // Nasty Workaround for IE 5.5
elmStyle[itm] = st[itm];
//}
}
}
return this;
},
getStyle : function( cssRule, d ) {
var doc = (!d) ? document.defaultView : d;
if(this.nodeType == 1)
return (doc && doc.getComputedStyle) ? doc.getComputedStyle( this, null ).getPropertyValue(cssRule) : this.currentStyle[ bkLib.camelize(cssRule) ];
},
remove : function() {
this.parentNode.removeChild(this);
return this;
},
setAttributes : function(at) {
for(var itm in at) {
this[itm] = at[itm];
}
return this;
}
});
var bkLib = {
isMSIE : (navigator.appVersion.indexOf("MSIE") != -1),
addEvent : function(obj, type, fn) {
obj._bkE = obj._bkE||[];
obj._bkE.push([type, fn]);
(obj.addEventListener) ? obj.addEventListener( type, fn, false ) : obj.attachEvent("on"+type, fn);
},
removeEvent : function(obj, type, fn) {
(obj.removeEventListener) ? obj.removeEventListener( type, fn, false ) : obj.detachEvent("on"+type, fn);
},
removeAllEvents : function(obj) {
if (!obj._bkE) return;
for (var i = 0; i < obj._bkE.length; i++) {
bkLib.removeEvent(obj,obj._bkE[i][0],obj._bkE[i][1]);
}
obj._bkE = [];
},
toArray : function(iterable) {
var length = iterable.length, results = new Array(length);
while (length--) { results[length] = iterable[length] };
return results;
},
noSelect : function(element) {
if(element.setAttribute && element.nodeName.toLowerCase() != 'input' && element.nodeName.toLowerCase() != 'textarea') {
element.setAttribute('unselectable','on');
}
for(var i=0;i<element.childNodes.length;i++) {
bkLib.noSelect(element.childNodes[i]);
}
},
camelize : function(s) {
return s.replace(/\-(.)/g, function(m, l){return l.toUpperCase()});
},
inArray : function(arr,item) {
return (bkLib.search(arr,item) != null);
},
search : function(arr,itm) {
for(var i=0; i < arr.length; i++) {
if(arr[i] == itm)
return i;
}
return null;
},
cancelEvent : function(e) {
e = e || window.event;
if(e.preventDefault && e.stopPropagation) {
e.preventDefault();
e.stopPropagation();
}
return false;
},
domLoad : [],
domLoaded : function() {
if (arguments.callee.done) return;
arguments.callee.done = true;
for (i = 0;i < bkLib.domLoad.length;i++) bkLib.domLoad[i]();
},
onDomLoaded: function(fireThis) {
this.domLoad.push(fireThis);
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", bkLib.domLoaded, null);
} else if (bkLib.isMSIE) {
var e = document.createElement('script');
e.setAttribute('defer', 'defer');
e.setAttribute('src', location.protocol == "https:" ? "javascript:void(0)" : "//0");
(document.head || document.documentElement).appendChild(e);
e.onreadystatechange = function() {
if (this.readyState == "complete") bkLib.domLoaded();
};
}
window.onload = bkLib.domLoaded;
}
};
function $BK(elm) {
if(typeof(elm) == "string") {
elm = document.getElementById(elm);
}
return (elm && !elm.appendTo) ? bkExtend(elm,bkElement.prototype) : elm;
}
var bkEvent = {
addEvent : function(evType, evFunc) {
if(evFunc) {
this.eventList = this.eventList || {};
this.eventList[evType] = this.eventList[evType] || [];
this.eventList[evType].push(evFunc);
}
return this;
},
fireEvent : function() {
var args = bkLib.toArray(arguments), evType = args.shift();
if(this.eventList && this.eventList[evType]) {
for(var i=0;i<this.eventList[evType].length;i++) {
this.eventList[evType][i].apply(this,args);
}
}
}
};
if (!__) {
__ = function(s) {
return s;
}
}
Function.prototype.closure = function() {
var __method = this, args = bkLib.toArray(arguments), obj = args.shift();
return function() { if(typeof(bkLib) != 'undefined') { return __method.apply(obj,args.concat(bkLib.toArray(arguments))); } };
}
Function.prototype.closureListener = function() {
var __method = this, args = bkLib.toArray(arguments), object = args.shift();
return function(e) {
e = e || window.event;
if(e.target) { var target = e.target; } else { var target = e.srcElement };
return __method.apply(object, [e,target].concat(args) );
};
}
/* START CONFIG */
var nicEditorConfig = bkClass.extend({
buttons : {
'bold' : {name : __('Click to Bold'), command : 'Bold', tags : ['B','STRONG'], css : {'font-weight' : 'bold'}, key : 'b'},
'italic' : {name : __('Click to Italic'), command : 'Italic', tags : ['EM','I'], css : {'font-style' : 'italic'}, key : 'i'},
'underline' : {name : __('Click to Underline'), command : 'Underline', tags : ['U'], css : {'text-decoration' : 'underline'}, key : 'u'},
'left' : {name : __('Left Align'), command : 'justifyleft', noActive : true},
'center' : {name : __('Center Align'), command : 'justifycenter', noActive : true},
'right' : {name : __('Right Align'), command : 'justifyright', noActive : true},
'justify' : {name : __('Justify Align'), command : 'justifyfull', noActive : true},
'ol' : {name : __('Insert Ordered List'), command : 'insertorderedlist', tags : ['OL']},
'ul' : {name : __('Insert Unordered List'), command : 'insertunorderedlist', tags : ['UL']},
'subscript' : {name : __('Click to Subscript'), command : 'subscript', tags : ['SUB']},
'superscript' : {name : __('Click to Superscript'), command : 'superscript', tags : ['SUP']},
'strikethrough' : {name : __('Click to Strike Through'), command : 'strikeThrough', css : {'text-decoration' : 'line-through'}},
'removeformat' : {name : __('Remove Formatting'), command : 'removeformat', noActive : true},
'indent' : {name : __('Indent Text'), command : 'indent', noActive : true},
'outdent' : {name : __('Remove Indent'), command : 'outdent', noActive : true},
'hr' : {name : __('Horizontal Rule'), command : 'insertHorizontalRule', noActive : true}
},
iconsPath : '../nicEditorIcons.gif',
buttonList : ['save','bold','italic','underline','strikethrough','left','center','right','justify','ol','ul','fontSize','fontFamily','fontFormat','image','upload','link','unlink','removeformat','forecolor','bgcolor','indent','outdent','subscript','superscript','xhtml','table'],
iconList : {"xhtml":1,"bgcolor":2,"forecolor":3,"bold":4,"center":5,"hr":6,"indent":7,"italic":8,"justify":9,"left":10,"ol":11,"outdent":12,"removeformat":13,"right":14,"save":25,"strikethrough":16,"subscript":17,"superscript":18,"ul":19,"underline":20,"image":21,"link":22,"unlink":23,"close":24,"arrow":26,"upload":27,"table":28}
});
/* END CONFIG */
var nicEditors = {
nicPlugins : [],
editors : [],
registerPlugin : function(plugin,options) {
this.nicPlugins.push({p : plugin, o : options});
},
allTextAreas : function(nicOptions) {
var textareas = document.getElementsByTagName("textarea");
for(var i=0;i<textareas.length;i++) {
nicEditors.editors.push(new nicEditor(nicOptions).panelInstance(textareas[i]));
}
return nicEditors.editors;
},
findEditor : function(e) {
var editors = nicEditors.editors;
for(var i=0;i<editors.length;i++) {
if(editors[i].instanceById(e)) {
return editors[i].instanceById(e);
}
}
}
};
var nicEditor = bkClass.extend({
construct : function(o) {
this.options = new nicEditorConfig();
bkExtend(this.options,o);
this.nicInstances = new Array();
this.loadedPlugins = new Array();
var plugins = nicEditors.nicPlugins;
for(var i=0;i<plugins.length;i++) {
this.loadedPlugins.push(new plugins[i].p(this,plugins[i].o));
}
nicEditors.editors.push(this);
bkLib.addEvent(document.body, 'mousedown', this.selectCheck.closureListener(this));
var st = document.createElement('style');
st.appendChild(document.createTextNode(".nicEdit-main p { margin: .3em 0; }"));
(document.head || document.documentElement).appendChild(st);
},
panelInstance : function(e,o) {
e = this.checkReplace($BK(e));
var panelElm = new bkElement('DIV').setStyle({width : (parseInt(e.getStyle('width')) || e.clientWidth)+'px'}).appendBefore(e);
this.setPanel(panelElm);
return this.addInstance(e,o);
},
checkReplace : function(e) {
var r = nicEditors.findEditor(e);
if(r) {
r.removeInstance(e);
r.removePanel();
}
return e;
},
addInstance : function(e,o) {
e = this.checkReplace($BK(e));
if( e.contentEditable || !!window.opera ) {
var newInstance = new nicEditorInstance(e,o,this);
} else {
var newInstance = new nicEditorIFrameInstance(e,o,this);
}
this.nicInstances.push(newInstance);
return this;
},
removeInstance : function(e) {
e = $BK(e);
var instances = this.nicInstances;
for(var i=0;i<instances.length;i++) {
if(instances[i].e == e) {
instances[i].remove();
this.nicInstances.splice(i,1);
}
}
},
removePanel : function(e) {
if(this.nicPanel) {
this.nicPanel.remove();
this.nicPanel = null;
}
},
instanceById : function(e) {
e = $BK(e);
var instances = this.nicInstances;
for(var i=0;i<instances.length;i++) {
if(instances[i].e == e) {
return instances[i];
}
}
},
setPanel : function(e) {
this.nicPanel = new nicEditorPanel($BK(e),this.options,this);
this.fireEvent('panel',this.nicPanel);
return this;
},
nicCommand : function(cmd,args) {
if(this.selectedInstance) {
this.selectedInstance.nicCommand(cmd,args);
}
},
getIcon : function(iconName,options) {
var icon = this.options.iconList[iconName];
var file = (options.iconFiles) ? options.iconFiles[iconName] : '';
return {backgroundImage : "url('"+((icon) ? this.options.iconsPath : file)+"')", backgroundPosition : ((icon) ? ((icon-1)*-18) : 0)+'px 0px'};
},
selectCheck : function(e,t) {
do{
if(t.className && t.className.indexOf('nicEdit') != -1) {
return false;
}
} while(t = t.parentNode);
this.fireEvent('blur',this.selectedInstance,t);
this.lastSelectedInstance = this.selectedInstance;
this.selectedInstance = null;
return false;
}
});
nicEditor = nicEditor.extend(bkEvent);
var nicEditorInstance = bkClass.extend({
isSelected : false,
construct : function(e,options,nicEditor) {
this.ne = nicEditor;
this.elm = this.e = e;
this.options = options || {};
newX = parseInt(e.getStyle('width')) || e.clientWidth;
newY = parseInt(e.getStyle('height')) || e.clientHeight;
this.initialHeight = newY-8;
var isTextarea = (e.nodeName.toLowerCase() == "textarea");
if(isTextarea || this.options.hasPanel) {
var ie7s = (bkLib.isMSIE && !((typeof document.body.style.maxHeight != "undefined") && document.compatMode == "CSS1Compat"));
var s = {
width: newX+'px',
border: '1px solid #ccc',
boxSizing: 'border-box',
overflowY: 'auto',
overflowX: 'hidden'
};
s[ie7s ? 'height' : 'maxHeight'] = isTextarea ? newY+'px' : (this.ne.options.maxHeight ? this.ne.options.maxHeight+'px' : null);
this.editorContain = new bkElement('DIV').setStyle(s).appendBefore(e);
var editorElm = new bkElement('DIV').setStyle({
width: (newX-10)+'px',
padding: '4px',
minHeight: (newY-10)+'px'
}).addClass('main').appendTo(this.editorContain);
e.setStyle({display : 'none'});
editorElm.innerHTML = e.innerHTML;
if(isTextarea) {
editorElm.setContent(e.value);
this.copyElm = e;
var f = e.parentTag('FORM');
if(f) { bkLib.addEvent( f, 'submit', this.saveContent.closure(this)); }
}
editorElm.setStyle((ie7s) ? {height : newY+'px'} : {overflow: 'hidden'});
this.elm = editorElm;
}
this.ne.addEvent('blur',this.blur.closure(this));
this.init();
this.blur();
},
init : function() {
this.elm.setAttribute('contentEditable','true');
if(this.getContent() == "") {
this.setContent('<br />');
}
this.instanceDoc = document.defaultView;
this.elm.addEvent('mousedown',this.selected.closureListener(this)).addEvent('keypress',this.keyDown.closureListener(this)).addEvent('focus',this.selected.closure(this)).addEvent('blur',this.blur.closure(this)).addEvent('keyup',this.selected.closure(this));
this.ne.fireEvent('add',this);
},
remove : function() {
this.saveContent();
if(this.copyElm || this.options.hasPanel) {
this.editorContain.remove();
this.e.setStyle({'display' : 'block'});
this.ne.removePanel();
}
this.elm.removeAllEvents();
this.disable();
this.ne.fireEvent('remove',this);
},
disable : function() {
this.elm.setAttribute('contentEditable','false');
},
getSel : function() {
return (window.getSelection) ? window.getSelection() : document.selection;
},
getRng : function() {
var s = this.getSel();
if (!s) return;
if (s.rangeCount > 0) {
return s.getRangeAt(0);
} else if (typeof s.createRange == 'undefined') {
return document.createRange();
}
return s.createRange();
},
selRng : function(rng,s) {
if(window.getSelection) {
s.removeAllRanges();
s.addRange(rng);
} else {
rng.select();
}
},
selElm : function() {
var r = this.getRng();
if(!r) { return; }
if(r.startContainer) {
var contain = r.startContainer;
if(r.cloneContents().childNodes.length == 1) {
for(var i=0;i<contain.childNodes.length;i++) {
var rng = contain.childNodes[i].ownerDocument.createRange();
rng.selectNode(contain.childNodes[i]);
if(r.compareBoundaryPoints(Range.START_TO_START,rng) != 1 &&
r.compareBoundaryPoints(Range.END_TO_END,rng) != -1) {
return $BK(contain.childNodes[i]);
}
}
}
return $BK(contain);
} else {
return $BK((this.getSel().type == "Control") ? r.item(0) : r.parentElement());
}
},
selBlockType : function() {
var e = this.selElm();
var t = {'P':1,'PRE':1,'H1':1,'H2':1,'H3':1,'H4':1,'H5':1,'H6':1};
while (e != this.elm) {
if (t[e.nodeName]) {
return e.nodeName;
}
e = e.parentNode;
}
return false;
},
saveRng : function() {
this.savedRange = this.getRng();
this.savedSel = this.getSel();
},
restoreRng : function() {
if(this.savedRange) {
this.selRng(this.savedRange,this.savedSel);
}
},
keyDown : function(e,t) {
if(e.keyCode == 13 || e.keyCode == 10) {
if (!e.shiftKey && !this.selBlockType()) {
this.ne.nicCommand('formatBlock', 'p');
}
}
if(e.ctrlKey) {
this.ne.fireEvent('key',this,e);
}
},
selected : function(e,t) {
if(!t && !(t = this.selElm)) { t = this.selElm(); }
if(!e.ctrlKey) {
var selInstance = this.ne.selectedInstance;
if(selInstance != this) {
if(selInstance) {
this.ne.fireEvent('blur',selInstance,t);
}
this.ne.selectedInstance = this;
this.ne.fireEvent('focus',selInstance,t);
}
this.ne.fireEvent('selected',selInstance,t);
this.isFocused = true;
this.elm.addClass('selected');
}
return false;
},
blur : function() {
this.isFocused = false;
this.elm.removeClass('selected');
},
saveContent : function() {
if(this.copyElm || this.options.hasPanel) {
this.ne.fireEvent('save',this);
(this.copyElm) ? this.copyElm.value = this.getContent() : this.e.innerHTML = this.getContent();
}
},
getElm : function() {
return this.elm;
},
getContent : function() {
this.content = this.getElm().innerHTML;
this.ne.fireEvent('get',this);
return this.content;
},
setContent : function(e) {
this.content = e;
this.ne.fireEvent('set',this);
this.elm.innerHTML = this.content;
},
nicCommand : function(cmd,args) {
this.elm.focus();
document.execCommand(cmd,false,args);
}
});
var nicEditorIFrameInstance = nicEditorInstance.extend({
savedStyles : [],
init : function() {
var c = this.elm.innerHTML.replace(/^\s+|\s+$/g, '');
this.elm.innerHTML = '';
(!c) ? c = "<br />" : c;
this.initialContent = c;
this.elmFrame = new bkElement('iframe').setAttributes({'src' : 'javascript:;', 'frameBorder' : 0, 'allowTransparency' : 'true', 'scrolling' : 'no'}).setStyle({height: '100px', width: '100%'}).addClass('frame').appendTo(this.elm);
if(this.copyElm) { this.elmFrame.setStyle({width : (this.elm.offsetWidth-4)+'px'}); }
var styleList = ['font-size','font-family','font-weight','color'];
for(itm in styleList) {
this.savedStyles[bkLib.camelize(itm)] = this.elm.getStyle(itm);
}
setTimeout(this.initFrame.closure(this),50);
},
disable : function() {
this.elm.innerHTML = this.getContent();
},
initFrame : function() {
var fd = $BK(this.elmFrame.contentWindow.document);
fd.designMode = "on";
fd.open();
var css = this.ne.options.externalCSS;
fd.write('<html><head>'+((css) ? '<link href="'+css+'" rel="stylesheet" type="text/css" />' : '')+'</head><body id="nicEditContent" style="margin: 0 !important; background-color: transparent !important;">'+this.initialContent+'</body></html>');
fd.close();
this.frameDoc = fd;
this.frameWin = $BK(this.elmFrame.contentWindow);
this.frameContent = $BK(this.frameWin.document.body).setStyle(this.savedStyles);
this.instanceDoc = this.frameWin.document.defaultView;
this.heightUpdate();
this.frameDoc.addEvent('mousedown', this.selected.closureListener(this)).addEvent('keyup',this.heightUpdate.closureListener(this)).addEvent('keydown',this.keyDown.closureListener(this)).addEvent('keyup',this.selected.closure(this));
this.ne.fireEvent('add',this);
},
getElm : function() {
return this.frameContent;
},
setContent : function(c) {
this.content = c;
this.ne.fireEvent('set',this);
this.frameContent.innerHTML = this.content;
this.heightUpdate();
},
getSel : function() {
return (this.frameWin) ? this.frameWin.getSelection() : this.frameDoc.selection;
},
heightUpdate : function() {
this.elmFrame.style.height = Math.max(this.frameContent.offsetHeight,this.initialHeight)+'px';
},
nicCommand : function(cmd,args) {
this.frameDoc.execCommand(cmd,false,args);
setTimeout(this.heightUpdate.closure(this),100);
}
});
var nicEditorPanel = bkClass.extend({
construct : function(e,options,nicEditor) {
this.elm = e;
this.options = options;
this.ne = nicEditor;
this.panelButtons = new Array();
this.buttonList = bkExtend([],this.ne.options.buttonList);
this.panelContain = new bkElement('DIV').setStyle({overflow : 'hidden', width : '100%', border : '1px solid #cccccc', backgroundColor : '#efefef'}).addClass('panelContain');
this.panelElm = new bkElement('DIV').setStyle({margin : '2px', marginTop : '0px', zoom : 1, overflow : 'hidden'}).addClass('panel').appendTo(this.panelContain);
this.panelContain.appendTo(e);
var opt = this.ne.options;
var buttons = opt.buttons;
for(button in buttons) {
this.addButton(button,opt,true);
}
this.reorder();
e.noSelect();
},
addButton : function(buttonName,options,noOrder) {
var button = options.buttons[buttonName];
var type = null;
if (button['type']) {
type = typeof(window[button['type']]) == undefined ? null : window[button['type']];
}
else {
type = nicEditorButton;
}
var hasButton = bkLib.inArray(this.buttonList,buttonName);
if(type && (hasButton || this.ne.options.fullPanel)) {
this.panelButtons.push(new type(this.panelElm,buttonName,options,this.ne));
if(!hasButton) {
this.buttonList.push(buttonName);
}
}
},
findButton : function(itm) {
for(var i=0;i<this.panelButtons.length;i++) {
if(this.panelButtons[i].name == itm)
return this.panelButtons[i];
}
},
reorder : function() {
var bl = this.buttonList;
for(var i=0;i<bl.length;i++) {
var button = this.findButton(bl[i]);
if(button) {
this.panelElm.appendChild(button.margin);
}
}
},
remove : function() {
this.elm.remove();
}
});
var nicEditorButton = bkClass.extend({
construct : function(e,buttonName,options,nicEditor) {
this.options = options.buttons[buttonName];
this.name = buttonName;
this.ne = nicEditor;
this.elm = e;
this.margin = new bkElement('DIV').setStyle({'float' : 'left', marginTop : '2px'}).appendTo(e);
this.contain = new bkElement('DIV').setStyle({width : '20px', height : '20px'}).addClass('buttonContain').appendTo(this.margin);
this.border = new bkElement('DIV').setStyle({backgroundColor : '#efefef', border : '1px solid #efefef'}).appendTo(this.contain);
this.button = new bkElement('DIV').setStyle({width : '18px', height : '18px', overflow : 'hidden', zoom : 1, cursor : 'pointer'}).addClass('button').setStyle(this.ne.getIcon(buttonName,options)).appendTo(this.border);
this.button.addEvent('mouseover', this.hoverOn.closure(this)).addEvent('mouseout',this.hoverOff.closure(this)).addEvent('mousedown',this.mouseClick.closure(this)).noSelect();
if(!window.opera) {
this.button.onmousedown = this.button.onclick = bkLib.cancelEvent;
}
nicEditor.addEvent('selected', this.enable.closure(this)).addEvent('blur', this.disable.closure(this)).addEvent('key',this.key.closure(this));
this.disable();
this.init();
},
init : function() { },
hide : function() {
this.contain.setStyle({display : 'none'});
},
updateState : function() {
if(this.isDisabled) { this.setBg(); }
else if(this.isHover) { this.setBg('hover'); }
else if(this.isActive) { this.setBg('active'); }
else { this.setBg(); }
},
setBg : function(state) {
switch(state) {
case 'hover':
var stateStyle = {border : '1px solid #666', backgroundColor : '#ddd'};
break;
case 'active':
var stateStyle = {border : '1px solid #666', backgroundColor : '#ccc'};
break;
default:
var stateStyle = {border : '1px solid #efefef', backgroundColor : '#efefef'};
}
this.border.setStyle(stateStyle).addClass('button-'+state);
},
checkNodes : function(e) {
var elm = e;
do {
if(this.options.tags && bkLib.inArray(this.options.tags,elm.nodeName)) {
this.activate();
return true;
}
} while((elm = elm.parentNode) && elm.className != "nicEdit");
elm = $BK(e);
while(elm.nodeType == 3) {
elm = $BK(elm.parentNode);
}
if(this.options.css) {
for(itm in this.options.css) {
if(elm.getStyle(itm,this.ne.selectedInstance.instanceDoc) == this.options.css[itm]) {
this.activate();
return true;
}
}
}
this.deactivate();
return false;
},
activate : function() {
if(!this.isDisabled) {
this.isActive = true;
this.updateState();
this.ne.fireEvent('buttonActivate',this);
}
},
deactivate : function() {
this.isActive = false;
this.updateState();
if(!this.isDisabled) {
this.ne.fireEvent('buttonDeactivate',this);
}
},
enable : function(ins,t) {
this.isDisabled = false;
this.contain.setStyle({'opacity' : 1}).addClass('buttonEnabled');
this.updateState();
this.checkNodes(t);
},
disable : function(ins,t) {
this.isDisabled = true;
this.contain.setStyle({'opacity' : 0.6}).removeClass('buttonEnabled');
this.updateState();
},
toggleActive : function() {
(this.isActive) ? this.deactivate() : this.activate();
},
hoverOn : function() {
if(!this.isDisabled) {
this.isHover = true;
this.updateState();
this.ne.fireEvent("buttonOver",this);
}
},
hoverOff : function() {
this.isHover = false;
this.updateState();
this.ne.fireEvent("buttonOut",this);
},
mouseClick : function() {
if(this.options.command) {
this.ne.nicCommand(this.options.command,this.options.commandArgs);
if(!this.options.noActive) {
this.toggleActive();
}
}
this.ne.fireEvent("buttonClick",this);
},
key : function(nicInstance,e) {
if(this.options.key && e.ctrlKey && String.fromCharCode(e.keyCode || e.charCode).toLowerCase() == this.options.key) {
this.mouseClick();
if(e.preventDefault) e.preventDefault();
}
}
});
var nicPlugin = bkClass.extend({
construct : function(nicEditor,options) {
this.options = options;
this.ne = nicEditor;
this.ne.addEvent('panel',this.loadPanel.closure(this));
this.init();
},
loadPanel : function(np) {
var buttons = this.options.buttons;
for(var button in buttons) {
np.addButton(button,this.options);
}
np.reorder();
},
init : function() { }
});
/** nicPane */
/* START CONFIG */
var nicPaneOptions = { };
/* END CONFIG */
var nicEditorPane = bkClass.extend({
construct : function(elm,nicEditor,options,openButton) {
this.ne = nicEditor;
this.elm = elm;
this.pos = elm.pos();
this.contain = new bkElement('div').setStyle({zIndex: '999', overflow: 'hidden', position: 'absolute', left: this.pos[0]+'px', top : (this.pos[1]+elm.offsetHeight)+'px'})
this.pane = new bkElement('div').setStyle({fontSize: '12px', border: '1px solid #ccc', overflow: 'hidden', padding: '4px', textAlign: 'left', backgroundColor : '#ffffc9'}).addClass('pane').setStyle(options).appendTo(this.contain);
if(openButton && !openButton.options.noClose) {
this.close = new bkElement('div').setStyle({float: 'right', height: '16px', width: '16px', cursor: 'pointer'}).setStyle(this.ne.getIcon('close',nicPaneOptions)).addEvent('mousedown',openButton.removePane.closure(this)).appendTo(this.pane);
}
this.contain.noSelect().appendTo(document.body);
this.position();
this.init();
},
init : function() { },
position : function() {
if(this.ne.nicPanel) {
var panelElm = this.ne.nicPanel.elm;
var panelPos = panelElm.pos();
var newLeft = panelPos[0]+parseInt(panelElm.getStyle('width'))-(parseInt(this.pane.getStyle('width'))+8);
if(newLeft < this.pos[0]) {
this.contain.setStyle({left : newLeft+'px'});
}
}
},
toggle : function() {
this.isVisible = !this.isVisible;
this.contain.setStyle({display : ((this.isVisible) ? 'block' : 'none')});
},
remove : function() {
if(this.contain) {
this.contain.remove();
this.contain = null;
}
},
append : function(c) {
c.appendTo(this.pane);
},
setContent : function(c) {
this.pane.setContent(c);
}
});
/** nicAdvancedButton */
var nicEditorAdvancedButton = nicEditorButton.extend({
init : function() {
this.ne.addEvent('selected',this.removePane.closure(this)).addEvent('blur',this.removePane.closure(this));
},
mouseClick : function() {
if(!this.isDisabled) {
if(this.pane && this.pane.pane) {
this.removePane();
} else {
this.pane = new nicEditorPane(this.contain,this.ne,{width : (this.width || '270px'), backgroundColor : '#fff'},this);
this.addPane();
this.ne.selectedInstance.saveRng();
}
}
},
addForm : function(f,elm) {
this.form = new bkElement('form').setAttributes({className: 'niceabf'}).addEvent('submit',this.submit.closureListener(this));
this.pane.append(this.form);
this.inputs = {};
if (!document._nicCss) {
document._nicCss = document.createElement('style');
document._nicCss.appendChild(document.createTextNode(
'.niceabf table { border-collapse: collapse; }\n'+
'.niceabf td { padding: 2px 5px 2px 0; }\n'+
'.niceabf td.h { vertical-align: top; padding-top: 4px; white-space: nowrap; }\n'+
'.niceabf h2 { font-size: 14px; font-weight: bold; padding: 0; margin: 0; }\n'+
'.niceabf input, .niceabf select { text-transform: none; font-weight: normal; height: auto; padding: 1px; vertical-align: middle; font-size: 13px; border: 1px solid #ccc; }\n'+
'.niceabf textarea { border: 1px solid #ccc; }\n'+
'.niceabf input.button { background-color: #efefef; color: black; margin: 3px 0; }\n'
));
document.getElementsByTagName('head')[0].appendChild(document._nicCss);
}
var tab, tr, td;
for(itm in f) {
var field = f[itm];
var val = '';
if(elm) {
val = elm.getAttribute(itm);
}
if(!val) {
val = field['value'] || '';
}
var type = f[itm].type;
if(type == 'title') {
new bkElement('h2').setContent(field.txt).appendTo(this.form);
} else {
if (!tab) {
tab = new bkElement('table').appendTo(this.form);
}
tr = new bkElement('tr').appendTo(tab);
if(field.txt) {
td = new bkElement('td').setAttributes({className: 'h'}).appendTo(tr);
new bkElement('label').setAttributes({htmlFor: itm}).setContent(field.txt).appendTo(td);
}
td = new bkElement('td').appendTo(tr);
if(!field.txt) {
td.setAttributes({colspan: 2});
}
switch(type) {
case 'text':
this.inputs[itm] = new bkElement('input').setAttributes({id: itm, value: val, type: 'text'}).setStyle(field.style).appendTo(td);
break;
case 'select':
this.inputs[itm] = new bkElement('select').setAttributes({id: itm}).appendTo(td);
for(opt in field.options) {
var o = new bkElement('option').setAttributes({value: opt, selected: (opt == val) ? 'selected' : ''}).setContent(field.options[opt]).appendTo(this.inputs[itm]);
}
break;
case 'content':
this.inputs[itm] = new bkElement('textarea').setAttributes({id: itm}).setStyle(field.style).appendTo(td);
this.inputs[itm].value = val;
break;
case 'container':
this.inputs[itm] = td;
break;
}
}
}
new bkElement('input').setAttributes({type: 'submit', value: __('Submit'), className: 'button'}).appendTo(this.form);
this.form.onsubmit = bkLib.cancelEvent;
},
submit : function() { },
findElm : function(tag,attr,val) {
var list = this.ne.selectedInstance.getElm().getElementsByTagName(tag);
for(var i=0;i<list.length;i++) {
if(list[i].getAttribute(attr) == val) {
return $BK(list[i]);
}
}
},
removePane : function() {
if(this.pane) {
this.pane.remove();
this.pane = null;
this.ne.selectedInstance.restoreRng();
}
}
});
/** nicButtonTips */
var nicButtonTips = bkClass.extend({
construct : function(nicEditor) {
this.ne = nicEditor;
nicEditor.addEvent('buttonOver',this.show.closure(this)).addEvent('buttonOut',this.hide.closure(this));
},
show : function(button) {
this.timer = setTimeout(this.create.closure(this,button),400);
},
create : function(button) {
this.timer = null;
if(!this.pane) {
this.pane = new nicEditorPane(button.button,this.ne,{fontSize : '12px', marginTop : '5px'});
this.pane.setContent(button.options.name);
}
},
hide : function(button) {
if(this.timer) {
clearTimeout(this.timer);
}
if(this.pane) {
this.pane = this.pane.remove();
}
}
});
nicEditors.registerPlugin(nicButtonTips);
/** nicSelect */
/* START CONFIG */
var nicSelectOptions = {
buttons : {
'fontSize' : {name : __('Select Font Size'), type : 'nicEditorFontSizeSelect', command : 'fontsize'},
'fontFamily' : {name : __('Select Font Family'), type : 'nicEditorFontFamilySelect', command : 'fontname'},
'fontFormat' : {name : __('Select Font Format'), type : 'nicEditorFontFormatSelect', command : 'formatBlock'}
}
};
/* END CONFIG */
var nicEditorSelect = bkClass.extend({
construct : function(e,buttonName,options,nicEditor) {
this.options = options.buttons[buttonName];
this.elm = e;
this.ne = nicEditor;
this.name = buttonName;
this.selOptions = new Array();
this.margin = new bkElement('div').setStyle({'float' : 'left', margin : '2px 1px 0 1px'}).appendTo(this.elm);
this.contain = new bkElement('div').setStyle({width: '90px', height : '20px', cursor : 'pointer', overflow: 'hidden'}).addClass('selectContain').addEvent('click',this.toggle.closure(this)).appendTo(this.margin);
this.items = new bkElement('div').setStyle({overflow : 'hidden', zoom : 1, border: '1px solid #ccc', paddingLeft : '3px', backgroundColor : '#fff'}).appendTo(this.contain);
this.control = new bkElement('div').setStyle({overflow : 'hidden', 'float' : 'right', height: '18px', width : '16px'}).addClass('selectControl').setStyle(this.ne.getIcon('arrow',options)).appendTo(this.items);
this.txt = new bkElement('div').setStyle({overflow : 'hidden', 'float' : 'left', width : '66px', height : '14px', marginTop : '1px', fontFamily : 'sans-serif', textAlign : 'center', fontSize : '12px'}).addClass('selectTxt').appendTo(this.items);
if(!window.opera) {
this.contain.onmousedown = this.control.onmousedown = this.txt.onmousedown = bkLib.cancelEvent;
}
this.margin.noSelect();
this.ne.addEvent('selected', this.enable.closure(this)).addEvent('blur', this.disable.closure(this));
this.disable();
this.init();
},
disable : function() {
this.isDisabled = true;
this.close();
this.contain.setStyle({opacity : 0.6});
},
enable : function(t) {
this.isDisabled = false;
this.close();
this.contain.setStyle({opacity : 1});
},
setDisplay : function(txt) {
this.txt.setContent(txt);
},
toggle : function() {
if(!this.isDisabled) {
(this.pane) ? this.close() : this.open();
}
},
open : function() {
this.pane = new nicEditorPane(this.items,this.ne,{width : '88px', padding: '0px', borderTop : 0, borderLeft : '1px solid #ccc', borderRight : '1px solid #ccc', borderBottom : '0px', backgroundColor : '#fff'});
for(var i=0;i<this.selOptions.length;i++) {
var opt = this.selOptions[i];
var itmContain = new bkElement('div').setStyle({overflow : 'hidden', borderBottom : '1px solid #ccc', width: '88px', textAlign : 'left', overflow : 'hidden', cursor : 'pointer'});
var itm = new bkElement('div').setStyle({padding : '0px 4px'}).setContent(opt[1]).appendTo(itmContain).noSelect();
itm.addEvent('click',this.update.closure(this,opt[0])).addEvent('mouseover',this.over.closure(this,itm)).addEvent('mouseout',this.out.closure(this,itm)).setAttributes('id',opt[0]);
this.pane.append(itmContain);
if(!window.opera) {
itm.onmousedown = bkLib.cancelEvent;
}
}
},
close : function() {
if(this.pane) {
this.pane = this.pane.remove();
}
},
over : function(opt) {
opt.setStyle({backgroundColor : '#ccc'});
},
out : function(opt) {
opt.setStyle({backgroundColor : '#fff'});
},
add : function(k,v) {
this.selOptions.push(new Array(k,v));
},
update : function(elm) {
this.ne.nicCommand(this.options.command,elm);
this.close();
}
});
var nicEditorFontSizeSelect = nicEditorSelect.extend({
sel : {1 : '1&nbsp;(8pt)', 2 : '2&nbsp;(10pt)', 3 : '3&nbsp;(12pt)', 4 : '4&nbsp;(14pt)', 5 : '5&nbsp;(18pt)', 6 : '6&nbsp;(24pt)'},
init : function() {
this.setDisplay(__('Font&nbsp;Size...'));
for(itm in this.sel) {
this.add(itm,'<font size="'+itm+'">'+this.sel[itm]+'</font>');
}
}
});
var nicEditorFontFamilySelect = nicEditorSelect.extend({
sel : {'sans-serif':__('Sans-Serif'), 'serif':__('Serif'), 'fantasy':__('Fantasy'), 'monospace':__('Monospace'), 'cursive':__('Cursive'), 'georgia':'Georgia'},
init : function() {
this.setDisplay(__('Font&nbsp;Family...'));
for(itm in this.sel) {
this.add(itm,'<font face="'+itm+'">'+this.sel[itm]+'</font>');
}
}
});
var nicEditorFontFormatSelect = nicEditorSelect.extend({
sel : {'p' : __('Paragraph'), 'pre' : __('Pre'), 'h6' : __('Heading&nbsp;6'), 'h5' : __('Heading&nbsp;5'), 'h4' : __('Heading&nbsp;4'), 'h3' : __('Heading&nbsp;3'), 'h2' : __('Heading&nbsp;2'), 'h1' : __('Heading&nbsp;1')},
init : function() {
this.setDisplay(__('Font&nbsp;Format...'));
for(itm in this.sel) {
var tag = itm.toUpperCase();
this.add('<'+tag+'>','<'+itm+' style="padding: 0px; margin: 0px;">'+this.sel[itm]+'</'+tag+'>');
}
}
});
nicEditors.registerPlugin(nicPlugin,nicSelectOptions);
/** nicColors */
/* START CONFIG */
var nicColorOptions = {
buttons : {
'forecolor' : {name : __('Change Text Color'), type : 'nicEditorColorButton', noClose : true},
'bgcolor' : {name : __('Change Background Color'), type : 'nicEditorBgColorButton', noClose : true}
}
};
/* END CONFIG */
var nicEditorColorButton = nicEditorAdvancedButton.extend({
addPane : function() {
var colorList = {0 : '00',1 : '33',2 : '66',3 :'99',4 : 'CC',5 : 'FF'};
var colorItems = new bkElement('DIV').setStyle({width: '270px'});
for(var r in colorList) {
for(var b in colorList) {
for(var g in colorList) {
var colorCode = '#'+colorList[r]+colorList[g]+colorList[b];
var colorSquare = new bkElement('DIV').setStyle({'cursor' : 'pointer', 'height' : '15px', 'float' : 'left'}).appendTo(colorItems);
var colorBorder = new bkElement('DIV').setStyle({border: '2px solid '+colorCode}).appendTo(colorSquare);
var colorInner = new bkElement('DIV').setStyle({backgroundColor : colorCode, overflow : 'hidden', width : '11px', height : '11px'}).addEvent('click',this.colorSelect.closure(this,colorCode)).addEvent('mouseover',this.on.closure(this,colorBorder)).addEvent('mouseout',this.off.closure(this,colorBorder,colorCode)).appendTo(colorBorder);
if(!window.opera) {
colorSquare.onmousedown = colorInner.onmousedown = bkLib.cancelEvent;
}
}
}
}
this.pane.append(colorItems.noSelect());
},
colorSelect : function(c) {
this.ne.nicCommand('foreColor',c);
this.removePane();
},
on : function(colorBorder) {
colorBorder.setStyle({border : '2px solid #000'});
},
off : function(colorBorder,colorCode) {
colorBorder.setStyle({border : '2px solid '+colorCode});
}
});
var nicEditorBgColorButton = nicEditorColorButton.extend({
colorSelect : function(c) {
this.ne.nicCommand('hiliteColor',c);
this.removePane();
}
});
nicEditors.registerPlugin(nicPlugin,nicColorOptions);
/** nicXHTML */
var nicXHTML = bkClass.extend({
stripAttributes : ['_moz_dirty','_moz_resizing','_extended'],
noShort : ['style','title','script','textarea','a'],
cssReplace : {'font-weight:bold;' : 'strong', 'font-style:italic;' : 'em'},
sizes : {1 : 'xx-small', 2 : 'x-small', 3 : 'small', 4 : 'medium', 5 : 'large', 6 : 'x-large'},
construct : function(nicEditor) {
this.ne = nicEditor;
if(this.ne.options.xhtml) {
nicEditor.addEvent('get',this.cleanup.closure(this));
}
},
cleanup : function(ni) {
var node = ni.getElm();
var xhtml = this.toXHTML(node);
ni.content = xhtml;
},
toXHTML : function(n,r,d) {
var txt = '';
var attrTxt = '';
var cssTxt = '';
var nType = n.nodeType;
var nName = n.nodeName.toLowerCase();
var nChild = n.hasChildNodes && n.hasChildNodes();
var extraNodes = new Array();
switch(nType) {
case 1:
var nAttributes = n.attributes;
switch(nName) {
case 'b':
nName = 'strong';
break;
case 'i':
nName = 'em';
break;
case 'font':
nName = 'span';
break;
}
if(r) {
for(var i=0;i<nAttributes.length;i++) {
var attr = nAttributes[i];
var attributeName = attr.nodeName.toLowerCase();
var attributeValue = attr.nodeValue;
if(!attr.specified || !attributeValue || bkLib.inArray(this.stripAttributes,attributeName) || typeof(attributeValue) == "function") {
continue;
}
switch(attributeName) {
case 'style':
var css = attributeValue.replace(/ /g,"");
for(itm in this.cssReplace) {
if(css.indexOf(itm) != -1) {
extraNodes.push(this.cssReplace[itm]);
css = css.replace(itm,'');
}
}
cssTxt += css;
attributeValue = "";
break;
case 'class':
attributeValue = attributeValue.replace("Apple-style-span","");
break;
case 'size':
cssTxt += "font-size:"+this.sizes[attributeValue]+';';
attributeValue = "";
break;
}
if(attributeValue) {
attrTxt += ' '+attributeName+'="'+attributeValue+'"';
}
}
if(cssTxt) {
attrTxt += ' style="'+cssTxt+'"';
}
for(var i=0;i<extraNodes.length;i++) {
txt += '<'+extraNodes[i]+'>';
}
if(attrTxt == "" && nName == "span") {
r = false;
}
if(r) {
txt += '<'+nName;
if(nName != 'br') {
txt += attrTxt;
}
}
}
if(!nChild && !bkLib.inArray(this.noShort,attributeName)) {
if(r) {
txt += ' />';
}
} else {
if(r) {
txt += '>';
}
for(var i=0;i<n.childNodes.length;i++) {
var results = this.toXHTML(n.childNodes[i],true,true);
if(results) {
txt += results;
}
}
}
if(r && nChild) {
txt += '</'+nName+'>';
}
for(var i=0;i<extraNodes.length;i++) {
txt += '</'+extraNodes[i]+'>';
}
break;
case 3:
//if(n.nodeValue != '\n') {
txt += n.nodeValue;
//}
break;
}
return txt;
}
});
nicEditors.registerPlugin(nicXHTML);
/** nicCode */
/* START CONFIG */
var nicCodeOptions = {
buttons : {
'xhtml' : {name : __('Edit HTML'), type : 'nicCodeButton'}
}
};
/* END CONFIG */
var nicCodeButton = nicEditorAdvancedButton.extend({
width : '350px',
addPane : function() {
this.addForm({
'' : {type : 'title', txt : __('Edit HTML')},
'code' : {type : 'content', 'value' : this.ne.selectedInstance.getContent(), style : {width: '340px', height : '200px'}}
});
},
submit : function(e) {
var code = this.inputs['code'].value;
this.ne.selectedInstance.setContent(code);
this.removePane();
}
});
nicEditors.registerPlugin(nicPlugin,nicCodeOptions);
/** nicTable (c) Vitaliy Filippov */
/* START CONFIG */
var nicTableOptions = {
buttons : {
'table' : {name : __('Add Table'), type : 'nicTableButton', tags : ['TABLE']}
}
};
/* END CONFIG */
var nicTableButton = nicEditorAdvancedButton.extend({
addPane: function() {
this.t = this.ne.selectedInstance.selElm().parentTag('TABLE');
var r = 3, c = 3, h = '', b = 'yes';
if (this.t && (r = this.t.rows.length)) {
c = this.t.rows[0].cells.length;
if (this.t.rows[0].cells[c-1].nodeName == 'TH') h += 'top';
if (this.t.rows[r-1].cells[0].nodeName == 'TH') h += 'left';
if (this.t.className.indexOf('bordered') < 0) b = 'no';
}
this.addForm({
'': {type: 'title', txt: __('Add/Edit Table')},
'cols': {type: 'text', txt: __('Columns'), value: c, style: {width: '50px'}},
'rows': {type: 'text', txt: __('Rows'), value: r, style: {width: '50px'}},
'header': {type: 'select', txt: __('Headers'), value: h, options: {'':__('None'), left:__('Left'), top:__('Top'), topleft:__('Top and Left')}},
'bordered': {type: 'select', txt: __('Borders'), value: b, options: {'no':__('No'), 'yes':__('Yes')}}
},this.t);
},
submit: function(e) {
var r = parseInt(this.inputs['rows'].value);
var c = parseInt(this.inputs['cols'].value);
var cl = this.inputs['bordered'].value == 'no' ? '' : 'bordered';
var i, j;
if(!this.t) {
var tmp = 'javascript:nicImTemp();', h = '';
for (i = 0; i < r; i++) {
h += '<tr>'+(new Array(c+1)).join('<td>-</td>')+'</tr>';
}
this.ne.nicCommand("insertHTML", '<table title="'+tmp+'">'+h+'</table>');
this.t = this.findElm('TABLE','title',tmp);
}
if(this.t) {
this.t.className = cl;
this.t.removeAttribute('title');
for (i = this.t.rows.length-1; i >= r; i--) {
this.t.deleteRow(r);
}
for (i = this.t.rows.length; i < r; i++) {
this.t.insertRow(i).innerHTML = (new Array(c+1)).join('<td>-</td>');
}
if (this.t.rows.length && this.t.rows[0].cells.length != c) {
for (i = 0; i < r; i++) {
for (j = this.t.rows[i].cells.length; j < c; j++) {
this.t.rows[i].insertCell(j).innerHTML = '-';
}
for (j = this.t.rows[i].cells.length-1; j >= c; j--) {
$BK(this.t.rows[i].cells[c]).remove();
}
}
}
if (this.t.rows.length) {
var ht = this.inputs['header'].value;
var repl = function(node, name) {
var nn = document.createElement(name ? 'th' : 'td');
nn.innerHTML = node.innerHTML;
node.parentNode.insertBefore(nn, node);
node.parentNode.removeChild(node);
};
repl(this.t.rows[0].cells[0], ht != '');
j = ht == 'top' || ht == 'topleft';
for (i = 1; i < c; i++) {
repl(this.t.rows[0].cells[i], j);
}
j = ht == 'left' || ht == 'topleft';
for (i = 1; i < r; i++) {
repl(this.t.rows[i].cells[0], j);
}
}
}
}
});
nicEditors.registerPlugin(nicPlugin,nicTableOptions);
/** nicFloatingPanel */
nicEditor = nicEditor.extend({
floatingPanel: function() {
this.floating = new bkElement('DIV').setStyle({display: 'inline-block', position: 'absolute', left: '-1000px', top: '-1000px', zIndex: 100}).appendTo(document.body);
this.addEvent('focus', this.reposition.closure(this)).addEvent('blur', this.hide.closure(this));
bkLib.addEvent(window, 'scroll', this.reposition.closure(this));
this.setPanel(this.floating);
},
reposition: function() {
var e = this.selectedInstance;
if (!e || !(e = e.elm)) return;
var h = this.floating.offsetHeight;
var p = e.pos();
var d = document;
d = window.pageYOffset || d.body.scrollTop || d.documentElement.scrollTop;
var top = p[1]-h;
this.floating.setStyle({ top: (top < d ? d : top)+'px', left: p[0]+'px' });
},
hide: function() {
this.floating.setStyle({ top: '-1000px', left: '-1000px' });
}
});