12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741 |
- /**
- * SCEditor v1.3.4
- * http://www.samclarke.com/2011/07/sceditor/
- *
- * Copyright (C) 2011-2012, Sam Clarke (samclarke.com)
- *
- * SCEditor is licensed under the MIT license:
- * http://www.opensource.org/licenses/mit-license.php
- */
- // ==ClosureCompiler==
- // @output_file_name jquery.sceditor.min.js
- // @compilation_level SIMPLE_OPTIMIZATIONS
- // ==/ClosureCompiler==
- /*jshint smarttabs: true, scripturl: true, jquery: true, devel:true, eqnull:true, curly: false */
- /*global XMLSerializer: true*/
- (function ($) {
- 'use strict';
- $.sceditor = function (el, options) {
- var base = this;
- /**
- * The textarea element being replaced
- * @private
- */
- var $textarea = $(el);
- var textarea = el;
- /**
- * The div which contains the editor and toolbar
- * @private
- */
- var editorContainer = null;
- /**
- * The editors toolbar
- * @private
- */
- var $toolbar = null;
- /**
- * The editors iframe which should be in design mode
- * @private
- */
- var $wysiwygEditor = null;
- var wysiwygEditor = null;
- /**
- * The editors textarea for viewing source
- * @private
- */
- var $textEditor = null;
- var textEditor = null;
- /**
- * The current dropdown
- * @private
- */
- var $dropdown = null;
- var dropdownIgnoreLastClick = false;
- /**
- * Array of all the commands key press functions
- * @private
- */
- var keyPressFuncs = [];
- /**
- * Store the last cursor position. Needed for IE because it forgets
- * @private
- */
- var lastRange = null;
-
- /**
- * The editors locale
- * @private
- */
- var locale = null;
- /**
- * Stores a cache of preloaded images
- * @private
- */
- var preLoadCache = [];
-
- var rangeHelper = null;
- var init,
- replaceEmoticons,
- handleCommand,
- saveRange,
- handlePasteEvt,
- handlePasteData,
- handleKeyPress,
- handleKeyUp,
- handleMouseDown,
- initEditor,
- initToolBar,
- initKeyPressFuncs,
- initResize,
- documentClickHandler,
- formSubmitHandler,
- preLoadEmoticons,
- getWysiwygDoc,
- handleWindowResize,
- setHeight,
- setWidth,
- initLocale;
- /**
- * All the commands supported by the editor
- */
- base.commands = $.extend({}, (options.commands || $.sceditor.commands));
- /**
- * Initializer. Creates the editor iframe and textarea
- * @private
- */
- init = function () {
- $textarea.data("sceditor", base);
- base.options = $.extend({}, $.sceditor.defaultOptions, options);
- // Load locale
- if(base.options.locale !== null && base.options.locale !== "en")
- initLocale();
-
- if(base.options.height !== null)
- $textarea.height(base.options.height);
- if(base.options.width !== null)
- $textarea.width(base.options.width);
- // if either width or height are % based, add the resize handler to update the editor
- // when the window is resized
- if((base.options.height !== null && base.options.height.toString().indexOf("%") > -1) ||
- (base.options.width !== null && base.options.width.toString().indexOf("%") > -1))
- $(window).resize(handleWindowResize);
- editorContainer = $('<div class="sceditor-container" />')
- .width($textarea.outerWidth())
- .height($textarea.outerHeight());
- $textarea.after(editorContainer);
- // create the editor
- initToolBar();
- initEditor();
- initKeyPressFuncs();
- if(base.options.resizeEnabled)
- initResize();
- $(document).click(documentClickHandler);
- (textarea.form ? $(textarea.form) : $textarea.parents("form"))
- .attr('novalidate','novalidate')
- .submit(formSubmitHandler);
-
- // prefix emoticon root to emoticon urls
- if(base.options.emoticonsRoot && base.options.emoticons)
- {
- $.each(base.options.emoticons, function (idx, emoticons) {
- $.each(emoticons, function (key, url) {
- base.options.emoticons[idx][key] = base.options.emoticonsRoot + url;
- });
- });
- }
- // load any textarea value into the editor
- var val = $textarea.hide().val();
- // Pass the value though the getTextHandler if it is set so that
- // BBCode, ect. can be converted
- if(base.options.getTextHandler && base.options.supportedWysiwyg)
- {
- val = base.options.getTextHandler(val);
- base.setWysiwygEditorValue(val);
- }
- else
- {
- base.toggleTextMode();
- base.setTextareaValue(val);
- }
- if(base.options.toolbar.indexOf('emoticon') !== -1)
- preLoadEmoticons();
- };
- /**
- * Creates the editor iframe and textarea
- * @private
- */
- initEditor = function () {
- var contentEditable = $('<div contenteditable="true">')[0].contentEditable,
- contentEditableSupported = typeof contentEditable !== 'undefined' && contentEditable !== 'inherit',
- $doc, $body;
- $textEditor = $('<textarea></textarea>').hide();
- $wysiwygEditor = $('<iframe frameborder="0"></iframe>');
- if(window.location.protocol === "https:")
- $wysiwygEditor.attr("src", "javascript:false");
- // add the editor to the HTML and store the editors element
- editorContainer.append($wysiwygEditor).append($textEditor);
- wysiwygEditor = $wysiwygEditor[0];
- textEditor = $textEditor[0];
- setWidth($textarea.width());
- setHeight($textarea.height());
- // turn on design mode if contenteditable not supported
- if(!contentEditableSupported)
- getWysiwygDoc().designMode = 'On';
-
- getWysiwygDoc().open();
- getWysiwygDoc().write(
- '<html><head><!--[if gte IE 9]><style>* {min-height: auto !important}</style><![endif]-->' +
- '<meta http-equiv="Content-Type" content="text/html;charset=' + base.options.charset + '" />' +
- '<link rel="stylesheet" type="text/css" href="' + base.options.style + '" />' +
- '</head><body contenteditable="true"></body></html>'
- );
- getWysiwygDoc().close();
-
- // turn on design mode if contenteditable not supported
- if(!contentEditableSupported)
- getWysiwygDoc().designMode = 'On';
- $doc = $(getWysiwygDoc());
- $body = $doc.find("body");
- // set the key press event
- $body.keypress(handleKeyPress);
- $body.keyup(handleKeyUp);
- $doc.keypress(handleKeyPress);
- $doc.keyup(handleKeyUp);
- $doc.mousedown(handleMouseDown);
- $doc.bind("beforedeactivate keyup", saveRange);
- $doc.focus(function() {
- lastRange = null;
- });
-
- if(base.options.enablePasteFiltering)
- $body.bind("paste", handlePasteEvt);
- rangeHelper = new $.sceditor.rangeHelper(wysiwygEditor.contentWindow);
- };
- /**
- * Creates the toolbar and appends it to the container
- * @private
- */
- initToolBar = function () {
- var buttonClick = function (e) {
- handleCommand($(this), base.commands[$(this).data("sceditor-command")]);
- e.preventDefault();
- };
- $toolbar = $('<div class="sceditor-toolbar" />');
- var rows = base.options.toolbar.split("||");
- for (var r=0; r < rows.length; r++) {
- var row = $('<div class="sceditor-row" />');
- var groups = rows[r].split("|"),
- group, buttons, accessibilityName, button, i;
- for (i=0; i < groups.length; i++) {
- group = $('<div class="sceditor-group" />');
- buttons = groups[i].split(",");
- for (var x=0; x < buttons.length; x++) {
- // the button must be a valid command otherwise ignore it
- if(!base.commands.hasOwnProperty(buttons[x]))
- continue;
- accessibilityName = base.commands[buttons[x]].tooltip ? base._(base.commands[buttons[x]].tooltip) : buttons[x];
-
- button = $('<a class="sceditor-button sceditor-button-' + buttons[x] +
- ' " unselectable="on"><div unselectable="on">' + accessibilityName + '</div></a>');
- if(base.commands[buttons[x]].hasOwnProperty("tooltip"))
- button.attr('title', base._(base.commands[buttons[x]].tooltip));
-
- if(base.commands[buttons[x]].exec)
- button.data('sceditor-wysiwygmode', true);
- else
- button.addClass('disabled');
-
- if(base.commands[buttons[x]].txtExec)
- button.data('sceditor-txtmode', true);
- // add the click handler for the button
- button.data("sceditor-command", buttons[x]);
- button.click(buttonClick);
- group.append(button);
- }
- row.append(group);
- }
- $toolbar.append(row);
- }
- // append the toolbar to the toolbarContainer option if given
- if(base.options.toolbarContainer === null)
- editorContainer.append($toolbar);
- else
- $(base.options.toolbarContainer).append($toolbar);
- };
- /**
- * Creates an array of all the key press functions
- * like emoticons, ect.
- * @private
- */
- initKeyPressFuncs = function () {
- $.each(base.commands, function (command, values) {
- if(typeof values.keyPress !== "undefined")
- keyPressFuncs.push(values.keyPress);
- });
- };
- setWidth = function (width) {
- editorContainer.width(width);
- // fix the height and width of the textarea/iframe
- $wysiwygEditor.width(width);
- $wysiwygEditor.width(width + (width - $wysiwygEditor.outerWidth(true)));
- $textEditor.width(width);
- $textEditor.width(width + (width - $textEditor.outerWidth(true)));
- };
- setHeight = function (height) {
- editorContainer.height(height);
- height = height - (base.options.toolbarContainer === null?$toolbar.outerHeight():0);
- // fix the height and width of the textarea/iframe
- $wysiwygEditor.height(height);
- $wysiwygEditor.height(height + (height - $wysiwygEditor.outerHeight(true)));
- $textEditor.height(height);
- $textEditor.height(height + (height - $textEditor.outerHeight(true)));
- };
- /**
- * Creates the resizer.
- * @private
- */
- initResize = function () {
- var $grip = $('<div class="sceditor-grip" />'),
- // cover is used to cover the editor iframe so document still gets mouse move events
- $cover = $('<div class="sceditor-resize-cover" />'),
- startX = 0,
- startY = 0,
- startWidth = 0,
- startHeight = 0,
- origWidth = editorContainer.width(),
- origHeight = editorContainer.height(),
- dragging = false,
- minHeight, maxHeight, minWidth, maxWidth, mouseMoveFunc;
- minHeight = (base.options.resizeMinHeight == null ?
- origHeight / 2 :
- base.options.resizeMinHeight);
- maxHeight = (base.options.resizeMaxHeight == null ?
- origHeight * 2 :
- base.options.resizeMaxHeight);
- minWidth = (base.options.resizeMinWidth == null ?
- origWidth / 2 :
- base.options.resizeMinWidth);
- maxWidth = (base.options.resizeMaxWidth == null ?
- origWidth * 2 :
- base.options.resizeMaxWidth);
- mouseMoveFunc = function (e) {
- var newHeight = startHeight + (e.pageY - startY),
- newWidth = startWidth + (e.pageX - startX);
- if (newWidth >= minWidth && (maxWidth < 0 || newWidth <= maxWidth))
- setWidth(newWidth);
- if (newHeight >= minHeight && (maxHeight < 0 || newHeight <= maxHeight))
- setHeight(newHeight);
- e.preventDefault();
- };
- editorContainer.append($grip);
- editorContainer.append($cover.hide());
- $grip.mousedown(function (e) {
- startX = e.pageX;
- startY = e.pageY;
- startWidth = editorContainer.width();
- startHeight = editorContainer.height();
- dragging = true;
- $cover.show();
- $(document).bind('mousemove', mouseMoveFunc);
- e.preventDefault();
- });
- $(document).mouseup(function (e) {
- if(!dragging)
- return;
- dragging = false;
- $cover.hide();
- $(document).unbind('mousemove', mouseMoveFunc);
- e.preventDefault();
- });
- };
-
- formSubmitHandler = function(e) {
- base.updateTextareaValue();
-
- $(this).removeAttr('novalidate');
-
- if(this.checkValidity && !this.checkValidity())
- e.preventDefault();
-
- $(this).attr('novalidate','novalidate');
- };
-
- /**
- * Destroys the editor, removing all elements and
- * event handlers.
- */
- base.destory = function () {
- $(document).unbind('click', documentClickHandler);
- $textarea.removeAttr('novalidate').unbind('submit', formSubmitHandler);
- $(window).unbind('resize', handleWindowResize);
-
- editorContainer.remove();
- editorContainer = null;
-
- $textarea.removeData("sceditor").show();
- };
- /**
- * Preloads the emoticon images
- * Idea from: http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript
- * @private
- */
- preLoadEmoticons = function () {
- var emoticons = $.extend({}, base.options.emoticons.more, base.options.emoticons.dropdown, base.options.emoticons.hidden),
- emoticon;
- $.each(emoticons, function (key, url) {
- if (key == '')
- emoticon = document.createElement('br');
- else
- {
- emoticon = document.createElement('img');
- emoticon.src = url;
- }
- preLoadCache.push(emoticon);
- });
- };
- /**
- * Creates a menu item drop down
- * @param HTMLElement menuItem The button to align the drop down with
- * @param string dropDownName Used for styling the dropown, will be a class sceditor-dropDownName
- * @param string content The HTML content of the dropdown
- * @param bool ieUnselectable If to add the unselectable attribute to all the contents elements. Stops
- * IE from deselecting the text in the editor
- */
- base.createDropDown = function (menuItem, dropDownName, content, ieUnselectable) {
- base.closeDropDown();
-
- // IE needs unselectable attr to stop it from unselecting the text in the editor.
- // The editor can cope if IE does unselect the text it's just not nice.
- if(ieUnselectable !== false) {
- content = $(content);
- content.find(':not(input,textarea)').filter(function() { return this.nodeType===1; }).attr('unselectable', 'on');
- }
-
- var o_css = {
- top: menuItem.offset().top,
- left: menuItem.offset().left
- };
- $.extend(o_css, base.options.dropDownCss);
- $dropdown = $('<div class="sceditor-dropdown sceditor-' + dropDownName + '" />').css(o_css).append(content);
- //editorContainer.after($dropdown);
- $dropdown.appendTo($('body'));
- dropdownIgnoreLastClick = true;
- // stop clicks within the dropdown from being handled
- $dropdown.click(function (e) {
- e.stopPropagation();
- });
- };
- /**
- * Handles any document click and closes the dropdown if open
- * @private
- */
- documentClickHandler = function (e) {
- // ignore right clicks
- if(!dropdownIgnoreLastClick && e.which !== 3)
- base.closeDropDown();
- dropdownIgnoreLastClick = false;
- };
-
- handlePasteEvt = function(e) {
- var elm = getWysiwygDoc().body,
- checkCount = 0,
- pastearea = elm.ownerDocument.createElement('div'),
- prePasteContent = elm.ownerDocument.createDocumentFragment();
- rangeHelper.saveRange();
- document.body.appendChild(pastearea);
- if (e && e.clipboardData && e.clipboardData.getData)
- {
- var html, handled=true;
-
- if ((html = e.clipboardData.getData('text/html')) || (html = e.clipboardData.getData('text/plain')))
- pastearea.innerHTML = html;
- else
- handled = false;
-
- if(handled)
- {
- handlePasteData(elm, pastearea);
-
- if (e.preventDefault)
- {
- e.stopPropagation();
- e.preventDefault();
- }
-
- return false;
- }
- }
-
- while(elm.firstChild)
- prePasteContent.appendChild(elm.firstChild);
-
- function handlePaste(elm, pastearea) {
- if (elm.childNodes.length > 0)
- {
- while(elm.firstChild)
- pastearea.appendChild(elm.firstChild);
-
- while(prePasteContent.firstChild)
- elm.appendChild(prePasteContent.firstChild);
-
- handlePasteData(elm, pastearea);
- }
- else
- {
- // Allow max 25 checks before giving up.
- // Needed inscase empty input is posted or
- // something gose wrong.
- if(checkCount > 25)
- {
- while(prePasteContent.firstChild)
- elm.appendChild(prePasteContent.firstChild);
-
- return;
- }
- ++checkCount;
- setTimeout(function () {
- handlePaste(elm, pastearea);
- }, 20);
- }
- }
- handlePaste(elm, pastearea);
-
- base.focus();
-
- return true;
- };
-
- /**
- * @param {Element} elm
- * @param {Element} pastearea
- */
- handlePasteData = function(elm, pastearea) {
- // fix any invalid nesting
- $.sceditor.dom.fixNesting(pastearea);
-
- var pasteddata = pastearea.innerHTML;
-
- if(base.options.getHtmlHandler)
- pasteddata = base.options.getHtmlHandler(pasteddata, $(pastearea));
- pastearea.parentNode.removeChild(pastearea);
- if(base.options.getTextHandler)
- pasteddata = base.options.getTextHandler(pasteddata, true);
- rangeHelper.restoreRange();
- rangeHelper.insertHTML(pasteddata);
- };
- /**
- * Closes the current drop down
- *
- * @param bool focus If to focus the editor on close
- */
- base.closeDropDown = function (focus) {
- if($dropdown !== null) {
- $dropdown.remove();
- $dropdown = null;
- }
-
- if(focus === true)
- base.focus();
- };
- /**
- * Gets the WYSIWYG editors document
- */
- getWysiwygDoc = function () {
- if (wysiwygEditor.contentDocument)
- return wysiwygEditor.contentDocument;
- if (wysiwygEditor.contentWindow && wysiwygEditor.contentWindow.document)
- return wysiwygEditor.contentWindow.document;
- if (wysiwygEditor.document)
- return wysiwygEditor.document;
- return null;
- };
- /**
- * Inserts HTML into WYSIWYG editor. If endHtml is defined and some text is selected the
- * selected text will be put inbetween html and endHtml. If endHtml isn't defined and some
- * text is selected it will be replaced by the HTML
- *
- * The HTML can have only one root node, if it has more than one only the first will be used.
- * e.g. with: <b>test</b><i>test2</i> only <b>test</b> will be inserted. To fix this you could
- * do: <span><b>test</b><i>test2</i></span>
- *
- * @param string html The HTML to insert
- * @param string endHtml If specified instead of the inserted HTML replacing the selected text the selected text
- * will be placed between html and endHtml. If there is no selected text html and endHtml will
- * be concated together.
- */
- base.wysiwygEditorInsertHtml = function (html, endHtml, overrideCodeBlocking) {
- base.focus();
-
- // don't apply to code elements
- if(!overrideCodeBlocking && ($(rangeHelper.parentNode()).is('code') ||
- $(rangeHelper.parentNode()).parents('code').length !== 0))
- return;
-
- rangeHelper.insertHTML(html, endHtml);
- };
- /**
- * Like wysiwygEditorInsertHtml except it converts any HTML to text
- * @private
- */
- base.wysiwygEditorInsertText = function (text) {
- text = text.replace(/&/g, "&")
- .replace(/</g, "<")
- .replace(/>/g, ">")
- .replace(/ /g, " ")
- .replace(/\r\n|\r/g, "\n")
- .replace(/\n/g, "<br />");
-
- base.wysiwygEditorInsertHtml(text);
- };
-
- /**
- * Like wysiwygEditorInsertHtml but works on the
- * text editor instead
- *
- * @param {String} text
- * @param {String} endText
- */
- base.textEditorInsertText = function (text, endText) {
- var range, start, end, txtLen;
-
- textEditor.focus();
-
- if(textEditor.selectionStart != null)
- {
- start = textEditor.selectionStart;
- end = textEditor.selectionEnd;
- txtLen = text.length;
-
- if(endText)
- text += textEditor.value.substring(start, end) + endText;
-
- textEditor.value = textEditor.value.substring(0, start) + text + textEditor.value.substring(end, textEditor.value.length);
-
- if(endText)
- textEditor.selectionStart = (start + text.length) - endText.length;
- else
- textEditor.selectionStart = start + text.length;
-
- textEditor.selectionEnd = textEditor.selectionStart;
- }
- else if(document.selection.createRange)
- {
- range = document.selection.createRange();
-
- if(endText)
- text += range.text + endText;
-
- range.text = text;
- }
- else
- textEditor.value += text + endText;
-
- textEditor.focus();
- };
-
- /**
- * Gets the current rangeHelper instance
- */
- base.getRangeHelper = function () {
- return rangeHelper;
- };
- /**
- * Gets the WYSIWYG editors HTML which is between the body tags
- */
- base.getWysiwygEditorValue = function (filter) {
- if (!base.options.supportedWysiwyg)
- return;
- var $body = $wysiwygEditor.contents().find("body"),
- html;
-
- // fix any invalid nesting
- $.sceditor.dom.fixNesting($body.get(0));
- html = $body.html();
-
- if(filter !== false && base.options.getHtmlHandler)
- html = base.options.getHtmlHandler(html, $body);
- return html;
- };
- /**
- * Gets the text editor value
- * @param bool filter If to run the returned string through the filter or if to return the raw value. Defaults to filter.
- */
- base.getTextareaValue = function (filter) {
- var val = $textEditor.val();
- if(filter !== false && base.options.getTextHandler)
- val = base.options.getTextHandler(val);
- return val;
- };
- /**
- * Sets the WYSIWYG HTML editor value. Should only be the HTML contained within the body tags
- * @param bool filter If to run the returned string through the filter or if to return the raw value. Defaults to filter.
- */
- base.setWysiwygEditorValue = function (value) {
- getWysiwygDoc().body.innerHTML = replaceEmoticons(value);
- };
- /**
- * Sets the text editor value
- */
- base.setTextareaValue = function (value) {
- $textEditor.val(value);
- };
- /**
- * Updates the forms textarea value
- */
- base.updateTextareaValue = function () {
- if(base.inSourceMode())
- $textarea.val(base.getTextareaValue(false));
- else
- $textarea.val(base.getWysiwygEditorValue());
- };
- /**
- * Replaces any emoticon codes in the passed HTML with their emoticon images
- * @private
- */
- replaceEmoticons = function (html) {
- if(base.options.toolbar.indexOf('emoticon') === -1)
- return html;
-
- var emoticons = $.extend({}, base.options.emoticons.more, base.options.emoticons.dropdown, base.options.emoticons.hidden);
- $.each(emoticons, function (key, url) {
- if (key == '')
- return;
- // escape the key before using it as a regex
- // and append the regex to only find emoticons outside
- // of HTML tags
- var reg = $.sceditor.regexEscape(key) + "(?=([^\\<\\>]*?<(?!/code)|[^\\<\\>]*?$))",
- group = '';
-
- // Make sure the emoticon is surrounded by whitespace or is at the start/end of a string or html tag
- if(base.options.emoticonsCompat)
- {
- reg = "((>|^|\\s|\xA0|\u2002|\u2003|\u2009| ))" + reg + "(?=(\\s|$|<|\xA0|\u2002|\u2003|\u2009| ))";
- group = '$1';
- }
- html = html.replace(
- new RegExp(reg, 'gm'),
- group + '<img src="' + url + '" data-sceditor-emoticon="' + key + '" alt="' + key + '" />'
- );
- });
- return html;
- };
-
- /**
- * If the editor is in source code mode
- * @return boolean
- */
- base.inSourceMode = function () {
- return $textEditor.is(':visible');
- };
- /**
- * Switches between the WYSIWYG and plain text modes
- */
- base.toggleTextMode = function () {
- if(base.inSourceMode() && base.options.supportedWysiwyg)
- base.setWysiwygEditorValue(base.getTextareaValue());
- else
- base.setTextareaValue(base.getWysiwygEditorValue());
- // enable all the buttons
- $toolbar.find('.sceditor-button').removeClass('disabled');
- lastRange = null;
- $textEditor.toggle();
- $wysiwygEditor.toggle();
-
- // diable any buttons that are not allowed for this mode
- $toolbar.find('.sceditor-button').each(function () {
- var button = $(this);
-
- if(base.inSourceMode() && !button.data('sceditor-txtmode'))
- button.addClass('disabled');
- else if (!base.inSourceMode() && !button.data('sceditor-wysiwygmode'))
- button.addClass('disabled');
- });
- };
- /**
- * Handles the passed command
- * @private
- */
- handleCommand = function (caller, command) {
- // check if in text mode and handle text commands
- if(base.inSourceMode())
- {
- if(command.txtExec)
- {
- if($.isArray(command.txtExec))
- base.textEditorInsertText.apply(base, command.txtExec);
- else
- command.txtExec.call(base, caller);
- }
-
- return;
- }
-
- if(!command.hasOwnProperty("exec"))
- return;
-
- if($.isFunction(command.exec))
- command.exec.call(base, caller);
- else
- base.execCommand (command.exec, command.hasOwnProperty("execParam") ? command.execParam : null);
- };
- /**
- * Fucuses the editors input area
- */
- base.focus = function () {
- if(!base.inSourceMode())
- {
- wysiwygEditor.contentWindow.focus();
-
- // Needed for IE < 9
- if(lastRange !== null) {
- rangeHelper.selectRange(lastRange);
-
- // remove the stored range after being set.
- // If the editor loses focus it should be
- // saved again.
- lastRange = null;
- }
- }
- else
- textEditor.focus();
- };
- /**
- * Saves the current range. Needed for IE because it forgets
- * where the cursor was and what was selected
- * @private
- */
- saveRange = function () {
- /* this is only needed for IE */
- if(!$.browser.msie)
- return;
- lastRange = rangeHelper.selectedRange();
- };
- /**
- * Executes a command on the WYSIWYG editor
- *
- * @param string|function command
- * @param mixed param
- */
- base.execCommand = function (command, param) {
- var executed = false;
- base.focus();
- // don't apply any comannds to code elements
- if($(rangeHelper.parentNode()).is('code') ||
- $(rangeHelper.parentNode()).parents('code').length !== 0)
- return;
- if(getWysiwygDoc())
- {
- try
- {
- executed = getWysiwygDoc().execCommand(command, false, param);
- }
- catch (e){}
- }
- // show error if execution failed and an error message exists
- if(!executed && typeof base.commands[command] !== "undefined" &&
- typeof base.commands[command].errorMessage !== "undefined")
- alert(base._(base.commands[command].errorMessage));
- };
-
- /**
- * Handles any key press in the WYSIWYG editor
- *
- * @private
- */
- handleKeyPress = function (e) {
- base.closeDropDown();
-
- var selectedContainer = rangeHelper.parentNode(),
- $selectedContainer = $(selectedContainer);
- // "Fix" (ok it's a hack) for blocklevel elements being duplicated in some browsers when
- // enter is pressed instead of inserting a newline
- if(e.which === 13)
- {
- if($selectedContainer.is('code, blockquote') || $selectedContainer.parents('code, blockquote').length !== 0)
- {
- lastRange = null;
- base.wysiwygEditorInsertHtml('<br />', null, true);
- return false;
- }
- }
- // make sure there is always a newline after code or quote tags
- var d = getWysiwygDoc();
- $.sceditor.dom.rTraverse(d.body, function(node) {
- if((node.nodeType === 3 && node.nodeValue !== "") ||
- node.nodeName.toLowerCase() === 'br') {
- // this is the last text or br node, if its in a code or quote tag
- // then add a newline after it
- if($(node).parents('code, blockquote').length > 0)
- $(d.body).append(d.createElement('br'));
- return false;
- }
- }, true);
- // don't apply to code elements
- if($selectedContainer.is('code') || $selectedContainer.parents('code').length !== 0)
- return;
-
- var i = keyPressFuncs.length;
- while(i--)
- keyPressFuncs[i].call(base, e, wysiwygEditor, $textEditor);
- };
-
- handleKeyUp = function (e) {
- };
- /**
- * Handles any mousedown press in the WYSIWYG editor
- * @private
- */
- handleMouseDown = function (e) {
- base.closeDropDown();
- lastRange = null;
- };
- /**
- * Handles the window resize event. Needed to resize then editor
- * when the window size changes in fluid deisgns.
- */
- handleWindowResize = function () {
- if(base.options.height !== null && base.options.height.toString().indexOf("%") > -1)
- setHeight(editorContainer.parent().height() *
- (parseFloat(base.options.height) / 100));
- if(base.options.width !== null && base.options.width.toString().indexOf("%") > -1)
- setWidth(editorContainer.parent().width() *
- (parseFloat(base.options.width) / 100));
- };
-
- /**
- * Translates the string into the locale language.
- *
- * Replaces any {0}, {1}, {2}, ect. with the params provided.
- * @public
- * @return string
- */
- base._ = function() {
- var args = arguments;
-
- if(locale !== null && locale[args[0]])
- args[0] = locale[args[0]];
-
- return args[0].replace(/\{(\d+)\}/g, function(str, p1) {
- return typeof args[p1-0+1] !== 'undefined'?
- args[p1-0+1] :
- '{' + p1 + '}';
- });
- };
-
- /**
- * Init the locale variable with the specified locale if possible
- * @private
- * @return void
- */
- initLocale = function () {
- if($.sceditor.locale[base.options.locale])
- locale = $.sceditor.locale[base.options.locale];
- else
- {
- var lang = base.options.locale.split("-");
-
- if($.sceditor.locale[lang[0]])
- locale = $.sceditor.locale[lang[0]];
- }
-
- if(locale !== null && locale.dateFormat)
- base.options.dateFormat = locale.dateFormat;
- };
- // run the initializer
- init();
- };
-
- // ----------------------------------------------------------
- // A short snippet for detecting versions of IE in JavaScript
- // without resorting to user-agent sniffing
- // ----------------------------------------------------------
- // If you're not in IE (or IE version is less than 5) then:
- // ie === undefined
- // If you're in IE (>=5) then you can determine which version:
- // ie === 7; // IE7
- // Thus, to detect IE:
- // if (ie) {}
- // And to detect the version:
- // ie === 6 // IE6
- // ie > 7 // IE8, IE9 ...
- // ie < 9 // Anything less than IE9
- // ----------------------------------------------------------
- // UPDATE: Now using Live NodeList idea from @jdalton
- // Source: https://gist.github.com/527683
- $.sceditor.ie = (function(){
- var undef,
- v = 3,
- div = document.createElement('div'),
- all = div.getElementsByTagName('i');
-
- while (
- div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
- all[0]
- );
-
- return v > 4 ? v : undef;
-
- }());
-
- /**
- * Escapes a string so it's safe to use in regex
- * @param string str The strong to escape
- * @return string
- */
- $.sceditor.regexEscape = function (str) {
- return str.replace(/[\$\?\[\]\.\*\(\)\|\\]/g, "\\$&")
- .replace("<", "<")
- .replace(">", ">");
- };
- $.sceditor.locale = {};
- $.sceditor.commands = {
- // START_COMMAND: Bold
- bold: {
- exec: "bold",
- tooltip: "Bold"
- },
- // END_COMMAND
- // START_COMMAND: Italic
- italic: {
- exec: "italic",
- tooltip: "Italic"
- },
- // END_COMMAND
- // START_COMMAND: Underline
- underline: {
- exec: "underline",
- tooltip: "Underline"
- },
- // END_COMMAND
- // START_COMMAND: Strikethrough
- strike: {
- exec: "strikethrough",
- tooltip: "Strikethrough"
- },
- // END_COMMAND
- // START_COMMAND: Subscript
- subscript: {
- exec: "subscript",
- tooltip: "Subscript"
- },
- // END_COMMAND
- // START_COMMAND: Superscript
- superscript: {
- exec: "superscript",
- tooltip: "Superscript"
- },
- // END_COMMAND
- // START_COMMAND: Left
- left: {
- exec: "justifyleft",
- tooltip: "Align left"
- },
- // END_COMMAND
- // START_COMMAND: Centre
- center: {
- exec: "justifycenter",
- tooltip: "Center"
- },
- // END_COMMAND
- // START_COMMAND: Right
- right: {
- exec: "justifyright",
- tooltip: "Align right"
- },
- // END_COMMAND
- // START_COMMAND: Justify
- justify: {
- exec: "justifyfull",
- tooltip: "Justify"
- },
- // END_COMMAND
- // START_COMMAND: Font
- font: {
- exec: function (caller) {
- var editor = this,
- fonts = editor.options.fonts.split(","),
- content = $("<div />"),
- clickFunc = function (e) {
- editor.execCommand("fontname", $(this).data('sceditor-font'));
- editor.closeDropDown(true);
- e.preventDefault();
- };
- for (var i=0; i < fonts.length; i++) {
- content.append(
- $('<a class="sceditor-font-option" href="#"><font face="' + fonts[i] + '">' + fonts[i] + '</font></a>')
- .data('sceditor-font', fonts[i])
- .click(clickFunc));
- }
- editor.createDropDown(caller, "font-picker", content);
- },
- tooltip: "Font Name"
- },
- // END_COMMAND
- // START_COMMAND: Size
- size: {
- exec: function (caller) {
- var sizes = [0, 8, 10, 12, 14, 18, 24, 36];
- var editor = this,
- content = $("<div />"),
- clickFunc = function (e) {
- editor.execCommand("fontsize", $(this).data('sceditor-fontsize'));
- editor.closeDropDown(true);
- e.preventDefault();
- };
- for (var i=1; i<= 7; i++) {
- content.append(
- $('<a class="sceditor-fontsize-option" style="line-height:' + sizes[i] + 'pt" href="#"><font size="' + i + '">' + i + '</font></a>')
- .data('sceditor-fontsize', i)
- .click(clickFunc));
- }
- editor.createDropDown(caller, "fontsize-picker", content);
- },
- tooltip: "Font Size"
- },
- // END_COMMAND
- // START_COMMAND: Colour
- color: {
- exec: function (caller) {
- var editor = this,
- genColor = {r: 255, g: 255, b: 255},
- content = $("<div />"),
- colorColumns = this.options.colors?this.options.colors.split("|"):new Array(21),
- // IE is slow at string concation so use an array
- html = [],
- htmlIndex = 0;
- for (var i=0; i < colorColumns.length; ++i) {
- var colors = (typeof colorColumns[i] !== "undefined")?colorColumns[i].split(","):new Array(21);
- html[htmlIndex++] = '<div class="sceditor-color-column">';
- for (var x=0; x < colors.length; ++x) {
- // use pre defined colour if can otherwise use the generated color
- var color = (typeof colors[x] !== "undefined")?colors[x]:"#" + genColor.r.toString(16) + genColor.g.toString(16) + genColor.b.toString(16);
- html[htmlIndex++] = '<a href="#" class="sceditor-color-option" style="background-color: '+color+'" data-color="'+color+'"></a>';
- // calculate the next generated color
- if(x%5===0)
- genColor = {r: genColor.r, g: genColor.g-51, b: 255};
- else
- genColor = {r: genColor.r, g: genColor.g, b: genColor.b-51};
- }
- html[htmlIndex++] = '</div>';
- // calculate the next generated color
- if(i%5===0)
- genColor = {r: genColor.r-51, g: 255, b: 255};
- else
- genColor = {r: genColor.r, g: 255, b: 255};
- }
- content.append(html.join(''))
- .find('a')
- .click(function (e) {
- editor.execCommand("forecolor", $(this).attr('data-color'));
- editor.closeDropDown(true);
- e.preventDefault();
- });
- editor.createDropDown(caller, "color-picker", content);
- },
- tooltip: "Font Color"
- },
- // END_COMMAND
- // START_COMMAND: Remove Format
- removeformat: {
- exec: "removeformat",
- tooltip: "Remove Formatting"
- },
- // END_COMMAND
- // START_COMMAND: Cut
- cut: {
- exec: "cut",
- tooltip: "Cut",
- errorMessage: "Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X"
- },
- // END_COMMAND
- // START_COMMAND: Copy
- copy: {
- exec: "copy",
- tooltip: "Copy",
- errorMessage: "Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C"
- },
- // END_COMMAND
- // START_COMMAND: Paste
- paste: {
- exec: "paste",
- tooltip: "Paste",
- errorMessage: "Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V"
- },
- // END_COMMAND
- // START_COMMAND: Paste Text
- pastetext: {
- exec: function (caller) {
- var editor = this,
- content = $(this._('<form><div><label for="txt">{0}</label> <textarea cols="20" rows="7" id="txt">' +
- '</textarea></div></form>',
- this._("Paste your text inside the following box:")
- ))
- .submit(function () {return false;});
- content.append($(this._('<div><input type="button" class="button" value="{0}" /></div>',
- this._("Insert")
- )).click(function (e) {
- editor.wysiwygEditorInsertText($(this).parent("form").find("#txt").val());
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "pastetext", content);
- },
- tooltip: "Paste Text"
- },
- // END_COMMAND
- // START_COMMAND: Bullet List
- bulletlist: {
- exec: "insertunorderedlist",
- tooltip: "Bullet list"
- },
- // END_COMMAND
- // START_COMMAND: Ordered List
- orderedlist: {
- exec: "insertorderedlist",
- tooltip: "Numbered list"
- },
- // END_COMMAND
- // START_COMMAND: Table
- table: {
- exec: function (caller) {
- var editor = this,
- content = $(this._(
- '<form><div><label for="rows">{0}</label><input type="text" id="rows" value="2" /></div>' +
- '<div><label for="cols">{1}</label><input type="text" id="cols" value="2" /></div></form>',
- this._("Rows:"),
- this._("Cols:")
- ))
- .submit(function () {return false;});
- content.append($(this._('<div><input type="button" class="button" value="{0}" /></div>',
- this._("Insert")
- )).click(function (e) {
- var rows = $(this).parent("form").find("#rows").val() - 0,
- cols = $(this).parent("form").find("#cols").val() - 0,
- html = '<table>';
- if(rows < 1 || cols < 1)
- return;
-
- for (var row=0; row < rows; row++) {
- html += '<tr>';
- for (var col=0; col < cols; col++) {
- if($.browser.msie)
- html += '<td></td>';
- else
- html += '<td><br class="sceditor-ignore" /></td>';
- }
- html += '</tr>';
- }
- html += '</table>';
- editor.wysiwygEditorInsertHtml(html);
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "inserttable", content);
- },
- tooltip: "Insert a table"
- },
- // END_COMMAND
- // START_COMMAND: Horizontal Rule
- horizontalrule: {
- exec: "inserthorizontalrule",
- tooltip: "Insert a horizontal rule"
- },
- // END_COMMAND
- // START_COMMAND: Code
- code: {
- exec: function () {
- this.wysiwygEditorInsertHtml('<code>', '<br /></code>');
- },
- tooltip: "Code"
- },
- // END_COMMAND
- // START_COMMAND: Image
- image: {
- exec: function (caller) {
- var editor = this,
- content = $(this._('<form><div><label for="link">{0}</label> <input type="text" id="image" value="http://" /></div>' +
- '<div><label for="width">{1}</label> <input type="text" id="width" size="2" /></div>' +
- '<div><label for="height">{2}</label> <input type="text" id="height" size="2" /></div></form>',
- this._("URL:"),
- this._("Width (optional):"),
- this._("Height (optional):")
- ))
- .submit(function () {return false;});
- content.append($(this._('<div><input type="button" class="button" value="Insert" /></div>',
- this._("Insert")
- )).click(function (e) {
- var $form = $(this).parent("form"),
- val = $form.find("#image").val(),
- attrs = '',
- width,
- height;
- if((width = $form.find("#width").val()))
- attrs += ' width="' + width + '"';
- if((height = $form.find("#height").val()))
- attrs += ' height="' + height + '"';
- if(val && val !== "http://")
- editor.wysiwygEditorInsertHtml('<img' + attrs + ' src="' + val + '" />');
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "insertimage", content);
- },
- tooltip: "Insert an image"
- },
- // END_COMMAND
- // START_COMMAND: E-mail
- email: {
- exec: function (caller) {
- var editor = this,
- content = $(this._('<form><div><label for="email">{0}</label> <input type="text" id="email" value="" /></div></form>',
- this._("E-mail:")
- ))
- .submit(function () {return false;});
- content.append($('<div><input type="button" class="button" value="Insert" /></div>').click(function (e) {
- var val = $(this).parent("form").find("#email").val();
- if(val)
- {
- // needed for IE to reset the last range
- editor.focus();
- if(!editor.getRangeHelper().selectedHtml())
- editor.wysiwygEditorInsertHtml('<a href="' + 'mailto:' + val + '">' + val + '</a>');
- else
- editor.execCommand("createlink", 'mailto:' + val);
- }
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "insertemail", content);
- },
- tooltip: "Insert an email"
- },
- // END_COMMAND
- // START_COMMAND: Link
- link: {
- exec: function (caller) {
- var editor = this,
- content = $(this._('<form><div><label for="link">{0}</label> <input type="text" id="link" value="http://" /></div>' +
- '<div><label for="des">{1}</label> <input type="text" id="des" value="" /></div></form>',
- this._("URL:"),
- this._("Description (optional):")
- ))
- .submit(function () {return false;});
- content.append($(
- this._('<div><input type="button" class="button" value="{0}" /></div>',
- this._("Insert")
- )).click(function (e) {
- var val = $(this).parent("form").find("#link").val(),
- description = $(this).parent("form").find("#des").val();
- if(val !== "" && val !== "http://") {
- // needed for IE to reset the last range
- editor.focus();
- if(!editor.getRangeHelper().selectedHtml() || description)
- {
- if(!description)
- description = val;
-
- editor.wysiwygEditorInsertHtml('<a href="' + val + '">' + description + '</a>');
- }
- else
- editor.execCommand("createlink", val);
- }
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "insertlink", content);
- },
- tooltip: "Insert a link"
- },
- // END_COMMAND
- // START_COMMAND: Unlink
- unlink: {
- exec: "unlink",
- tooltip: "Unlink"
- },
- // END_COMMAND
- // START_COMMAND: Quote
- quote: {
- exec: function (caller, html, author) {
- var before = '<blockquote>',
- end = '</blockquote>';
- // if there is HTML passed set end to null so any selected
- // text is replaced
- if(html)
- {
- author = (author ? '<cite>' + author + '</cite>' : '');
-
- before = before + author + html + end + '<br />';
- end = null;
- }
- // if not add a newline to the end of the inserted quote
- else if(this.getRangeHelper().selectedHtml() === "")
- end = '<br />' + end;
-
- this.wysiwygEditorInsertHtml(before, end);
- },
- tooltip: "Insert a Quote"
- },
- // END_COMMAND
- // START_COMMAND: Emoticons
- emoticon: {
- exec: function (caller) {
- var appendEmoticon,
- editor = this,
- content = $('<div />'),
- line = $('<div />');
- appendEmoticon = function (code, emoticon) {
- line.append($('<img />')
- .attr({
- src: emoticon,
- alt: code
- })
- .click(function (e) {
- var start = '', end = '';
-
- if(editor.options.emoticonsCompat)
- {
- start = '<span> ';
- end = ' </span>';
- }
-
- editor.wysiwygEditorInsertHtml(start + '<img src="' + $(this).attr("src") +
- '" data-sceditor-emoticon="' + $(this).attr('alt') + '" />' + end);
- editor.closeDropDown(true);
- e.preventDefault();
- })
- );
- if(line.children().length > 3) {
- content.append(line);
- line = $('<div />');
- }
- };
- $.each(editor.options.emoticons.dropdown, appendEmoticon);
- if(line.children().length > 0)
- content.append(line);
- if(typeof editor.options.emoticons.more !== "undefined") {
- var more = $(this._('<a class="sceditor-more">{0}</a>', this._("More"))).click(function () {
- var emoticons = $.extend({}, editor.options.emoticons.dropdown, editor.options.emoticons.more);
- content = $('<div />');
- line = $('<div />');
- $.each(emoticons, appendEmoticon);
- if(line.children().length > 0)
- content.append(line);
- editor.createDropDown(caller, "insertemoticon", content);
- });
- content.append(more);
- }
- editor.createDropDown(caller, "insertemoticon", content);
- },
- keyPress: function (e, wysiwygEditor)
- {
- // make sure emoticons command is in the toolbar before running
- if(this.options.toolbar.indexOf('emoticon') === -1)
- return;
-
- var editor = this,
- pos = 0,
- curChar = String.fromCharCode(e.which);
-
- if(!editor.EmoticonsCache) {
- editor.EmoticonsCache = [];
-
- $.each($.extend({}, editor.options.emoticons.more, editor.options.emoticons.dropdown, editor.options.emoticons.hidden), function(key, url) {
- editor.EmoticonsCache[pos++] = [
- key,
- '<img src="' + url + '" data-sceditor-emoticon="' + key + '" alt="' + key + '" />'
- ];
- });
- editor.EmoticonsCache.sort(function(a, b){
- return a[0].length - b[0].length;
- });
- }
-
- if(!editor.longestEmoticonCode)
- editor.longestEmoticonCode = editor.EmoticonsCache[editor.EmoticonsCache.length - 1][0].length;
-
- if(editor.getRangeHelper().raplaceKeyword(editor.EmoticonsCache, true, true, editor.longestEmoticonCode, editor.options.emoticonsCompat, curChar))
- {
- if(/^\s$/.test(curChar) && editor.options.emoticonsCompat)
- return true;
-
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- },
- tooltip: "Insert an emoticon"
- },
- // END_COMMAND
- // START_COMMAND: YouTube
- youtube: {
- exec: function (caller) {
- var editor = this;
- var content = $(
- this._('<form><div><label for="link">{0}</label> <input type="text" id="link" value="http://" /></div></form>',
- this._("Video URL:")
- ))
- .submit(function () {return false;});
- content.append(
- $(this._('<div><input type="button" class="button" value="{0}" /></div>',
- this._("Insert")
- ))
- .click(function (e) {
- var val = $(this).parent("form").find("#link").val();
-
- if(val !== "" && val !== "http://") {
- // See http://www.abovetopsecret.com/forum/thread270269/pg1
- val = val.replace(/^[^v]+v.(.{11}).*/,"$1");
- editor.wysiwygEditorInsertHtml('<iframe width="560" height="315" src="http://www.youtube.com/embed/' + val +
- '?wmode=opaque" data-youtube-id="' + val + '" frameborder="0" allowfullscreen></iframe>');
- }
-
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "insertlink", content);
- },
- tooltip: "Insert a YouTube video"
- },
- // END_COMMAND
- // START_COMMAND: Date
- date: {
- exec: function () {
- var now = new Date(),
- year = now.getYear(),
- month = now.getMonth()+1,
- day = now.getDate();
- if(year < 2000)
- year = 1900 + year;
- if(month < 10)
- month = "0" + month;
- if(day < 10)
- day = "0" + day;
- this.wysiwygEditorInsertHtml('<span>' +
- this.options.dateFormat.replace(/year/i, year).replace(/month/i, month).replace(/day/i, day) +
- '</span>');
- },
- tooltip: "Insert current date"
- },
- // END_COMMAND
- // START_COMMAND: Time
- time: {
- exec: function () {
- var now = new Date(),
- hours = now.getHours(),
- mins = now.getMinutes(),
- secs = now.getSeconds();
- if(hours < 10)
- hours = "0" + hours;
- if(mins < 10)
- mins = "0" + mins;
- if(secs < 10)
- secs = "0" + secs;
- this.wysiwygEditorInsertHtml('<span>' + hours + ':' + mins + ':' + secs + '</span>');
- },
- tooltip: "Insert current time"
- },
- // END_COMMAND
- // START_COMMAND: Print
- print: {
- exec: "print",
- tooltip: "Print"
- },
- // END_COMMAND
- // START_COMMAND: Source
- source: {
- exec: function () {
- this.toggleTextMode();
- },
- txtExec: function () {
- this.toggleTextMode();
- },
- tooltip: "View source"
- },
- // END_COMMAND
-
- // this is here so that commands above can be removed
- // without having to remove the , after the last one.
- // Needed for IE.
- ignore: {}
- };
-
- /**
- * Range helper class
- */
- $.sceditor.rangeHelper = function(w, d) {
- var win, doc,
- isW3C = true,
- startMarker = "sceditor-start-marker",
- endMarker = "sceditor-end-marker",
- base = this,
- init, _createMarker, _getOuterText, _selectOuterText;
-
- /**
- * @constructor
- * @param Window window
- * @param Document document
- * @private
- */
- init = function (window, document) {
- doc = document || window.contentDocument || window.document;
- win = window;
- isW3C = !!window.getSelection;
- }(w, d);
-
- /**
- * Inserts HTML.
- *
- * If endHTML is specified the selected contents will be put between
- * html and endHTML.
- * @param string html
- * @param string endHTML
- */
- base.insertHTML = function(html, endHTML) {
- var node, endNode, div;
-
- if(endHTML)
- html += base.selectedHtml() + endHTML;
-
- if(isW3C)
- {
- div = doc.createElement('div');
- node = doc.createDocumentFragment();
- div.innerHTML = html;
-
- while(div.firstChild)
- node.appendChild(div.firstChild);
-
- base.insertNode(node);
- }
- else
- base.selectedRange().pasteHTML(html);
- };
-
- /**
- * Inserts a DOM node.
- *
- * If endNode is specified the selected contents will be put between
- * node and endNode.
- * @param Node node
- * @param Node endNode
- */
- base.insertNode = function(node, endNode) {
- if(isW3C)
- {
- var toInsert = doc.createDocumentFragment(),
- range = base.selectedRange(),
- selection, selectAfter;
-
- toInsert.appendChild(node);
-
- if(endNode)
- {
- toInsert.appendChild(range.extractContents());
- toInsert.appendChild(endNode);
- }
-
- selectAfter = toInsert.lastChild;
- range.deleteContents();
- range.insertNode(toInsert);
-
- selection = doc.createRange();
- selection.setStartAfter(selectAfter);
- base.selectRange(selection);
- }
- else
- base.insertHTML(node.outerHTML, endNode?endNode.outerHTML:null);
- };
-
- /**
- * Clones the selected Range
- * @return Range|TextRange
- */
- base.cloneSelected = function() {
- if(!isW3C)
- return base.selectedRange().duplicate();
-
- return base.selectedRange().cloneRange();
- };
-
- /**
- * Gets the selected Range
- * @return Range|TextRange
- */
- base.selectedRange = function() {
- var sel;
-
- if(win.getSelection)
- sel = win.getSelection();
- else
- sel = doc.selection;
-
- if(sel.getRangeAt && sel.rangeCount <= 0)
- sel.addRange(doc.createRange());
-
- if(!isW3C)
- return sel.createRange();
-
- return sel.getRangeAt(0);
- };
-
- /**
- * Gets the selected HTML
- * @return string
- */
- base.selectedHtml = function() {
- var range = base.selectedRange();
-
- if(!range)
- return '';
-
- // IE9+ and all other browsers
- if (window.XMLSerializer)
- return new XMLSerializer().serializeToString(range.cloneContents());
-
- // IE < 9
- if(!isW3C)
- {
- if(range.text !== '' && range.htmlText)
- return range.htmlText;
- }
-
- return '';
- };
-
- base.parentNode = function() {
- var range = base.selectedRange();
-
- if(isW3C)
- return range.commonAncestorContainer;
- else
- return range.parentElement();
- };
-
- /**
- * Inserts a node at either the start or end of the current selection
- * @param Bool start
- * @param Node node
- */
- base.insertNodeAt = function(start, node) {
- var range = base.cloneSelected();
-
- range.collapse(start);
-
- if(range.insertNode)
- range.insertNode(node);
- else
- range.pasteHTML(node.outerHTML);
- };
-
- /**
- * Creates a marker node
- * @param String id
- * @return Node
- */
- _createMarker = function(id) {
- base.removeMarker(id);
-
- var marker = doc.createElement("span");
- marker.id = id;
- marker.style.lineHeight = "0";
- marker.style.display = "none";
- marker.className = "sceditor-selection";
-
- return marker;
- };
-
- /**
- * Inserts start/end markers for the current selection
- */
- base.insertMarkers = function() {
- base.insertNodeAt(true, _createMarker(startMarker));
- base.insertNodeAt(false, _createMarker(endMarker));
- };
-
- /**
- * Gets the marker with the specified ID
- * @param String id
- * @return Node
- */
- base.getMarker = function(id) {
- return doc.getElementById(id);
- };
-
- /**
- * Removes the marker with the specified ID
- * @param String id
- */
- base.removeMarker = function(id) {
- var marker = base.getMarker(id);
-
- if(marker)
- marker.parentNode.removeChild(marker);
- };
-
- /**
- * Removes the start/end markers
- */
- base.removeMarkers = function() {
- base.removeMarker(startMarker);
- base.removeMarker(endMarker);
- };
-
- /**
- * Saves the current range location
- */
- base.saveRange = function() {
- base.insertMarkers();
- };
-
- /**
- * Selected the specified range
- * @param Range|TextRange range
- */
- base.selectRange = function(range) {
- if(!isW3C)
- range.select();
- else
- {
- win.getSelection().removeAllRanges();
- win.getSelection().addRange(range);
- }
- };
-
- /**
- * Restores the last saved range if possible
- */
- base.restoreRange = function() {
- var range = base.selectedRange(),
- start = base.getMarker(startMarker),
- end = base.getMarker(endMarker);
-
- if(!start || !end)
- return false;
-
- if(!isW3C)
- {
- range = doc.body.createTextRange();
- var marker = doc.body.createTextRange();
- marker.moveToElementText(start);
- range.setEndPoint('StartToStart', marker);
- range.moveStart('character', 0);
- marker.moveToElementText(end);
- range.setEndPoint('EndToStart', marker);
- range.moveEnd('character', 0);
-
- base.selectRange(range);
- }
- else
- {
- range = doc.createRange();
- range.setStartBefore(start);
- range.setEndAfter(end);
-
- base.selectRange(range);
- }
-
- base.removeMarkers();
- };
-
- /**
- * Selects the text left and right of the current selection
- * @param int left
- * @param int right
- * @private
- */
- _selectOuterText = function(left, right) {
- var range = base.cloneSelected();
- range.collapse(false);
- if(!isW3C)
- {
- range.moveStart('character', 0-left);
- range.moveEnd('character', right);
- }
- else
- {
- range.setStart(range.startContainer, range.startOffset-left);
- range.setEnd(range.endContainer, range.endOffset+right);
- //range.deleteContents();
- }
-
- base.selectRange(range);
- };
-
- /**
- * Gets the text left or right of the current selection
- * @param bool before
- * @param int length
- * @private
- */
- _getOuterText = function(before, length) {
- var ret = "",
- range = base.cloneSelected(),
- node;
-
- range.collapse(false);
- if(before)
- {
- if(!isW3C)
- {
- range.moveStart('character', 0-length);
- ret = range.text;
- }
- else
- {
- ret = range.startContainer.textContent.substr(0, range.startOffset);
- ret = ret.substr(Math.max(0, ret.length - length));
- }
- }
- else
- {
- if(!isW3C)
- {
- range.moveEnd('character', length);
- ret = range.text;
- }
- else
- ret = range.startContainer.textContent.substr(range.startOffset, length);
- }
- return ret;
- };
-
- /**
- * Replaces keys with values based on the current range
- * @param Array rep
- * @param Bool includePrev If to include text before or just text after
- * @param Bool repSorted If the keys array is pre sorted
- * @param Int longestKey Length of the longest key
- * @param Bool requireWhiteSpace If the key must be surrounded by whitespace
- */
- base.raplaceKeyword = function(rep, includeAfter, repSorted, longestKey, requireWhiteSpace, curChar) {
- if(!repSorted)
- rep.sort(function(a, b){
- return a.length - b.length;
- });
- var maxKeyLen = longestKey || rep[rep.length-1][0].length,
- before, after, str, i, start, left, pat, lookStart;
- before = after = str = "";
- if(requireWhiteSpace)
- {
- // forcing spaces around doesn't work with textRanges as they will select text
- // on the other side of an image causing space-img-key to be returned as
- // space-key which would be valid when it's not.
- if(!isW3C)
- return false;
-
- ++maxKeyLen;
- }
- before = _getOuterText(true, maxKeyLen);
-
- if(includeAfter)
- after = _getOuterText(false, maxKeyLen);
-
- str = before + (curChar!=null?curChar:"") + after;
- i = rep.length;
- while(i--)
- {
- //pat = new RegExp("(?:^|\\s)" + $.sceditor.regexEscape(rep[i][0]) + "(?=\\s|$)");
- pat = new RegExp("(?:[\\s\xA0\u2002\u2003\u2009])" + $.sceditor.regexEscape(rep[i][0]) + "(?=[\\s\xA0\u2002\u2003\u2009])");
- lookStart = before.length - 1 - rep[i][0].length;
-
- if(requireWhiteSpace)
- --lookStart;
-
- lookStart = Math.max(0, lookStart);
- if((!requireWhiteSpace && (start = str.indexOf(rep[i][0], lookStart)) > -1) ||
- (requireWhiteSpace && (start = str.substr(lookStart).search(pat)) > -1))
- {
- if(requireWhiteSpace)
- start += lookStart + 1;
-
- // make sure the substr is between before and after not entierly in one
- // or the other
- if(start > before.length || start+rep[i][0].length + (requireWhiteSpace?1:0) < before.length)
- continue;
- left = before.length - start;
- _selectOuterText(left, rep[i][0].length-left-(curChar!=null&&/^\S/.test(curChar)?1:0));
- base.insertHTML(rep[i][1]);
- return true;
- }
- }
-
- return false;
- };
- };
- /**
- * Static DOM helper class
- */
- $.sceditor.dom = {
- /**
- * Loop all child nodes of the passed node
- *
- * The function should accept 1 parameter being the node.
- * If the function returns false the loop will be exited.
- *
- * @param HTMLElement node
- * @param function func Function that is called for every node, should accept 1 param for the node
- * @param bool innermostFirst If the innermost node should be passed to the function before it's parents
- * @param bool siblingsOnly If to only traverse the nodes siblings
- * @param bool reverse If to traverse the nodes in reverse
- */
- traverse: function(node, func, innermostFirst, siblingsOnly, reverse) {
- if(node)
- {
- node = reverse ? node.lastChild : node.firstChild;
-
- while(node != null)
- {
- if(!innermostFirst && func(node) === false)
- return false;
-
- // traverse all children
- if(!siblingsOnly && this.traverse(node, func, innermostFirst, siblingsOnly, reverse) === false)
- return false;
-
- if(innermostFirst && func(node) === false)
- return false;
-
- // move to next child
- node = reverse ? node.previousSibling : node.nextSibling;
- }
- }
- },
-
- rTraverse: function(node, func, innermostFirst, siblingsOnly) {
- this.traverse(node, func, innermostFirst, siblingsOnly, true);
- },
-
- /**
- * Checks if an element is inline
- *
- * @param bool includeInlineBlock If passed inline-block will count as an inline element instead of block
- * @return bool
- */
- isInline: function(elm, includeInlineBlock) {
- if(elm == null || elm.nodeType !== 1)
- return true;
-
- var d = (window.getComputedStyle ? window.getComputedStyle(elm) : elm.currentStyle).display;
- if(includeInlineBlock)
- return d !== "block";
-
- return d === "inline";
- },
-
- /**
- * Gets the next node. If the node has no siblings
- * it gets the parents next sibling, and so on untill
- * another element is found. If none are found
- * it returns null.
- *
- * @param HTMLElement node
- * @return HTMLElement
- */
- /*getNext: function(node) {
- if(!node)
- return null;
-
- var n = node.nextSibling;
- if(n)
- return n;
-
- return getNext(node.parentNode);
- },*/
-
- copyCSS: function(from, to) {
- to.style.cssText = from.style.cssText;
- },
-
- /**
- * Fixes block level elements in inline elements.
- *
- * @param HTMLElement The node to fix
- */
- fixNesting: function(node) {
- var base = this,
- getLastInlineParent = function(node) {
- while(base.isInline(node.parentNode))
- node = node.parentNode;
-
- return node;
- };
-
- base.traverse(node, function(node) {
- // if node is an element, and is blocklevel and the parent isn't block level
- // then it needs fixing
- if(node.nodeType === 1 && !base.isInline(node) && base.isInline(node.parentNode))
- {
- var parent = getLastInlineParent(node),
- rParent = parent.parentNode,
- before = base.extractContents(parent, node),
- middle = node;
-
- // copy current styling so when moved out of the parent
- // it still has the same styling
- base.copyCSS(middle, middle);
-
- rParent.insertBefore(before, parent);
- rParent.insertBefore(middle, parent);
- }
- });
- },
-
- /**
- * Finds the common parent of two nodes
- *
- * @param HTMLElement node1
- * @param HTMLElement node2
- * @return HTMLElement
- */
- findCommonAncestor: function(node1, node2) {
- // not as fast as making two arrays of parents and comparing
- // but is a lot smaller and as it's currently only used with
- // fixing invalid nesting it doesn't need to be very fast
- return $(node1).parents().has($(node2)).first();
- },
-
- /**
- * Removes unused whitespace from the root and it's children
- *
- * @param HTMLElement root
- * @return void
- */
- removeWhiteSpace: function(root) {
- // 00A0 is non-breaking space which should not be striped
- var regex = /[^\S|\u00A0]+/g;
- this.traverse(root, function(node) {
- if(node.nodeType === 3 && $(node).parents('code, pre').length === 0)
- {
- if(!/\S|\u00A0/.test(node.nodeValue))
- node.nodeValue = " ";
- else if(regex.test(node.nodeValue))
- node.nodeValue = node.nodeValue.replace(regex, " ");
- }
- });
- },
-
- /**
- * Extracts all the nodes between the start and end nodes
- *
- * @param HTMLElement startNode The node to start extracting at
- * @param HTMLElement endNode The node to stop extracting at
- * @return DocumentFragment
- */
- extractContents: function(startNode, endNode) {
- var base = this,
- $commonAncestor = base.findCommonAncestor(startNode, endNode),
- commonAncestor = $commonAncestor===null?null:$commonAncestor.get(0),
- startReached = false,
- endReached = false;
- return (function extract(root) {
- var df = startNode.ownerDocument.createDocumentFragment();
-
- base.traverse(root, function(node) {
- // if end has been reached exit loop
- if(endReached || (node === endNode && startReached))
- {
- endReached = true;
- return false;
- }
- if(node === startNode)
- startReached = true;
- var c, n;
- if(startReached)
- {
- // if the start has been reached and this elm contains
- // the end node then clone it
- if(jQuery.contains(node, endNode) && node.nodeType === 1)
- {
- c = extract(node);
- n = node.cloneNode(false);
- n.appendChild(c);
- df.appendChild(n);
- }
- // otherwise just move it
- else
- df.appendChild(node);
- }
- // if this node contains the start node then add it
- else if(jQuery.contains(node, startNode) && node.nodeType === 1)
- {
- c = extract(node);
- n = node.cloneNode(false);
- n.appendChild(c);
- df.appendChild(n);
- }
- });
- return df;
- }(commonAncestor));
- }
- };
-
- /**
- * Checks if a command with the specified name exists
- *
- * @param {String} name
- * @return Bool
- */
- $.sceditor.commandExists = function(name) {
- return typeof $.sceditor.commands[name] !== "undefined";
- };
-
- /**
- * Adds/updates a command.
- *
- * Only name and exec are required. Exec is only required if
- * the command dose not already exist.
- *
- * @param {String} name The commands name
- * @param {String|Function} exec The commands exec function or string for the native execCommand
- * @param {String} tooltip The commands tooltip text
- * @param {Function} keypress Function that gets called every time a key is pressed
- * @param {Function|Array} txtExec Called when the command is executed in source mode or array containing prepend and optional append
- * @return Bool
- */
- $.sceditor.setCommand = function(name, exec, tooltip, keypress, txtExec) {
- if(!name || !($.sceditor.commandExists(name) || exec))
- return false;
- if(!$.sceditor.commandExists(name))
- $.sceditor.commands[name] = {};
- $.sceditor.commands[name].exec = exec;
- if(tooltip)
- $.sceditor.commands[name].tooltip = tooltip;
- if(keypress)
- $.sceditor.commands[name].keyPress = keypress;
-
- if(txtExec)
- $.sceditor.commands[name].txtExec = txtExec;
- return true;
- };
-
- $.sceditor.defaultOptions = {
- // Toolbar buttons order and groups. Should be comma seperated and have a bar | to seperate groups
- toolbar: "bold,italic,underline,strike,subscript,superscript|left,center,right,justify|" +
- "font,size,color,removeformat|cut,copy,paste,pastetext|bulletlist,orderedlist|" +
- "table|code,quote|horizontalrule,image,email,link,unlink|emoticon,youtube,date,time|" +
- "print,source",
- // Stylesheet to include in the WYSIWYG editor. Will style the WYSIWYG elements
- style: "jquery.sceditor.default.css",
- // Comma seperated list of fonts for the font selector
- fonts: "Arial,Arial Black,Comic Sans MS,Courier New,Georgia,Impact,Sans-serif,Serif,Times New Roman,Trebuchet MS,Verdana",
- // Colors should be comma seperated and have a bar | to signal a new column. If null the colors will be auto generated.
- colors: null,
-
- locale: "en",
-
- charset: "utf-8",
- // compatibility mode for if you have emoticons such as :/ This mode requires
- // emoticons to be surrounded by whitespace or end of line chars. This mode
- // has limited As You Type emoticon converstion support (end of line chars)
- // are not accepted as whitespace so only emoticons surrounded by whitespace
- // will work
- emoticonsCompat: false,
- emoticonsRoot: '',
- emoticons: {
- dropdown: {
- ":)": "emoticons/smile.png",
- ":angel:": "emoticons/angel.png",
- ":angry:": "emoticons/angry.png",
- "8-)": "emoticons/cool.png",
- ":'(": "emoticons/cwy.png",
- ":ermm:": "emoticons/ermm.png",
- ":D": "emoticons/grin.png",
- "<3": "emoticons/heart.png",
- ":(": "emoticons/sad.png",
- ":O": "emoticons/shocked.png",
- ":P": "emoticons/tongue.png",
- ";)": "emoticons/wink.png"
- },
- more: {
- ":alien:": "emoticons/alien.png",
- ":blink:": "emoticons/blink.png",
- ":blush:": "emoticons/blush.png",
- ":cheerful:": "emoticons/cheerful.png",
- ":devil:": "emoticons/devil.png",
- ":dizzy:": "emoticons/dizzy.png",
- ":getlost:": "emoticons/getlost.png",
- ":happy:": "emoticons/happy.png",
- ":kissing:": "emoticons/kissing.png",
- ":ninja:": "emoticons/ninja.png",
- ":pinch:": "emoticons/pinch.png",
- ":pouty:": "emoticons/pouty.png",
- ":sick:": "emoticons/sick.png",
- ":sideways:": "emoticons/sideways.png",
- ":silly:": "emoticons/silly.png",
- ":sleeping:": "emoticons/sleeping.png",
- ":unsure:": "emoticons/unsure.png",
- ":woot:": "emoticons/w00t.png",
- ":wassat:": "emoticons/wassat.png"
- },
- hidden: {
- ":whistling:": "emoticons/whistling.png",
- ":love:": "emoticons/wub.png"
- }
- },
- // Width of the editor. Set to null for automatic with
- width: null,
- // Height of the editor including toolbat. Set to null for automatic height
- height: null,
- // If to allow the editor to be resized
- resizeEnabled: true,
- // Min resize to width, set to null for half textarea width or -1 for unlimited
- resizeMinWidth: null,
- // Min resize to height, set to null for half textarea height or -1 for unlimited
- resizeMinHeight: null,
- // Max resize to height, set to null for double textarea height or -1 for unlimited
- resizeMaxHeight: null,
- // Max resize to width, set to null for double textarea width or -1 for unlimited
- resizeMaxWidth: null,
- getHtmlHandler: null,
- getTextHandler: null,
-
- // date format. year, month and day will be replaced with the users current year, month and day.
- dateFormat: "year-month-day",
- toolbarContainer: null,
-
- enablePasteFiltering: false,
- //add css to dropdown menu (eg. z-index)
- dropDownCss: { }
- };
- $.fn.sceditor = function (options) {
- return this.each(function () {
- (new $.sceditor(this, options));
- });
- };
- })(jQuery);
- (function($) {
- var extensionMethods = {
- InsertText: function(text, bClear) {
- var bIsSource = this.inSourceMode();
- // @TODO make it put the quote close to the current selection
- if (!bIsSource)
- this.toggleTextMode();
- var current_value = bClear ? text + "\n" : this.getTextareaValue(false) + "\n" + text + "\n";
- this.setTextareaValue(current_value);
- if (!bIsSource)
- this.toggleTextMode();
- },
- getText: function() {
- if(this.inSourceMode())
- var current_value = this.getTextareaValue(false);
- else
- var current_value = this.getWysiwygEditorValue();
- return current_value;
- },
- appendEmoticon: function (code, emoticon) {
- if (code == '')
- line.append($('<br />'));
- else
- line.append($('<img />')
- .attr({
- src: emoticon,
- alt: code,
- })
- .click(function (e) {
- var start = '', end = '';
-
- if (base.options.emoticonsCompat)
- {
- start = '<span> ';
- end = ' </span>';
- }
- if (base.inSourceMode())
- base.textEditorInsertText(' ' + $(this).attr('alt') + ' ');
- else
- base.wysiwygEditorInsertHtml(start + '<img src="' + $(this).attr("src") +
- '" data-sceditor-emoticon="' + $(this).attr('alt') + '" />' + end);
- e.preventDefault();
- })
- );
- if (line.children().length > 0)
- content.append(line);
- $(".sceditor-toolbar").append(content);
- },
- storeLastState: function (){
- this.wasSource = this.inSourceMode();
- },
- setTextMode: function () {
- if (!this.inSourceMode())
- this.toggleTextMode();
- },
- createPermanentDropDown: function() {
- var emoticons = $.extend({}, this.options.emoticons.dropdown);
- var popup_exists = false;
- content = $('<div />').attr({class: "sceditor-insertemoticon"});
- line = $('<div />');
- base = this;
- for (smiley_popup in this.options.emoticons.popup)
- {
- popup_exists = true;
- break;
- }
- if (popup_exists)
- {
- this.options.emoticons.more = this.options.emoticons.popup;
- moreButton = $('<div />').attr({class: "sceditor-more"}).text('[' + this._('More') + ']').click(function () {
- if ($(".sceditor-smileyPopup").length > 0)
- {
- $(".sceditor-smileyPopup").fadeIn('fast');
- }
- else
- {
- var emoticons = $.extend({}, base.options.emoticons.popup);
- var basement = $('<div />').attr({class: "sceditor-popup"});
- allowHide = true;
- popupContent = $('<div />');
- line = $('<div />');
- closeButton = $('<span />').text('[' + base._('Close') + ']').click(function () {
- $(".sceditor-smileyPopup").fadeOut('fast');
- });
- $.each(emoticons, base.appendEmoticon);
- if (line.children().length > 0)
- popupContent.append(line);
- if (typeof closeButton !== "undefined")
- popupContent.append(closeButton);
- // IE needs unselectable attr to stop it from unselecting the text in the editor.
- // The editor can cope if IE does unselect the text it's just not nice.
- if(base.ieUnselectable !== false) {
- content = $(content);
- content.find(':not(input,textarea)').filter(function() { return this.nodeType===1; }).attr('unselectable', 'on');
- }
- $dropdown = $('<div class="sceditor-dropdown sceditor-smileyPopup" />').append(popupContent);
- $dropdown.appendTo($('body'));
- dropdownIgnoreLastClick = true;
- $dropdown.css({
- position: "fixed",
- top: $(window).height() * 0.2,
- left: $(window).width() * 0.5 - ($dropdown.width() / 2),
- "max-width": "50%"
- });
- // stop clicks within the dropdown from being handled
- $dropdown.click(function (e) {
- e.stopPropagation();
- });
- }
- });
- }
- $.each(emoticons, base.appendEmoticon);
- if (typeof moreButton !== "undefined")
- content.append(moreButton);
- }
- };
- $.extend(true, $['sceditor'].prototype, extensionMethods);
- })(jQuery);
- $.sceditor.setCommand(
- 'ftp',
- function (caller) {
- var editor = this,
- content = $(this._('<form><div><label for="link">{0}</label> <input type="text" id="link" value="ftp://" /></div>' +
- '<div><label for="des">{1}</label> <input type="text" id="des" value="" /></div></form>',
- this._("URL:"),
- this._("Description (optional):")
- ))
- .submit(function () {return false;});
- content.append($(
- this._('<div><input type="button" class="button" value="{0}" /></div>',
- this._("Insert")
- )).click(function (e) {
- var val = $(this).parent("form").find("#link").val(),
- description = $(this).parent("form").find("#des").val();
- if(val !== "" && val !== "ftp://") {
- // needed for IE to reset the last range
- editor.focus();
- if(!editor.getRangeHelper().selectedHtml() || description)
- {
- if(!description)
- description = val;
-
- editor.wysiwygEditorInsertHtml('<a href="' + val + '">' + description + '</a>');
- }
- else
- editor.execCommand("createlink", val);
- }
- editor.closeDropDown(true);
- e.preventDefault();
- }));
- editor.createDropDown(caller, "insertlink", content);
- },
- 'Insert FTP Link'
- );
- $.sceditor.setCommand(
- 'glow',
- function () {
- this.wysiwygEditorInsertHtml('[glow=red,2,300]', '[/glow]');
- },
- 'Glow'
- );
- $.sceditor.setCommand(
- 'shadow',
- function () {
- this.wysiwygEditorInsertHtml('[shadow=red,left]', '[/shadow]');
- },
- 'Shadow'
- );
- $.sceditor.setCommand(
- 'tt',
- function () {
- this.wysiwygEditorInsertHtml('<tt>', '</tt>');
- },
- 'Teletype'
- );
|