noalyss Version-9
nicEdit.js
Go to the documentation of this file.
1/* NicEdit - Micro Inline WYSIWYG
2 * Copyright 2007-2008 Brian Kirchoff
3 *
4 * NicEdit is distributed under the terms of the MIT license
5 * For more information visit http://nicedit.com/
6 * Do not remove this copyright message
7 */
8var bkExtend = function(){
9 var args = arguments;
10 if (args.length == 1) args = [this, args[0]];
11 for (var prop in args[1]) args[0][prop] = args[1][prop];
12 return args[0];
13};
14function bkClass() { }
15bkClass.prototype.construct = function() {};
16bkClass.extend = function(def) {
17 var classDef = function() {
18 if (arguments[0] !== bkClass) { return this.construct.apply(this, arguments); }
19 };
20 var proto = new this(bkClass);
21 bkExtend(proto,def);
22 classDef.prototype = proto;
23 classDef.extend = this.extend;
24 return classDef;
25};
26
27var bkElement = bkClass.extend({
28 construct : function(elm,d) {
29 if(typeof(elm) == "string") {
30 elm = (d || document).createElement(elm);
31 }
32 elm = $BK(elm);
33 return elm;
34 },
35
36 appendTo : function(elm) {
37 elm.appendChild(this);
38 return this;
39 },
40
41 appendBefore : function(elm) {
42 elm.parentNode.insertBefore(this,elm);
43 return this;
44 },
45
46 addEvent : function(type, fn) {
47 bkLib.addEvent(this,type,fn);
48 return this;
49 },
50
51 setContent : function(c) {
52 this.innerHTML = c;
53 return this;
54 },
55
56 pos : function() {
57 var curleft = curtop = 0;
58 var o = obj = this;
59 if (obj.offsetParent) {
60 do {
61 curleft += obj.offsetLeft;
62 curtop += obj.offsetTop;
63 } while (obj = obj.offsetParent);
64 }
65 var b = (!window.opera) ? parseInt(this.getStyle('border-width') || this.style.border) || 0 : 0;
66 return [curleft+b,curtop+b+this.offsetHeight];
67 },
68
69 noSelect : function() {
70 bkLib.noSelect(this);
71 return this;
72 },
73
74 parentTag : function(t) {
75 var elm = this;
76 do {
77 if(elm && elm.nodeName && elm.nodeName.toUpperCase() == t) {
78 return elm;
79 }
80 elm = elm.parentNode;
81 } while(elm);
82 return false;
83 },
84
85 hasClass : function(cls) {
86 return this.className.match(new RegExp('(\\s|^)nicEdit-'+cls+'(\\s|$)'));
87 },
88
89 addClass : function(cls) {
90 if (!this.hasClass(cls)) { this.className += " nicEdit-"+cls };
91 return this;
92 },
93
94 removeClass : function(cls) {
95 if (this.hasClass(cls)) {
96 this.className = this.className.replace(new RegExp('(\\s|^)nicEdit-'+cls+'(\\s|$)'),' ');
97 }
98 return this;
99 },
100
101 setStyle : function(st) {
102 var elmStyle = this.style;
103 for(var itm in st) {
104 switch(itm) {
105 case 'float':
106 elmStyle['cssFloat'] = elmStyle['styleFloat'] = st[itm];
107 break;
108 case 'opacity':
109 elmStyle.opacity = st[itm];
110 elmStyle.filter = "alpha(opacity=" + Math.round(st[itm]*100) + ")";
111 break;
112 case 'className':
113 this.className = st[itm];
114 break;
115 default:
116 //if(document.compatMode || itm != "cursor") { // Nasty Workaround for IE 5.5
117 elmStyle[itm] = st[itm];
118 //}
119 }
120 }
121 return this;
122 },
123
124 getStyle : function( cssRule, d ) {
125 var doc = (!d) ? document.defaultView : d;
126 if(this.nodeType == 1)
127 return (doc && doc.getComputedStyle) ? doc.getComputedStyle( this, null ).getPropertyValue(cssRule) : this.currentStyle[ bkLib.camelize(cssRule) ];
128 },
129
130 remove : function() {
131 this.parentNode.removeChild(this);
132 return this;
133 },
134
135 setAttributes : function(at) {
136 for(var itm in at) {
137 this[itm] = at[itm];
138 }
139 return this;
140 }
141});
142
143var bkLib = {
144 isMSIE : (navigator.appVersion.indexOf("MSIE") != -1),
145
146 addEvent : function(obj, type, fn) {
147 (obj.addEventListener) ? obj.addEventListener( type, fn, false ) : obj.attachEvent("on"+type, fn);
148 },
149
150 toArray : function(iterable) {
151 var length = iterable.length, results = new Array(length);
152 while (length--) { results[length] = iterable[length] };
153 return results;
154 },
155
156 noSelect : function(element) {
157 if(element.setAttribute && element.nodeName.toLowerCase() != 'input' && element.nodeName.toLowerCase() != 'textarea') {
158 element.setAttribute('unselectable','on');
159 }
160 for(var i=0;i<element.childNodes.length;i++) {
161 bkLib.noSelect(element.childNodes[i]);
162 }
163 },
164 camelize : function(s) {
165 return s.replace(/\-(.)/g, function(m, l){return l.toUpperCase()});
166 },
167 inArray : function(arr,item) {
168 return (bkLib.search(arr,item) != null);
169 },
170 search : function(arr,itm) {
171 for(var i=0; i < arr.length; i++) {
172 if(arr[i] == itm)
173 return i;
174 }
175 return null;
176 },
177 cancelEvent : function(e) {
178 e = e || window.event;
179 if(e.preventDefault && e.stopPropagation) {
180 e.preventDefault();
181 e.stopPropagation();
182 }
183 return false;
184 },
185 domLoad : [],
186 domLoaded : function() {
187 if (arguments.callee.done) return;
188 arguments.callee.done = true;
189 for (i = 0;i < bkLib.domLoad.length;i++) bkLib.domLoad[i]();
190 },
191 onDomLoaded : function(fireThis) {
192 this.domLoad.push(fireThis);
193 if (document.addEventListener) {
194 document.addEventListener("DOMContentLoaded", bkLib.domLoaded, null);
195 } else if(bkLib.isMSIE) {
196 document.write("<style>.nicEdit-main p { margin: 0; }</style><scr"+"ipt id=__ie_onload defer " + ((location.protocol == "https:") ? "src='javascript:void(0)'" : "src=//0") + "><\/scr"+"ipt>");
197 $BK("__ie_onload").onreadystatechange = function() {
198 if (this.readyState == "complete"){bkLib.domLoaded();}
199 };
200 }
201 window.onload = bkLib.domLoaded;
202 }
203};
204
205function $BK(elm) {
206 if(typeof(elm) == "string") {
207 elm = document.getElementById(elm);
208 }
209 return (elm && !elm.appendTo) ? bkExtend(elm,bkElement.prototype) : elm;
210}
211
212var bkEvent = {
213 addEvent : function(evType, evFunc) {
214 if(evFunc) {
215 this.eventList = this.eventList || {};
216 this.eventList[evType] = this.eventList[evType] || [];
217 this.eventList[evType].push(evFunc);
218 }
219 return this;
220 },
221 fireEvent : function() {
222 var args = bkLib.toArray(arguments), evType = args.shift();
223 if(this.eventList && this.eventList[evType]) {
224 for(var i=0;i<this.eventList[evType].length;i++) {
225 this.eventList[evType][i].apply(this,args);
226 }
227 }
228 }
229};
230
231function __(s) {
232 return s;
233}
234
235Function.prototype.closure = function() {
236 var __method = this, args = bkLib.toArray(arguments), obj = args.shift();
237 return function() { if(typeof(bkLib) != 'undefined') { return __method.apply(obj,args.concat(bkLib.toArray(arguments))); } };
238}
239
240Function.prototype.closureListener = function() {
241 var __method = this, args = bkLib.toArray(arguments), object = args.shift();
242 return function(e) {
243 e = e || window.event;
244 if(e.target) { var target = e.target; } else { var target = e.srcElement };
245 return __method.apply(object, [e,target].concat(args) );
246 };
247}
248
249
250/* START CONFIG */
251
252var nicEditorConfig = bkClass.extend({
253 buttons : {
254 'bold' : {name : __('Click to Bold'), command : 'Bold', tags : ['B','STRONG'], css : {'font-weight' : 'bold'}, key : 'b'},
255 'italic' : {name : __('Click to Italic'), command : 'Italic', tags : ['EM','I'], css : {'font-style' : 'italic'}, key : 'i'},
256 'underline' : {name : __('Click to Underline'), command : 'Underline', tags : ['U'], css : {'text-decoration' : 'underline'}, key : 'u'},
257 'left' : {name : __('Left Align'), command : 'justifyleft', noActive : true},
258 'center' : {name : __('Center Align'), command : 'justifycenter', noActive : true},
259 'right' : {name : __('Right Align'), command : 'justifyright', noActive : true},
260 'justify' : {name : __('Justify Align'), command : 'justifyfull', noActive : true},
261 'ol' : {name : __('Insert Ordered List'), command : 'insertorderedlist', tags : ['OL']},
262 'ul' : {name : __('Insert Unordered List'), command : 'insertunorderedlist', tags : ['UL']},
263 'subscript' : {name : __('Click to Subscript'), command : 'subscript', tags : ['SUB']},
264 'superscript' : {name : __('Click to Superscript'), command : 'superscript', tags : ['SUP']},
265 'strikethrough' : {name : __('Click to Strike Through'), command : 'strikeThrough', css : {'text-decoration' : 'line-through'}},
266 'removeformat' : {name : __('Remove Formatting'), command : 'removeformat', noActive : true},
267 'indent' : {name : __('Indent Text'), command : 'indent', noActive : true},
268 'outdent' : {name : __('Remove Indent'), command : 'outdent', noActive : true},
269 'hr' : {name : __('Horizontal Rule'), command : 'insertHorizontalRule', noActive : true}
270 },
271 iconsPath : '../nicEditorIcons.gif',
272 buttonList : ['save','bold','italic','underline','left','center','right','justify','ol','ul','fontSize','fontFamily','fontFormat','indent','outdent','image','upload','link','unlink','forecolor','bgcolor'],
273 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}
274
275});
276/* END CONFIG */
277
278
279var nicEditors = {
280 nicPlugins : [],
281 editors : [],
282
283 registerPlugin : function(plugin,options) {
284 this.nicPlugins.push({p : plugin, o : options});
285 },
286
287 allTextAreas : function(nicOptions) {
288 var textareas = document.getElementsByTagName("textarea");
289 for(var i=0;i<textareas.length;i++) {
290 nicEditors.editors.push(new nicEditor(nicOptions).panelInstance(textareas[i]));
291 }
292 return nicEditors.editors;
293 },
294
295 findEditor : function(e) {
296 var editors = nicEditors.editors;
297 for(var i=0;i<editors.length;i++) {
298 if(editors[i].instanceById(e)) {
299 return editors[i].instanceById(e);
300 }
301 }
302 }
303};
304
305
306var nicEditor = bkClass.extend({
307 construct : function(o) {
308 this.options = new nicEditorConfig();
309 bkExtend(this.options,o);
310 this.nicInstances = new Array();
311 this.loadedPlugins = new Array();
312
313 var plugins = nicEditors.nicPlugins;
314 for(var i=0;i<plugins.length;i++) {
315 this.loadedPlugins.push(new plugins[i].p(this,plugins[i].o));
316 }
317 nicEditors.editors.push(this);
318 bkLib.addEvent(document.body,'mousedown', this.selectCheck.closureListener(this) );
319 },
320
321 panelInstance : function(e,o) {
322 e = this.checkReplace($BK(e));
323 var panelElm = new bkElement('DIV').setStyle({width : (parseInt(e.getStyle('width')) || e.clientWidth)+'px'}).appendBefore(e);
324 this.setPanel(panelElm);
325 return this.addInstance(e,o);
326 },
327
328 checkReplace : function(e) {
329 var r = nicEditors.findEditor(e);
330 if(r) {
331 r.removeInstance(e);
332 r.removePanel();
333 }
334 return e;
335 },
336
337 addInstance : function(e,o) {
338 e = this.checkReplace($BK(e));
339 if( e.contentEditable || !!window.opera ) {
340 var newInstance = new nicEditorInstance(e,o,this);
341 } else {
342 var newInstance = new nicEditorIFrameInstance(e,o,this);
343 }
344 this.nicInstances.push(newInstance);
345 return this;
346 },
347
348 removeInstance : function(e) {
349 e = $BK(e);
350 var instances = this.nicInstances;
351 for(var i=0;i<instances.length;i++) {
352 if(instances[i].e == e) {
353 instances[i].remove();
354 this.nicInstances.splice(i,1);
355 }
356 }
357 },
358
359 removePanel : function(e) {
360 if(this.nicPanel) {
361 this.nicPanel.remove();
362 this.nicPanel = null;
363 }
364 },
365
366 instanceById : function(e) {
367 e = $BK(e);
368 var instances = this.nicInstances;
369 for(var i=0;i<instances.length;i++) {
370 if(instances[i].e == e) {
371 return instances[i];
372 }
373 }
374 },
375
376 setPanel : function(e) {
377 this.nicPanel = new nicEditorPanel($BK(e),this.options,this);
378 this.fireEvent('panel',this.nicPanel);
379 return this;
380 },
381
382 nicCommand : function(cmd,args) {
383 if(this.selectedInstance) {
384 this.selectedInstance.nicCommand(cmd,args);
385 }
386 },
387
388 getIcon : function(iconName,options) {
389 var icon = this.options.iconList[iconName];
390 var file = (options.iconFiles) ? options.iconFiles[iconName] : '';
391 return {backgroundImage : "url('"+((icon) ? this.options.iconsPath : file)+"')", backgroundPosition : ((icon) ? ((icon-1)*-18) : 0)+'px 0px'};
392 },
393
394 selectCheck : function(e,t) {
395 var found = false;
396 do{
397 if(t.className && t.className.indexOf('nicEdit') != -1) {
398 return false;
399 }
400 } while(t = t.parentNode);
401 this.fireEvent('blur',this.selectedInstance,t);
402 this.lastSelectedInstance = this.selectedInstance;
403 this.selectedInstance = null;
404 return false;
405 }
406
407});
408nicEditor = nicEditor.extend(bkEvent);
409
410
411var nicEditorInstance = bkClass.extend({
412 isSelected : false,
413
414 construct : function(e,options,nicEditor) {
415 this.ne = nicEditor;
416 this.elm = this.e = e;
417 this.options = options || {};
418
419 newX = parseInt(e.getStyle('width')) || e.clientWidth;
420 newY = parseInt(e.getStyle('height')) || e.clientHeight;
421 this.initialHeight = newY-8;
422
423 var isTextarea = (e.nodeName.toLowerCase() == "textarea");
424 if(isTextarea || this.options.hasPanel) {
425 var ie7s = (bkLib.isMSIE && !((typeof document.body.style.maxHeight != "undefined") && document.compatMode == "CSS1Compat"))
426 var s = {width: newX+'px', border : '1px solid #ccc', borderTop : 0, overflowY : 'auto', overflowX: 'hidden' };
427 s[(ie7s) ? 'height' : 'maxHeight'] = (this.ne.options.maxHeight) ? this.ne.options.maxHeight+'px' : null;
428 this.editorContain = new bkElement('DIV').setStyle(s).appendBefore(e);
429 var editorElm = new bkElement('DIV').setStyle({width : (newX-8)+'px', margin: '4px', minHeight : newY+'px'}).addClass('main').appendTo(this.editorContain);
430
431 e.setStyle({display : 'none'});
432
433 editorElm.innerHTML = e.innerHTML;
434 if(isTextarea) {
435 editorElm.setContent(e.value);
436 this.copyElm = e;
437 var f = e.parentTag('FORM');
438 if(f) { bkLib.addEvent( f, 'submit', this.saveContent.closure(this)); }
439 }
440 editorElm.setStyle((ie7s) ? {height : newY+'px'} : {overflow: 'hidden'});
441 this.elm = editorElm;
442 }
443 this.ne.addEvent('blur',this.blur.closure(this));
444
445 this.init();
446 this.blur();
447 },
448
449 init : function() {
450 this.elm.setAttribute('contentEditable','true');
451 if(this.getContent() == "") {
452 this.setContent('<br />');
453 }
454 this.instanceDoc = document.defaultView;
455 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));
456 this.ne.fireEvent('add',this);
457 },
458
459 remove : function() {
460 this.saveContent();
461 if(this.copyElm || this.options.hasPanel) {
462 this.editorContain.remove();
463 this.e.setStyle({'display' : 'block'});
464 this.ne.removePanel();
465 }
466 this.disable();
467 this.ne.fireEvent('remove',this);
468 },
469
470 disable : function() {
471 this.elm.setAttribute('contentEditable','false');
472 },
473
474 getSel : function() {
475 return (window.getSelection) ? window.getSelection() : document.selection;
476 },
477
478 getRng : function() {
479 var s = this.getSel();
480 if(!s || s.rangeCount === 0) { return; }
481 return (s.rangeCount > 0) ? s.getRangeAt(0) : s.createRange();
482 },
483
484 selRng : function(rng,s) {
485 if(window.getSelection) {
486 s.removeAllRanges();
487 s.addRange(rng);
488 } else {
489 rng.select();
490 }
491 },
492
493 selElm : function() {
494 var r = this.getRng();
495 if(!r) { return; }
496 if(r.startContainer) {
497 var contain = r.startContainer;
498 if(r.cloneContents().childNodes.length == 1) {
499 for(var i=0;i<contain.childNodes.length;i++) {
500 var rng = contain.childNodes[i].ownerDocument.createRange();
501 rng.selectNode(contain.childNodes[i]);
502 if(r.compareBoundaryPoints(Range.START_TO_START,rng) != 1 &&
503 r.compareBoundaryPoints(Range.END_TO_END,rng) != -1) {
504 return $BK(contain.childNodes[i]);
505 }
506 }
507 }
508 return $BK(contain);
509 } else {
510 return $BK((this.getSel().type == "Control") ? r.item(0) : r.parentElement());
511 }
512 },
513
514 saveRng : function() {
515 this.savedRange = this.getRng();
516 this.savedSel = this.getSel();
517 },
518
519 restoreRng : function() {
520 if(this.savedRange) {
521 this.selRng(this.savedRange,this.savedSel);
522 }
523 },
524
525 keyDown : function(e,t) {
526 if(e.ctrlKey) {
527 this.ne.fireEvent('key',this,e);
528 }
529 },
530
531 selected : function(e,t) {
532 if(!t && !(t = this.selElm)) { t = this.selElm(); }
533 if(!e.ctrlKey) {
534 var selInstance = this.ne.selectedInstance;
535 if(selInstance != this) {
536 if(selInstance) {
537 this.ne.fireEvent('blur',selInstance,t);
538 }
539 this.ne.selectedInstance = this;
540 this.ne.fireEvent('focus',selInstance,t);
541 }
542 this.ne.fireEvent('selected',selInstance,t);
543 this.isFocused = true;
544 this.elm.addClass('selected');
545 }
546 return false;
547 },
548
549 blur : function() {
550 this.isFocused = false;
551 this.elm.removeClass('selected');
552 },
553
554 saveContent : function() {
555 if(this.copyElm || this.options.hasPanel) {
556 this.ne.fireEvent('save',this);
557 (this.copyElm) ? this.copyElm.value = this.getContent() : this.e.innerHTML = this.getContent();
558 }
559 },
560
561 getElm : function() {
562 return this.elm;
563 },
564
565 getContent : function() {
566 this.content = this.getElm().innerHTML;
567 this.ne.fireEvent('get',this);
568 return this.content;
569 },
570
571 setContent : function(e) {
572 this.content = e;
573 this.ne.fireEvent('set',this);
574 this.elm.innerHTML = this.content;
575 },
576
577 nicCommand : function(cmd,args) {
578 document.execCommand(cmd,false,args);
579 }
580});
581
582var nicEditorIFrameInstance = nicEditorInstance.extend({
583 savedStyles : [],
584
585 init : function() {
586 var c = this.elm.innerHTML.replace(/^\s+|\s+$/g, '');
587 this.elm.innerHTML = '';
588 (!c) ? c = "<br />" : c;
589 this.initialContent = c;
590
591 this.elmFrame = new bkElement('iframe').setAttributes({'src' : 'javascript:;', 'frameBorder' : 0, 'allowTransparency' : 'true', 'scrolling' : 'no'}).setStyle({height: '100px', width: '100%'}).addClass('frame').appendTo(this.elm);
592
593 if(this.copyElm) { this.elmFrame.setStyle({width : (this.elm.offsetWidth-4)+'px'}); }
594
595 var styleList = ['font-size','font-family','font-weight','color'];
596 for(itm in styleList) {
597 this.savedStyles[bkLib.camelize(itm)] = this.elm.getStyle(itm);
598 }
599
600 setTimeout(this.initFrame.closure(this),50);
601 },
602
603 disable : function() {
604 this.elm.innerHTML = this.getContent();
605 },
606
607 initFrame : function() {
608 var fd = $BK(this.elmFrame.contentWindow.document);
609 fd.designMode = "on";
610 fd.open();
611 var css = this.ne.options.externalCSS;
612 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>');
613 fd.close();
614 this.frameDoc = fd;
615
616 this.frameWin = $BK(this.elmFrame.contentWindow);
617 this.frameContent = $BK(this.frameWin.document.body).setStyle(this.savedStyles);
618 this.instanceDoc = this.frameWin.document.defaultView;
619
620 this.heightUpdate();
621 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));
622 this.ne.fireEvent('add',this);
623 },
624
625 getElm : function() {
626 return this.frameContent;
627 },
628
629 setContent : function(c) {
630 this.content = c;
631 this.ne.fireEvent('set',this);
632 this.frameContent.innerHTML = this.content;
633 this.heightUpdate();
634 },
635
636 getSel : function() {
637 return (this.frameWin) ? this.frameWin.getSelection() : this.frameDoc.selection;
638 },
639
640 heightUpdate : function() {
641 this.elmFrame.style.height = Math.max(this.frameContent.offsetHeight,this.initialHeight)+'px';
642 },
643
644 nicCommand : function(cmd,args) {
645 this.frameDoc.execCommand(cmd,false,args);
646 setTimeout(this.heightUpdate.closure(this),100);
647 }
648
649
650});
651var nicEditorPanel = bkClass.extend({
652 construct : function(e,options,nicEditor) {
653 this.elm = e;
654 this.options = options;
655 this.ne = nicEditor;
656 this.panelButtons = new Array();
657 this.buttonList = bkExtend([],this.ne.options.buttonList);
658
659 this.panelContain = new bkElement('DIV').setStyle({overflow : 'hidden', width : '100%', border : '1px solid #cccccc', backgroundColor : '#efefef'}).addClass('panelContain');
660 this.panelElm = new bkElement('DIV').setStyle({margin : '2px', marginTop : '0px', zoom : 1, overflow : 'hidden'}).addClass('panel').appendTo(this.panelContain);
661 this.panelContain.appendTo(e);
662
663 var opt = this.ne.options;
664 var buttons = opt.buttons;
665 for(button in buttons) {
666 this.addButton(button,opt,true);
667 }
668 this.reorder();
669 e.noSelect();
670 },
671
672 addButton : function(buttonName,options,noOrder) {
673 var button = options.buttons[buttonName];
674 var type = (button['type']) ? eval('(typeof('+button['type']+') == "undefined") ? null : '+button['type']+';') : nicEditorButton;
675 var hasButton = bkLib.inArray(this.buttonList,buttonName);
676 if(type && (hasButton || this.ne.options.fullPanel)) {
677 this.panelButtons.push(new type(this.panelElm,buttonName,options,this.ne));
678 if(!hasButton) {
679 this.buttonList.push(buttonName);
680 }
681 }
682 },
683
684 findButton : function(itm) {
685 for(var i=0;i<this.panelButtons.length;i++) {
686 if(this.panelButtons[i].name == itm)
687 return this.panelButtons[i];
688 }
689 },
690
691 reorder : function() {
692 var bl = this.buttonList;
693 for(var i=0;i<bl.length;i++) {
694 var button = this.findButton(bl[i]);
695 if(button) {
696 this.panelElm.appendChild(button.margin);
697 }
698 }
699 },
700
701 remove : function() {
702 this.elm.remove();
703 }
704});
705var nicEditorButton = bkClass.extend({
706
707 construct : function(e,buttonName,options,nicEditor) {
708 this.options = options.buttons[buttonName];
709 this.name = buttonName;
710 this.ne = nicEditor;
711 this.elm = e;
712
713 this.margin = new bkElement('DIV').setStyle({'float' : 'left', marginTop : '2px'}).appendTo(e);
714 this.contain = new bkElement('DIV').setStyle({width : '20px', height : '20px'}).addClass('buttonContain').appendTo(this.margin);
715 this.border = new bkElement('DIV').setStyle({backgroundColor : '#efefef', border : '1px solid #efefef'}).appendTo(this.contain);
716 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);
717 this.button.addEvent('mouseover', this.hoverOn.closure(this)).addEvent('mouseout',this.hoverOff.closure(this)).addEvent('mousedown',this.mouseClick.closure(this)).noSelect();
718
719 if(!window.opera) {
720 this.button.onmousedown = this.button.onclick = bkLib.cancelEvent;
721 }
722
723 nicEditor.addEvent('selected', this.enable.closure(this)).addEvent('blur', this.disable.closure(this)).addEvent('key',this.key.closure(this));
724
725 this.disable();
726 this.init();
727 },
728
729 init : function() { },
730
731 hide : function() {
732 this.contain.setStyle({display : 'none'});
733 },
734
735 updateState : function() {
736 if(this.isDisabled) { this.setBg(); }
737 else if(this.isHover) { this.setBg('hover'); }
738 else if(this.isActive) { this.setBg('active'); }
739 else { this.setBg(); }
740 },
741
742 setBg : function(state) {
743 switch(state) {
744 case 'hover':
745 var stateStyle = {border : '1px solid #666', backgroundColor : '#ddd'};
746 break;
747 case 'active':
748 var stateStyle = {border : '1px solid #666', backgroundColor : '#ccc'};
749 break;
750 default:
751 var stateStyle = {border : '1px solid #efefef', backgroundColor : '#efefef'};
752 }
753 this.border.setStyle(stateStyle).addClass('button-'+state);
754 },
755
756 checkNodes : function(e) {
757 var elm = e;
758 do {
759 if(this.options.tags && bkLib.inArray(this.options.tags,elm.nodeName)) {
760 this.activate();
761 return true;
762 }
763 } while(elm = elm.parentNode && elm.className != "nicEdit");
764 elm = $BK(e);
765 while(elm.nodeType == 3) {
766 elm = $BK(elm.parentNode);
767 }
768 if(this.options.css) {
769 for(itm in this.options.css) {
770 if(elm.getStyle(itm,this.ne.selectedInstance.instanceDoc) == this.options.css[itm]) {
771 this.activate();
772 return true;
773 }
774 }
775 }
776 this.deactivate();
777 return false;
778 },
779
780 activate : function() {
781 if(!this.isDisabled) {
782 this.isActive = true;
783 this.updateState();
784 this.ne.fireEvent('buttonActivate',this);
785 }
786 },
787
788 deactivate : function() {
789 this.isActive = false;
790 this.updateState();
791 if(!this.isDisabled) {
792 this.ne.fireEvent('buttonDeactivate',this);
793 }
794 },
795
796 enable : function(ins,t) {
797 this.isDisabled = false;
798 this.contain.setStyle({'opacity' : 1}).addClass('buttonEnabled');
799 this.updateState();
800 this.checkNodes(t);
801 },
802
803 disable : function(ins,t) {
804 this.isDisabled = true;
805 this.contain.setStyle({'opacity' : 0.6}).removeClass('buttonEnabled');
806 this.updateState();
807 },
808
809 toggleActive : function() {
810 (this.isActive) ? this.deactivate() : this.activate();
811 },
812
813 hoverOn : function() {
814 if(!this.isDisabled) {
815 this.isHover = true;
816 this.updateState();
817 this.ne.fireEvent("buttonOver",this);
818 }
819 },
820
821 hoverOff : function() {
822 this.isHover = false;
823 this.updateState();
824 this.ne.fireEvent("buttonOut",this);
825 },
826
827 mouseClick : function() {
828 if(this.options.command) {
829 this.ne.nicCommand(this.options.command,this.options.commandArgs);
830 if(!this.options.noActive) {
831 this.toggleActive();
832 }
833 }
834 this.ne.fireEvent("buttonClick",this);
835 },
836
837 key : function(nicInstance,e) {
838 if(this.options.key && e.ctrlKey && String.fromCharCode(e.keyCode || e.charCode).toLowerCase() == this.options.key) {
839 this.mouseClick();
840 if(e.preventDefault) e.preventDefault();
841 }
842 }
843
844});
845
846
847var nicPlugin = bkClass.extend({
848
849 construct : function(nicEditor,options) {
850 this.options = options;
851 this.ne = nicEditor;
852 this.ne.addEvent('panel',this.loadPanel.closure(this));
853
854 this.init();
855 },
856
857 loadPanel : function(np) {
858 var buttons = this.options.buttons;
859 for(var button in buttons) {
860 np.addButton(button,this.options);
861 }
862 np.reorder();
863 },
864
865 init : function() { }
866});
867
868
869
870
871 /* START CONFIG */
872var nicPaneOptions = { };
873/* END CONFIG */
874
875var nicEditorPane = bkClass.extend({
876 construct : function(elm,nicEditor,options,openButton) {
877 this.ne = nicEditor;
878 this.elm = elm;
879 this.pos = elm.pos();
880
881 this.contain = new bkElement('div').setStyle({zIndex : '99999', overflow : 'hidden', position : 'absolute', left : this.pos[0]+'px', top : this.pos[1]+'px'})
882 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);
883
884 if(openButton && !openButton.options.noClose) {
885 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);
886 }
887
888 this.contain.noSelect().appendTo(document.body);
889
890 this.position();
891 this.init();
892 },
893
894 init : function() { },
895
896 position : function() {
897 if(this.ne.nicPanel) {
898 var panelElm = this.ne.nicPanel.elm;
899 var panelPos = panelElm.pos();
900 var newLeft = panelPos[0]+parseInt(panelElm.getStyle('width'))-(parseInt(this.pane.getStyle('width'))+8);
901 if(newLeft < this.pos[0]) {
902 this.contain.setStyle({left : newLeft+'px'});
903 }
904 }
905 },
906
907 toggle : function() {
908 this.isVisible = !this.isVisible;
909 this.contain.setStyle({display : ((this.isVisible) ? 'block' : 'none')});
910 },
911
912 remove : function() {
913 if(this.contain) {
914 this.contain.remove();
915 this.contain = null;
916 }
917 },
918
919 append : function(c) {
920 c.appendTo(this.pane);
921 },
922
923 setContent : function(c) {
924 this.pane.setContent(c);
925 }
926
927});
928
929
930
931var nicEditorAdvancedButton = nicEditorButton.extend({
932
933 init : function() {
934 this.ne.addEvent('selected',this.removePane.closure(this)).addEvent('blur',this.removePane.closure(this));
935 },
936
937 mouseClick : function() {
938 if(!this.isDisabled) {
939 if(this.pane && this.pane.pane) {
940 this.removePane();
941 } else {
942 this.pane = new nicEditorPane(this.contain,this.ne,{width : (this.width || '270px'), backgroundColor : '#fff'},this);
943 this.addPane();
944 this.ne.selectedInstance.saveRng();
945 }
946 }
947 },
948
949 addForm : function(f,elm) {
950 this.form = new bkElement('form').addEvent('submit',this.submit.closureListener(this));
951 this.pane.append(this.form);
952 this.inputs = {};
953
954 for(itm in f) {
955 var field = f[itm];
956 var val = '';
957 if(elm) {
958 val = elm.getAttribute(itm);
959 }
960 if(!val) {
961 val = field['value'] || '';
962 }
963 var type = f[itm].type;
964
965 if(type == 'title') {
966 new bkElement('div').setContent(field.txt).setStyle({fontSize : '14px', fontWeight: 'bold', padding : '0px', margin : '2px 0'}).appendTo(this.form);
967 } else {
968 var contain = new bkElement('div').setStyle({overflow : 'hidden', clear : 'both'}).appendTo(this.form);
969 if(field.txt) {
970 new bkElement('label').setAttributes({'for' : itm}).setContent(field.txt).setStyle({margin : '2px 4px', fontSize : '13px', width: '50px', lineHeight : '20px', textAlign : 'right', 'float' : 'left'}).appendTo(contain);
971 }
972
973 switch(type) {
974 case 'text':
975 this.inputs[itm] = new bkElement('input').setAttributes({id : itm, 'value' : val, 'type' : 'text'}).setStyle({margin : '2px 0', fontSize : '13px', 'float' : 'left', height : '20px', border : '1px solid #ccc', overflow : 'hidden'}).setStyle(field.style).appendTo(contain);
976 break;
977 case 'select':
978 this.inputs[itm] = new bkElement('select').setAttributes({id : itm}).setStyle({border : '1px solid #ccc', 'float' : 'left', margin : '2px 0'}).appendTo(contain);
979 for(opt in field.options) {
980 var o = new bkElement('option').setAttributes({value : opt, selected : (opt == val) ? 'selected' : ''}).setContent(field.options[opt]).appendTo(this.inputs[itm]);
981 }
982 break;
983 case 'content':
984 this.inputs[itm] = new bkElement('textarea').setAttributes({id : itm}).setStyle({border : '1px solid #ccc', 'float' : 'left'}).setStyle(field.style).appendTo(contain);
985 this.inputs[itm].value = val;
986 }
987 }
988 }
989 new bkElement('input').setAttributes({'type' : 'submit'}).setStyle({backgroundColor : '#efefef',border : '1px solid #ccc', margin : '3px 0', 'float' : 'left', 'clear' : 'both'}).appendTo(this.form);
990 this.form.onsubmit = bkLib.cancelEvent;
991 },
992
993 submit : function() { },
994
995 findElm : function(tag,attr,val) {
996 var list = this.ne.selectedInstance.getElm().getElementsByTagName(tag);
997 for(var i=0;i<list.length;i++) {
998 if(list[i].getAttribute(attr) == val) {
999 return $BK(list[i]);
1000 }
1001 }
1002 },
1003
1004 removePane : function() {
1005 if(this.pane) {
1006 this.pane.remove();
1007 this.pane = null;
1008 this.ne.selectedInstance.restoreRng();
1009 }
1010 }
1011});
1012
1013
1014var nicButtonTips = bkClass.extend({
1015 construct : function(nicEditor) {
1016 this.ne = nicEditor;
1017 nicEditor.addEvent('buttonOver',this.show.closure(this)).addEvent('buttonOut',this.hide.closure(this));
1018
1019 },
1020
1021 show : function(button) {
1022 this.timer = setTimeout(this.create.closure(this,button),400);
1023 },
1024
1025 create : function(button) {
1026 this.timer = null;
1027 if(!this.pane) {
1028 this.pane = new nicEditorPane(button.button,this.ne,{fontSize : '12px', marginTop : '5px'});
1029 this.pane.setContent(button.options.name);
1030 }
1031 },
1032
1033 hide : function(button) {
1034 if(this.timer) {
1035 clearTimeout(this.timer);
1036 }
1037 if(this.pane) {
1038 this.pane = this.pane.remove();
1039 }
1040 }
1041});
1042nicEditors.registerPlugin(nicButtonTips);
1043
1044
1045
1046 /* START CONFIG */
1047var nicSelectOptions = {
1048 buttons : {
1049 'fontSize' : {name : __('Select Font Size'), type : 'nicEditorFontSizeSelect', command : 'fontsize'},
1050 'fontFamily' : {name : __('Select Font Family'), type : 'nicEditorFontFamilySelect', command : 'fontname'},
1051 'fontFormat' : {name : __('Select Font Format'), type : 'nicEditorFontFormatSelect', command : 'formatBlock'}
1052 }
1053};
1054/* END CONFIG */
1055var nicEditorSelect = bkClass.extend({
1056
1057 construct : function(e,buttonName,options,nicEditor) {
1058 this.options = options.buttons[buttonName];
1059 this.elm = e;
1060 this.ne = nicEditor;
1061 this.name = buttonName;
1062 this.selOptions = new Array();
1063
1064 this.margin = new bkElement('div').setStyle({'float' : 'left', margin : '2px 1px 0 1px'}).appendTo(this.elm);
1065 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);
1066 this.items = new bkElement('div').setStyle({overflow : 'hidden', zoom : 1, border: '1px solid #ccc', paddingLeft : '3px', backgroundColor : '#fff'}).appendTo(this.contain);
1067 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);
1068 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);
1069
1070 if(!window.opera) {
1071 this.contain.onmousedown = this.control.onmousedown = this.txt.onmousedown = bkLib.cancelEvent;
1072 }
1073
1074 this.margin.noSelect();
1075
1076 this.ne.addEvent('selected', this.enable.closure(this)).addEvent('blur', this.disable.closure(this));
1077
1078 this.disable();
1079 this.init();
1080 },
1081
1082 disable : function() {
1083 this.isDisabled = true;
1084 this.close();
1085 this.contain.setStyle({opacity : 0.6});
1086 },
1087
1088 enable : function(t) {
1089 this.isDisabled = false;
1090 this.close();
1091 this.contain.setStyle({opacity : 1});
1092 },
1093
1094 setDisplay : function(txt) {
1095 this.txt.setContent(txt);
1096 },
1097
1098 toggle : function() {
1099 if(!this.isDisabled) {
1100 (this.pane) ? this.close() : this.open();
1101 }
1102 },
1103
1104 open : function() {
1105 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'});
1106
1107 for(var i=0;i<this.selOptions.length;i++) {
1108 var opt = this.selOptions[i];
1109 var itmContain = new bkElement('div').setStyle({overflow : 'hidden', borderBottom : '1px solid #ccc', width: '88px', textAlign : 'left', overflow : 'hidden', cursor : 'pointer'});
1110 var itm = new bkElement('div').setStyle({padding : '0px 4px'}).setContent(opt[1]).appendTo(itmContain).noSelect();
1111 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]);
1112 this.pane.append(itmContain);
1113 if(!window.opera) {
1114 itm.onmousedown = bkLib.cancelEvent;
1115 }
1116 }
1117 },
1118
1119 close : function() {
1120 if(this.pane) {
1121 this.pane = this.pane.remove();
1122 }
1123 },
1124
1125 over : function(opt) {
1126 opt.setStyle({backgroundColor : '#ccc'});
1127 },
1128
1129 out : function(opt) {
1130 opt.setStyle({backgroundColor : '#fff'});
1131 },
1132
1133
1134 add : function(k,v) {
1135 this.selOptions.push(new Array(k,v));
1136 },
1137
1138 update : function(elm) {
1139 this.ne.nicCommand(this.options.command,elm);
1140 this.close();
1141 }
1142});
1143
1144var nicEditorFontSizeSelect = nicEditorSelect.extend({
1145 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)'},
1146 init : function() {
1147 this.setDisplay('Font&nbsp;Size...');
1148 for(itm in this.sel) {
1149 this.add(itm,'<font size="'+itm+'">'+this.sel[itm]+'</font>');
1150 }
1151 }
1152});
1153
1154var nicEditorFontFamilySelect = nicEditorSelect.extend({
1155 sel : {'arial' : 'Arial','comic sans ms' : 'Comic Sans','courier new' : 'Courier New','georgia' : 'Georgia', 'helvetica' : 'Helvetica', 'impact' : 'Impact', 'times new roman' : 'Times', 'trebuchet ms' : 'Trebuchet', 'verdana' : 'Verdana'},
1156
1157 init : function() {
1158 this.setDisplay('Font&nbsp;Family...');
1159 for(itm in this.sel) {
1160 this.add(itm,'<font face="'+itm+'">'+this.sel[itm]+'</font>');
1161 }
1162 }
1163});
1164
1165var nicEditorFontFormatSelect = nicEditorSelect.extend({
1166 /** original selection up to 6*/
1167 // sel : {'p' : 'Paragraph', 'pre' : 'Pre', 'h1' : '1 Heading ', 'h2' : '2 Heading', 'h3' : '3 Heading', 'h4' : '4 Heading', 'h5' : '5 Heading', 'p6' : '6 Heading'},
1168 sel : {'p' : 'Paragraph', 'pre' : 'Pre', 'h1' : '1 Heading ', 'h2' : '2 Heading', 'h3' : '3 Heading', 'h4' : '4 Heading'},
1169 init : function() {
1170 this.setDisplay('Font&nbsp;Format...');
1171 for(itm in this.sel) {
1172 var tag = itm.toUpperCase();
1173 this.add('<'+tag+'>',this.sel[itm]);
1174 }
1175 }
1176});
1177
1178nicEditors.registerPlugin(nicPlugin,nicSelectOptions);
1179
1180
1181
1182/* START CONFIG */
1183var nicLinkOptions = {
1184 buttons : {
1185 'link' : {name : 'Add Link', type : 'nicLinkButton', tags : ['A']},
1186 'unlink' : {name : 'Remove Link', command : 'unlink', noActive : true}
1187 }
1188};
1189/* END CONFIG */
1190
1191var nicLinkButton = nicEditorAdvancedButton.extend({
1192 addPane : function() {
1193 this.ln = this.ne.selectedInstance.selElm().parentTag('A');
1194 this.addForm({
1195 '' : {type : 'title', txt : 'Add/Edit Link'},
1196 'href' : {type : 'text', txt : 'URL', value : 'http://', style : {width: '150px'}},
1197 'title' : {type : 'text', txt : 'Title'},
1198 'target' : {type : 'select', txt : 'Open In', options : {'' : 'Current Window', '_blank' : 'New Window'},style : {width : '100px'}}
1199 },this.ln);
1200 },
1201
1202 submit: function(e) {
1203 var url = this.inputs['href'].value;
1204 if (url === "http://" || url === "") {
1205 alert("You must enter a URL to Create a Link");
1206 return false;
1207 }
1208 this.removePane();
1209
1210 if (!this.ln) {
1211 var tmp = 'javascript:nicTemp();';
1212 this.ne.nicCommand("createlink", tmp);
1213 this.ln = this.findElm('A', 'href', tmp);
1214 // set the link text to the title or the url if there is no text selected
1215 if (this.ln.innerHTML == tmp) {
1216 this.ln.innerHTML = this.inputs['title'].value || url;
1217 }
1218 }
1219 if (this.ln) {
1220 var oldTitle = this.ln.title;
1221 this.ln.setAttributes({
1222 href: this.inputs['href'].value,
1223 title: this.inputs['title'].value,
1224 target: this.inputs['target'].options[this.inputs['target'].selectedIndex].value
1225 });
1226 // set the link text to the title or the url if the old text was the old title
1227 if (this.ln.innerHTML == oldTitle) {
1228 this.ln.innerHTML = this.inputs['title'].value || this.inputs['href'].value;
1229 }
1230 }
1231 }
1232});
1233
1234nicEditors.registerPlugin(nicPlugin,nicLinkOptions);
1235
1236
1237
1238/* START CONFIG */
1239var nicColorOptions = {
1240 buttons : {
1241 'forecolor' : {name : __('Change Text Color'), type : 'nicEditorColorButton', noClose : true},
1242 'bgcolor' : {name : __('Change Background Color'), type : 'nicEditorBgColorButton', noClose : true}
1243 }
1244};
1245/* END CONFIG */
1246
1247var nicEditorColorButton = nicEditorAdvancedButton.extend({
1248 addPane : function() {
1249
1250 var colorItems = new bkElement('DIV').setStyle({width: '270px'});
1251 const aColorCode=['000000','808080','C0C0C0','800000','FFFFFF','FF0000','FFB6C1','ff8c00','800080','FF00FF','008000','00FF00','808000','FFFF00','000080','0000FF','008080','00FFFF'];
1252
1253 for ( let x=0;x<aColorCode.length;x++) {
1254
1255 let colorCode='#'+aColorCode[x];
1256 var colorSquare = new bkElement('DIV').setStyle({'cursor' : 'pointer', 'height' : '30px', 'float' : 'left'}).appendTo(colorItems);
1257 var colorBorder = new bkElement('DIV').setStyle({border: '2px solid '+colorCode}).appendTo(colorSquare);
1258 var colorInner = new bkElement('DIV').setStyle({backgroundColor : colorCode, overflow : 'hidden', width : '26px', height : '26px'}).addEvent('click',this.colorSelect.closure(this,colorCode)).addEvent('mouseover',this.on.closure(this,colorBorder)).addEvent('mouseout',this.off.closure(this,colorBorder,colorCode)).appendTo(colorBorder);
1259
1260 if(!window.opera) {
1261 colorSquare.onmousedown = colorInner.onmousedown = bkLib.cancelEvent;
1262 }
1263 }
1264 this.pane.append(colorItems.noSelect());
1265 },
1266
1267 colorSelect : function(c) {
1268 this.ne.nicCommand('foreColor',c);
1269 this.removePane();
1270 },
1271
1272 on : function(colorBorder) {
1273 colorBorder.setStyle({border : '2px solid #000'});
1274 },
1275
1276 off : function(colorBorder,colorCode) {
1277 colorBorder.setStyle({border : '2px solid '+colorCode});
1278 }
1279});
1280
1281var nicEditorBgColorButton = nicEditorColorButton.extend({
1282 colorSelect : function(c) {
1283 this.ne.nicCommand('hiliteColor',c);
1284 this.removePane();
1285 }
1286});
1287
1288nicEditors.registerPlugin(nicPlugin,nicColorOptions);
1289
1290
1291
1292/* START CONFIG */
1293var nicImageOptions = {
1294 buttons : {
1295 'image' : {name : 'Add Image', type : 'nicImageButton', tags : ['IMG']}
1296 }
1297
1298};
1299/* END CONFIG */
1300
1301var nicImageButton = nicEditorAdvancedButton.extend({
1302 addPane : function() {
1303 this.im = this.ne.selectedInstance.selElm().parentTag('IMG');
1304 this.addForm({
1305 '' : {type : 'title', txt : 'Add/Edit Image'},
1306 'src' : {type : 'text', txt : 'URL', 'value' : 'http://', style : {width: '150px'}},
1307 'alt' : {type : 'text', txt : 'Alt Text', style : {width: '100px'}},
1308 'align' : {type : 'select', txt : 'Align', options : {none : 'Default','left' : 'Left', 'right' : 'Right'}}
1309 },this.im);
1310 },
1311
1312 submit : function(e) {
1313 var src = this.inputs['src'].value;
1314 if(src == "" || src == "http://") {
1315 alert("You must enter a Image URL to insert");
1316 return false;
1317 }
1318 this.removePane();
1319
1320 if(!this.im) {
1321 var tmp = 'javascript:nicImTemp();';
1322 this.ne.nicCommand("insertImage",tmp);
1323 this.im = this.findElm('IMG','src',tmp);
1324 }
1325 if(this.im) {
1326 this.im.setAttributes({
1327 src : this.inputs['src'].value,
1328 alt : this.inputs['alt'].value,
1329 align : this.inputs['align'].value
1330 });
1331 }
1332 }
1333});
1334
1335nicEditors.registerPlugin(nicPlugin,nicImageOptions);
1336
1337
1338
1339
1340/* START CONFIG */
1341var nicSaveOptions = {
1342 buttons : {
1343 'save' : {name : __('Save this content'), type : 'nicEditorSaveButton'}
1344 }
1345};
1346/* END CONFIG */
1347
1348var nicEditorSaveButton = nicEditorButton.extend({
1349 init : function() {
1350 if(!this.ne.options.onSave) {
1351 this.margin.setStyle({'display' : 'none'});
1352 }
1353 },
1354 mouseClick : function() {
1355 var onSave = this.ne.options.onSave;
1356 var selectedInstance = this.ne.selectedInstance;
1357 onSave(selectedInstance.getContent(), selectedInstance.elm.id, selectedInstance);
1358 }
1359});
1360
1361nicEditors.registerPlugin(nicPlugin,nicSaveOptions);
1362
1363
1364
1365/* START CONFIG */
1366var nicUploadOptions = {
1367 buttons : {
1368 'upload' : {name : 'Upload Image', type : 'nicUploadButton'}
1369 }
1370
1371};
1372/* END CONFIG */
1373
1374var nicUploadButton = nicEditorAdvancedButton.extend({
1375 nicURI : 'https://api.imgur.com/3/image',
1376 errorText : 'Failed to upload image',
1377
1378 addPane : function() {
1379 if(typeof window.FormData === "undefined") {
1380 return this.onError("Image uploads are not supported in this browser, use Chrome, Firefox, or Safari instead.");
1381 }
1382 this.im = this.ne.selectedInstance.selElm().parentTag('IMG');
1383
1384 var container = new bkElement('div')
1385 .setStyle({ padding: '10px' })
1386 .appendTo(this.pane.pane);
1387
1388 new bkElement('div')
1389 .setStyle({ fontSize: '14px', fontWeight : 'bold', paddingBottom: '5px' })
1390 .setContent('Insert an Image')
1391 .appendTo(container);
1392
1393 this.fileInput = new bkElement('input')
1394 .setAttributes({ 'type' : 'file' })
1395 .appendTo(container);
1396
1397 this.progress = new bkElement('progress')
1398 .setStyle({ width : '100%', display: 'none' })
1399 .setAttributes('max', 100)
1400 .appendTo(container);
1401
1402 this.fileInput.onchange = this.uploadFile.closure(this);
1403 },
1404
1405 onError : function(msg) {
1406 this.removePane();
1407 alert(msg || "Failed to upload image");
1408 },
1409
1410 uploadFile : function() {
1411 var file = this.fileInput.files[0];
1412 if (!file || !file.type.match(/image.*/)) {
1413 this.onError("Only image files can be uploaded");
1414 return;
1415 }
1416 this.fileInput.setStyle({ display: 'none' });
1417 this.setProgress(0);
1418
1419 var fd = new FormData(); // https://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/
1420 fd.append("image", file);
1421
1422 var xhr = new XMLHttpRequest();
1423 xhr.open("POST", this.ne.options.uploadURI || this.nicURI);
1424
1425 xhr.onload = function() {
1426 try {
1427 var data = JSON.parse(xhr.responseText).data;
1428 } catch(e) {
1429 return this.onError();
1430 }
1431 if(data.error) {
1432 return this.onError(data.error);
1433 }
1434 this.onUploaded(data);
1435 }.closure(this);
1436 xhr.onerror = this.onError.closure(this);
1437 xhr.upload.onprogress = function(e) {
1438 this.setProgress(e.loaded / e.total);
1439 }.closure(this);
1440 xhr.setRequestHeader('Authorization', 'Client-ID c37fc05199a05b7');
1441 xhr.send(fd);
1442 },
1443
1444 setProgress : function(percent) {
1445 this.progress.setStyle({ display: 'block' });
1446 if(percent < .98) {
1447 this.progress.value = percent;
1448 } else {
1449 this.progress.removeAttribute('value');
1450 }
1451 },
1452
1453 onUploaded : function(options) {
1454 this.removePane();
1455 var src = options.link;
1456 if(!this.im) {
1457 this.ne.selectedInstance.restoreRng();
1458 var tmp = 'javascript:nicImTemp();';
1459 this.ne.nicCommand("insertImage", src);
1460 this.im = this.findElm('IMG','src', src);
1461 }
1462 var w = parseInt(this.ne.selectedInstance.elm.getStyle('width'));
1463 if(this.im) {
1464 this.im.setAttributes({
1465 src : src,
1466 width : (w && options.width) ? Math.min(w, options.width) : ''
1467 });
1468 }
1469 }
1470});
1471
1472nicEditors.registerPlugin(nicPlugin,nicUploadOptions);
1473
1474
1475
1476var nicXHTML = bkClass.extend({
1477 stripAttributes : ['_moz_dirty','_moz_resizing','_extended'],
1478 noShort : ['style','title','script','textarea','a'],
1479 cssReplace : {'font-weight:bold;' : 'strong', 'font-style:italic;' : 'em'},
1480 sizes : {1 : 'xx-small', 2 : 'x-small', 3 : 'small', 4 : 'medium', 5 : 'large', 6 : 'x-large'},
1481
1482 construct : function(nicEditor) {
1483 this.ne = nicEditor;
1484 if(this.ne.options.xhtml) {
1485 nicEditor.addEvent('get',this.cleanup.closure(this));
1486 }
1487 },
1488
1489 cleanup : function(ni) {
1490 var node = ni.getElm();
1491 var xhtml = this.toXHTML(node);
1492 ni.content = xhtml;
1493 },
1494
1495 toXHTML : function(n,r,d) {
1496 var txt = '';
1497 var attrTxt = '';
1498 var cssTxt = '';
1499 var nType = n.nodeType;
1500 var nName = n.nodeName.toLowerCase();
1501 var nChild = n.hasChildNodes && n.hasChildNodes();
1502 var extraNodes = new Array();
1503
1504 switch(nType) {
1505 case 1:
1506 var nAttributes = n.attributes;
1507
1508 switch(nName) {
1509 case 'b':
1510 nName = 'strong';
1511 break;
1512 case 'i':
1513 nName = 'em';
1514 break;
1515 case 'font':
1516 nName = 'span';
1517 break;
1518 }
1519
1520 if(r) {
1521 for(var i=0;i<nAttributes.length;i++) {
1522 var attr = nAttributes[i];
1523
1524 var attributeName = attr.nodeName.toLowerCase();
1525 var attributeValue = attr.nodeValue;
1526
1527 if(!attr.specified || !attributeValue || bkLib.inArray(this.stripAttributes,attributeName) || typeof(attributeValue) == "function") {
1528 continue;
1529 }
1530
1531 switch(attributeName) {
1532 case 'style':
1533 var css = attributeValue.replace(/ /g,"");
1534 for(itm in this.cssReplace) {
1535 if(css.indexOf(itm) != -1) {
1536 extraNodes.push(this.cssReplace[itm]);
1537 css = css.replace(itm,'');
1538 }
1539 }
1540 cssTxt += css;
1541 attributeValue = "";
1542 break;
1543 case 'class':
1544 attributeValue = attributeValue.replace("Apple-style-span","");
1545 break;
1546 case 'size':
1547 cssTxt += "font-size:"+this.sizes[attributeValue]+';';
1548 attributeValue = "";
1549 break;
1550 }
1551
1552 if(attributeValue) {
1553 attrTxt += ' '+attributeName+'="'+attributeValue+'"';
1554 }
1555 }
1556
1557 if(cssTxt) {
1558 attrTxt += ' style="'+cssTxt+'"';
1559 }
1560
1561 for(var i=0;i<extraNodes.length;i++) {
1562 txt += '<'+extraNodes[i]+'>';
1563 }
1564
1565 if(attrTxt == "" && nName == "span") {
1566 r = false;
1567 }
1568 if(r) {
1569 txt += '<'+nName;
1570 if(nName != 'br') {
1571 txt += attrTxt;
1572 }
1573 }
1574 }
1575
1576
1577
1578 if(!nChild && !bkLib.inArray(this.noShort,attributeName)) {
1579 if(r) {
1580 txt += ' />';
1581 }
1582 } else {
1583 if(r) {
1584 txt += '>';
1585 }
1586
1587 for(var i=0;i<n.childNodes.length;i++) {
1588 var results = this.toXHTML(n.childNodes[i],true,true);
1589 if(results) {
1590 txt += results;
1591 }
1592 }
1593 }
1594
1595 if(r && nChild) {
1596 txt += '</'+nName+'>';
1597 }
1598
1599 for(var i=0;i<extraNodes.length;i++) {
1600 txt += '</'+extraNodes[i]+'>';
1601 }
1602
1603 break;
1604 case 3:
1605 //if(n.nodeValue != '\n') {
1606 txt += n.nodeValue;
1607 //}
1608 break;
1609 }
1610
1611 return txt;
1612 }
1613});
1614nicEditors.registerPlugin(nicXHTML);
1615
1616
1617
1618var nicBBCode = bkClass.extend({
1619 construct : function(nicEditor) {
1620 this.ne = nicEditor;
1621 if(this.ne.options.bbCode) {
1622 nicEditor.addEvent('get',this.bbGet.closure(this));
1623 nicEditor.addEvent('set',this.bbSet.closure(this));
1624
1625 var loadedPlugins = this.ne.loadedPlugins;
1626 for(itm in loadedPlugins) {
1627 if(loadedPlugins[itm].toXHTML) {
1628 this.xhtml = loadedPlugins[itm];
1629 }
1630 }
1631 }
1632 },
1633
1634 bbGet : function(ni) {
1635 var xhtml = this.xhtml.toXHTML(ni.getElm());
1636 ni.content = this.toBBCode(xhtml);
1637 },
1638
1639 bbSet : function(ni) {
1640 ni.content = this.fromBBCode(ni.content);
1641 },
1642
1643 toBBCode : function(xhtml) {
1644 function rp(r,m) {
1645 xhtml = xhtml.replace(r,m);
1646 }
1647
1648 rp(/\n/gi,"");
1649 rp(/<strong>(.*?)<\/strong>/gi,"[b]$1[/b]");
1650 rp(/<em>(.*?)<\/em>/gi,"[i]$1[/i]");
1651 rp(/<span.*?style="text-decoration:underline;">(.*?)<\/span>/gi,"[u]$1[/u]");
1652 rp(/<ul>(.*?)<\/ul>/gi,"[list]$1[/list]");
1653 rp(/<li>(.*?)<\/li>/gi,"[*]$1[/*]");
1654 rp(/<ol>(.*?)<\/ol>/gi,"[list=1]$1[/list]");
1655 rp(/<img.*?src="(.*?)".*?>/gi,"[img]$1[/img]");
1656 rp(/<a.*?href="(.*?)".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]");
1657 rp(/<br.*?>/gi,"\n");
1658 rp(/<.*?>.*?<\/.*?>/gi,"");
1659
1660 return xhtml;
1661 },
1662
1663 fromBBCode : function(bbCode) {
1664 function rp(r,m) {
1665 bbCode = bbCode.replace(r,m);
1666 }
1667
1668 rp(/\[b\](.*?)\[\/b\]/gi,"<strong>$1</strong>");
1669 rp(/\[i\](.*?)\[\/i\]/gi,"<em>$1</em>");
1670 rp(/\[u\](.*?)\[\/u\]/gi,"<span style=\"text-decoration:underline;\">$1</span>");
1671 rp(/\[list\](.*?)\[\/list\]/gi,"<ul>$1</ul>");
1672 rp(/\[list=1\](.*?)\[\/list\]/gi,"<ol>$1</ol>");
1673 rp(/\[\*\](.*?)\[\/\*\]/gi,"<li>$1</li>");
1674 rp(/\[img\](.*?)\[\/img\]/gi,"<img src=\"$1\" />");
1675 rp(/\[url=(.*?)\](.*?)\[\/url\]/gi,"<a href=\"$1\">$2</a>");
1676 rp(/\n/gi,"<br />");
1677 //rp(/\[.*?\](.*?)\[\/.*?\]/gi,"$1");
1678
1679 return bbCode;
1680 }
1681
1682
1683});
1684nicEditors.registerPlugin(nicBBCode);
1685
1686
1687
1688nicEditor = nicEditor.extend({
1689 floatingPanel : function() {
1690 this.floating = new bkElement('DIV').setStyle({position: 'absolute', top : '-1000px'}).appendTo(document.body);
1691 this.addEvent('focus', this.reposition.closure(this)).addEvent('blur', this.hide.closure(this));
1692 this.setPanel(this.floating);
1693 },
1694
1695 reposition : function() {
1696 var e = this.selectedInstance.e;
1697 this.floating.setStyle({ width : (parseInt(e.getStyle('width')) || e.clientWidth)+'px' });
1698 var top = e.offsetTop-this.floating.offsetHeight;
1699 if(top < 0) {
1700 top = e.offsetTop+e.offsetHeight;
1701 }
1702
1703 this.floating.setStyle({ top : top+'px', left : e.offsetLeft+'px', display : 'block' });
1704 },
1705
1706 hide : function() {
1707 this.floating.setStyle({ top : '-1000px'});
1708 }
1709});
1710
1711
1712
1713/* START CONFIG */
1714var nicCodeOptions = {
1715 buttons : {
1716 'xhtml' : {name : 'Edit HTML', type : 'nicCodeButton'}
1717 }
1718
1719};
1720/* END CONFIG */
1721
1722var nicCodeButton = nicEditorAdvancedButton.extend({
1723 width : '350px',
1724
1725 addPane : function() {
1726 this.addForm({
1727 '' : {type : 'title', txt : 'Edit HTML'},
1728 'code' : {type : 'content', 'value' : this.ne.selectedInstance.getContent(), style : {width: '340px', height : '200px'}}
1729 });
1730 },
1731
1732 submit : function(e) {
1733 var code = this.inputs['code'].value;
1734 this.ne.selectedInstance.setContent(code);
1735 this.removePane();
1736 }
1737});
1738
1739nicEditors.registerPlugin(nicPlugin,nicCodeOptions);
1740
1741