1 | | (function(e){var a=/^\s*|\s*$/g,b,d="B".replace(/A(.)|B/,"$1")==="$1";var c={majorVersion:"3",minorVersion:"5.9",releaseDate:"2013-10-18",_init:function(){var s=this,q=document,o=navigator,g=o.userAgent,m,f,l,k,j,r;s.isIE11=g.indexOf("Trident/")!=-1&&(g.indexOf("rv:")!=-1||o.appName.indexOf("Netscape")!=-1);s.isOpera=e.opera&&opera.buildNumber;s.isWebKit=/WebKit/.test(g);s.isIE=!s.isWebKit&&!s.isOpera&&(/MSIE/gi).test(g)&&(/Explorer/gi).test(o.appName)||s.isIE11;s.isIE6=s.isIE&&/MSIE [56]/.test(g);s.isIE7=s.isIE&&/MSIE [7]/.test(g);s.isIE8=s.isIE&&/MSIE [8]/.test(g);s.isIE9=s.isIE&&/MSIE [9]/.test(g);s.isGecko=!s.isWebKit&&!s.isIE11&&/Gecko/.test(g);s.isMac=g.indexOf("Mac")!=-1;s.isAir=/adobeair/i.test(g);s.isIDevice=/(iPad|iPhone)/.test(g);s.isIOS5=s.isIDevice&&g.match(/AppleWebKit\/(\d*)/)[1]>=534;if(e.tinyMCEPreInit){s.suffix=tinyMCEPreInit.suffix;s.baseURL=tinyMCEPreInit.base;s.query=tinyMCEPreInit.query;return}s.suffix="";f=q.getElementsByTagName("base");for(m=0;m<f.length;m++){r=f[m].href;if(r){if(/^https?:\/\/[^\/]+$/.test(r)){r+="/"}k=r?r.match(/.*\//)[0]:""}}function h(i){if(i.src&&/tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(i.src)){if(/_(src|dev)\.js/g.test(i.src)){s.suffix="_src"}if((j=i.src.indexOf("?"))!=-1){s.query=i.src.substring(j+1)}s.baseURL=i.src.substring(0,i.src.lastIndexOf("/"));if(k&&s.baseURL.indexOf("://")==-1&&s.baseURL.indexOf("/")!==0){s.baseURL=k+s.baseURL}return s.baseURL}return null}f=q.getElementsByTagName("script");for(m=0;m<f.length;m++){if(h(f[m])){return}}l=q.getElementsByTagName("head")[0];if(l){f=l.getElementsByTagName("script");for(m=0;m<f.length;m++){if(h(f[m])){return}}}return},is:function(g,f){if(!f){return g!==b}if(f=="array"&&c.isArray(g)){return true}return typeof(g)==f},isArray:Array.isArray||function(f){return Object.prototype.toString.call(f)==="[object Array]"},makeMap:function(f,j,h){var g;f=f||[];j=j||",";if(typeof(f)=="string"){f=f.split(j)}h=h||{};g=f.length;while(g--){h[f[g]]={}}return h},each:function(i,f,h){var j,g;if(!i){return 0}h=h||i;if(i.length!==b){for(j=0,g=i.length;j<g;j++){if(f.call(h,i[j],j,i)===false){return 0}}}else{for(j in i){if(i.hasOwnProperty(j)){if(f.call(h,i[j],j,i)===false){return 0}}}}return 1},map:function(g,h){var i=[];c.each(g,function(f){i.push(h(f))});return i},grep:function(g,h){var i=[];c.each(g,function(f){if(!h||h(f)){i.push(f)}});return i},inArray:function(g,h){var j,f;if(g){for(j=0,f=g.length;j<f;j++){if(g[j]===h){return j}}}return -1},extend:function(n,k){var j,f,h,g=arguments,m;for(j=1,f=g.length;j<f;j++){k=g[j];for(h in k){if(k.hasOwnProperty(h)){m=k[h];if(m!==b){n[h]=m}}}}return n},trim:function(f){return(f?""+f:"").replace(a,"")},create:function(o,f,j){var n=this,g,i,k,l,h,m=0;o=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(o);k=o[3].match(/(^|\.)(\w+)$/i)[2];i=n.createNS(o[3].replace(/\.\w+$/,""),j);if(i[k]){return}if(o[2]=="static"){i[k]=f;if(this.onCreate){this.onCreate(o[2],o[3],i[k])}return}if(!f[k]){f[k]=function(){};m=1}i[k]=f[k];n.extend(i[k].prototype,f);if(o[5]){g=n.resolve(o[5]).prototype;l=o[5].match(/\.(\w+)$/i)[1];h=i[k];if(m){i[k]=function(){return g[l].apply(this,arguments)}}else{i[k]=function(){this.parent=g[l];return h.apply(this,arguments)}}i[k].prototype[k]=i[k];n.each(g,function(p,q){i[k].prototype[q]=g[q]});n.each(f,function(p,q){if(g[q]){i[k].prototype[q]=function(){this.parent=g[q];return p.apply(this,arguments)}}else{if(q!=k){i[k].prototype[q]=p}}})}n.each(f["static"],function(p,q){i[k][q]=p});if(this.onCreate){this.onCreate(o[2],o[3],i[k].prototype)}},walk:function(i,h,j,g){g=g||this;if(i){if(j){i=i[j]}c.each(i,function(k,f){if(h.call(g,k,f,j)===false){return false}c.walk(k,h,j,g)})}},createNS:function(j,h){var g,f;h=h||e;j=j.split(".");for(g=0;g<j.length;g++){f=j[g];if(!h[f]){h[f]={}}h=h[f]}return h},resolve:function(j,h){var g,f;h=h||e;j=j.split(".");for(g=0,f=j.length;g<f;g++){h=h[j[g]];if(!h){break}}return h},addUnload:function(j,i){var h=this,g;g=function(){var f=h.unloads,l,m;if(f){for(m in f){l=f[m];if(l&&l.func){l.func.call(l.scope,1)}}if(e.detachEvent){e.detachEvent("onbeforeunload",k);e.detachEvent("onunload",g)}else{if(e.removeEventListener){e.removeEventListener("unload",g,false)}}h.unloads=l=f=w=g=0;if(e.CollectGarbage){CollectGarbage()}}};function k(){var l=document;function f(){l.detachEvent("onstop",f);if(g){g()}l=0}if(l.readyState=="interactive"){if(l){l.attachEvent("onstop",f)}e.setTimeout(function(){if(l){l.detachEvent("onstop",f)}},0)}}j={func:j,scope:i||this};if(!h.unloads){if(e.attachEvent){e.attachEvent("onunload",g);e.attachEvent("onbeforeunload",k)}else{if(e.addEventListener){e.addEventListener("unload",g,false)}}h.unloads=[j]}else{h.unloads.push(j)}return j},removeUnload:function(i){var g=this.unloads,h=null;c.each(g,function(j,f){if(j&&j.func==i){g.splice(f,1);h=i;return false}});return h},explode:function(f,g){if(!f||c.is(f,"array")){return f}return c.map(f.split(g||","),c.trim)},_addVer:function(g){var f;if(!this.query){return g}f=(g.indexOf("?")==-1?"?":"&")+this.query;if(g.indexOf("#")==-1){return g+f}return g.replace("#",f+"#")},_replace:function(h,f,g){if(d){return g.replace(h,function(){var l=f,j=arguments,k;for(k=0;k<j.length-2;k++){if(j[k]===b){l=l.replace(new RegExp("\\$"+k,"g"),"")}else{l=l.replace(new RegExp("\\$"+k,"g"),j[k])}}return l})}return g.replace(h,f)}};c._init();e.tinymce=e.tinyMCE=c})(window);tinymce.create("tinymce.util.Dispatcher",{scope:null,listeners:null,inDispatch:false,Dispatcher:function(a){this.scope=a||this;this.listeners=[]},add:function(b,a){this.listeners.push({cb:b,scope:a||this.scope});return b},addToTop:function(d,b){var a=this,c={cb:d,scope:b||a.scope};if(a.inDispatch){a.listeners=[c].concat(a.listeners)}else{a.listeners.unshift(c)}return d},remove:function(c){var b=this.listeners,a=null;tinymce.each(b,function(e,d){if(c==e.cb){a=e;b.splice(d,1);return false}});return a},dispatch:function(){var a=this,e,b=arguments,c,d=a.listeners,f;a.inDispatch=true;for(c=0;c<d.length;c++){f=d[c];e=f.cb.apply(f.scope,b.length>0?b:[f.scope]);if(e===false){break}}a.inDispatch=false;return e}});(function(){var a=tinymce.each;tinymce.create("tinymce.util.URI",{URI:function(e,g){var f=this,i,d,c,h;e=tinymce.trim(e);g=f.settings=g||{};if(/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e)){f.source=e;return}if(e.indexOf("/")===0&&e.indexOf("//")!==0){e=(g.base_uri?g.base_uri.protocol||"http":"http")+"://mce_host"+e}if(!/^[\w\-]*:?\/\//.test(e)){h=g.base_uri?g.base_uri.path:new tinymce.util.URI(location.href).directory;e=((g.base_uri&&g.base_uri.protocol)||"http")+"://mce_host"+f.toAbsPath(h,e)}e=e.replace(/@@/g,"(mce_at)");e=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e);a(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(b,j){var k=e[j];if(k){k=k.replace(/\(mce_at\)/g,"@@")}f[b]=k});c=g.base_uri;if(c){if(!f.protocol){f.protocol=c.protocol}if(!f.userInfo){f.userInfo=c.userInfo}if(!f.port&&f.host==="mce_host"){f.port=c.port}if(!f.host||f.host==="mce_host"){f.host=c.host}f.source=""}},setPath:function(c){var b=this;c=/^(.*?)\/?(\w+)?$/.exec(c);b.path=c[0];b.directory=c[1];b.file=c[2];b.source="";b.getURI()},toRelative:function(b){var d=this,f;if(b==="./"){return b}b=new tinymce.util.URI(b,{base_uri:d});if((b.host!="mce_host"&&d.host!=b.host&&b.host)||d.port!=b.port||d.protocol!=b.protocol){return b.getURI()}var c=d.getURI(),e=b.getURI();if(c==e||(c.charAt(c.length-1)=="/"&&c.substr(0,c.length-1)==e)){return c}f=d.toRelPath(d.path,b.path);if(b.query){f+="?"+b.query}if(b.anchor){f+="#"+b.anchor}return f},toAbsolute:function(b,c){b=new tinymce.util.URI(b,{base_uri:this});return b.getURI(this.host==b.host&&this.protocol==b.protocol?c:0)},toRelPath:function(g,h){var c,f=0,d="",e,b;g=g.substring(0,g.lastIndexOf("/"));g=g.split("/");c=h.split("/");if(g.length>=c.length){for(e=0,b=g.length;e<b;e++){if(e>=c.length||g[e]!=c[e]){f=e+1;break}}}if(g.length<c.length){for(e=0,b=c.length;e<b;e++){if(e>=g.length||g[e]!=c[e]){f=e+1;break}}}if(f===1){return h}for(e=0,b=g.length-(f-1);e<b;e++){d+="../"}for(e=f-1,b=c.length;e<b;e++){if(e!=f-1){d+="/"+c[e]}else{d+=c[e]}}return d},toAbsPath:function(e,f){var c,b=0,h=[],d,g;d=/\/$/.test(f)?"/":"";e=e.split("/");f=f.split("/");a(e,function(i){if(i){h.push(i)}});e=h;for(c=f.length-1,h=[];c>=0;c--){if(f[c].length===0||f[c]==="."){continue}if(f[c]===".."){b++;continue}if(b>0){b--;continue}h.push(f[c])}c=e.length-b;if(c<=0){g=h.reverse().join("/")}else{g=e.slice(0,c).join("/")+"/"+h.reverse().join("/")}if(g.indexOf("/")!==0){g="/"+g}if(d&&g.lastIndexOf("/")!==g.length-1){g+=d}return g},getURI:function(d){var c,b=this;if(!b.source||d){c="";if(!d){if(b.protocol){c+=b.protocol+"://"}if(b.userInfo){c+=b.userInfo+"@"}if(b.host){c+=b.host}if(b.port){c+=":"+b.port}}if(b.path){c+=b.path}if(b.query){c+="?"+b.query}if(b.anchor){c+="#"+b.anchor}b.source=c}return b.source}})})();(function(){var a=tinymce.each;tinymce.create("static tinymce.util.Cookie",{getHash:function(d){var b=this.get(d),c;if(b){a(b.split("&"),function(e){e=e.split("=");c=c||{};c[unescape(e[0])]=unescape(e[1])})}return c},setHash:function(j,b,g,f,i,c){var h="";a(b,function(e,d){h+=(!h?"":"&")+escape(d)+"="+escape(e)});this.set(j,h,g,f,i,c)},get:function(i){var h=document.cookie,g,f=i+"=",d;if(!h){return}d=h.indexOf("; "+f);if(d==-1){d=h.indexOf(f);if(d!==0){return null}}else{d+=2}g=h.indexOf(";",d);if(g==-1){g=h.length}return unescape(h.substring(d+f.length,g))},set:function(i,b,g,f,h,c){document.cookie=i+"="+escape(b)+((g)?"; expires="+g.toGMTString():"")+((f)?"; path="+escape(f):"")+((h)?"; domain="+h:"")+((c)?"; secure":"")},remove:function(c,e,d){var b=new Date();b.setTime(b.getTime()-1000);this.set(c,"",b,e,d)}})})();(function(){function serialize(o,quote){var i,v,t,name;quote=quote||'"';if(o==null){return"null"}t=typeof o;if(t=="string"){v="\bb\tt\nn\ff\rr\"\"''\\\\";return quote+o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(a,b){if(quote==='"'&&a==="'"){return a}i=v.indexOf(b);if(i+1){return"\\"+v.charAt(i+1)}a=b.charCodeAt().toString(16);return"\\u"+"0000".substring(a.length)+a})+quote}if(t=="object"){if(o.hasOwnProperty&&Object.prototype.toString.call(o)==="[object Array]"){for(i=0,v="[";i<o.length;i++){v+=(i>0?",":"")+serialize(o[i],quote)}return v+"]"}v="{";for(name in o){if(o.hasOwnProperty(name)){v+=typeof o[name]!="function"?(v.length>1?","+quote:quote)+name+quote+":"+serialize(o[name],quote):""}}return v+"}"}return""+o}tinymce.util.JSON={serialize:serialize,parse:function(s){try{return eval("("+s+")")}catch(ex){}}}})();tinymce.create("static tinymce.util.XHR",{send:function(g){var a,e,b=window,h=0;function f(){if(!g.async||a.readyState==4||h++>10000){if(g.success&&h<10000&&a.status==200){g.success.call(g.success_scope,""+a.responseText,a,g)}else{if(g.error){g.error.call(g.error_scope,h>10000?"TIMED_OUT":"GENERAL",a,g)}}a=null}else{b.setTimeout(f,10)}}g.scope=g.scope||this;g.success_scope=g.success_scope||g.scope;g.error_scope=g.error_scope||g.scope;g.async=g.async===false?false:true;g.data=g.data||"";function d(i){a=0;try{a=new ActiveXObject(i)}catch(c){}return a}a=b.XMLHttpRequest?new XMLHttpRequest():d("Microsoft.XMLHTTP")||d("Msxml2.XMLHTTP");if(a){if(a.overrideMimeType){a.overrideMimeType(g.content_type)}a.open(g.type||(g.data?"POST":"GET"),g.url,g.async);if(g.content_type){a.setRequestHeader("Content-Type",g.content_type)}a.setRequestHeader("X-Requested-With","XMLHttpRequest");a.send(g.data);if(!g.async){return f()}e=b.setTimeout(f,10)}}});(function(){var c=tinymce.extend,b=tinymce.util.JSON,a=tinymce.util.XHR;tinymce.create("tinymce.util.JSONRequest",{JSONRequest:function(d){this.settings=c({},d);this.count=0},send:function(f){var e=f.error,d=f.success;f=c(this.settings,f);f.success=function(h,g){h=b.parse(h);if(typeof(h)=="undefined"){h={error:"JSON Parse error."}}if(h.error){e.call(f.error_scope||f.scope,h.error,g)}else{d.call(f.success_scope||f.scope,h.result)}};f.error=function(h,g){if(e){e.call(f.error_scope||f.scope,h,g)}};f.data=b.serialize({id:f.id||"c"+(this.count++),method:f.method,params:f.params});f.content_type="application/json";a.send(f)},"static":{sendRPC:function(d){return new tinymce.util.JSONRequest().send(d)}}})}());(function(a){a.VK={BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(b){return b.shiftKey||b.ctrlKey||b.altKey},metaKeyPressed:function(b){return a.isMac?b.metaKey:b.ctrlKey&&!b.altKey}}})(tinymce);tinymce.util.Quirks=function(a){var j=tinymce.VK,f=j.BACKSPACE,k=j.DELETE,e=a.dom,m=a.selection,I=a.settings,x=a.parser,p=a.serializer,F=tinymce.each;function B(O,N){try{a.getDoc().execCommand(O,false,N)}catch(M){}}function o(){var M=a.getDoc().documentMode;return M?M:6}function A(M){return M.isDefaultPrevented()}function K(){function M(S){var O,Q,N,T,P,R,U;function V(){if(P.nodeType==3){if(S&&R==P.length){return true}if(!S&&R===0){return true}}}O=m.getRng();var W=[O.startContainer,O.startOffset,O.endContainer,O.endOffset];if(!O.collapsed){S=true}P=O[(S?"start":"end")+"Container"];R=O[(S?"start":"end")+"Offset"];if(P.nodeType==3){Q=e.getParent(O.startContainer,e.isBlock);if(S){Q=e.getNext(Q,e.isBlock)}if(Q&&(V()||!O.collapsed)){N=e.create("em",{id:"__mceDel"});F(tinymce.grep(Q.childNodes),function(X){N.appendChild(X)});Q.appendChild(N)}}O=e.createRng();O.setStart(W[0],W[1]);O.setEnd(W[2],W[3]);m.setRng(O);a.getDoc().execCommand(S?"ForwardDelete":"Delete",false,null);if(N){T=m.getBookmark();while(U=e.get("__mceDel")){e.remove(U,true)}m.moveToBookmark(T)}}a.onKeyDown.add(function(N,P){var O;O=P.keyCode==k;if(!A(P)&&(O||P.keyCode==f)&&!j.modifierPressed(P)){P.preventDefault();M(O)}});a.addCommand("Delete",function(){M()})}function r(){function M(P){var O=e.create("body");var Q=P.cloneContents();O.appendChild(Q);return m.serializer.serialize(O,{format:"html"})}function N(O){var Q=M(O);var R=e.createRng();R.selectNode(a.getBody());var P=M(R);return Q===P}a.onKeyDown.add(function(P,R){var Q=R.keyCode,O;if(!A(R)&&(Q==k||Q==f)){O=P.selection.isCollapsed();if(O&&!e.isEmpty(P.getBody())){return}if(tinymce.isIE&&!O){return}if(!O&&!N(P.selection.getRng())){return}P.setContent("");P.selection.setCursorLocation(P.getBody(),0);P.nodeChanged()}})}function J(){a.onKeyDown.add(function(M,N){if(!A(N)&&N.keyCode==65&&j.metaKeyPressed(N)){N.preventDefault();M.execCommand("SelectAll")}})}function L(){if(!a.settings.content_editable){e.bind(a.getDoc(),"focusin",function(M){m.setRng(m.getRng())});e.bind(a.getDoc(),"mousedown",function(M){if(M.target==a.getDoc().documentElement){a.getWin().focus();m.setRng(m.getRng())}})}}function C(){a.onKeyDown.add(function(M,P){if(!A(P)&&P.keyCode===f){if(m.isCollapsed()&&m.getRng(true).startOffset===0){var O=m.getNode();var N=O.previousSibling;if(N&&N.nodeName&&N.nodeName.toLowerCase()==="hr"){e.remove(N);tinymce.dom.Event.cancel(P)}}}})}function z(){if(!Range.prototype.getClientRects){a.onMouseDown.add(function(N,O){if(!A(O)&&O.target.nodeName==="HTML"){var M=N.getBody();M.blur();setTimeout(function(){M.focus()},0)}})}}function h(){a.onClick.add(function(M,N){N=N.target;if(/^(IMG|HR)$/.test(N.nodeName)){m.getSel().setBaseAndExtent(N,0,N,1)}if(N.nodeName=="A"&&e.hasClass(N,"mceItemAnchor")){m.select(N)}M.nodeChanged()})}function c(){function N(){var P=e.getAttribs(m.getStart().cloneNode(false));return function(){var Q=m.getStart();if(Q!==a.getBody()){e.setAttrib(Q,"style",null);F(P,function(R){Q.setAttributeNode(R.cloneNode(true))})}}}function M(){return !m.isCollapsed()&&e.getParent(m.getStart(),e.isBlock)!=e.getParent(m.getEnd(),e.isBlock)}function O(P,Q){Q.preventDefault();return false}a.onKeyPress.add(function(P,R){var Q;if(!A(R)&&(R.keyCode==8||R.keyCode==46)&&M()){Q=N();P.getDoc().execCommand("delete",false,null);Q();R.preventDefault();return false}});e.bind(a.getDoc(),"cut",function(Q){var P;if(!A(Q)&&M()){P=N();a.onKeyUp.addToTop(O);setTimeout(function(){P();a.onKeyUp.remove(O)},0)}})}function b(){var N,M;e.bind(a.getDoc(),"selectionchange",function(){if(M){clearTimeout(M);M=0}M=window.setTimeout(function(){var O=m.getRng();if(!N||!tinymce.dom.RangeUtils.compareRanges(O,N)){a.nodeChanged();N=O}},50)})}function y(){document.body.setAttribute("role","application")}function u(){a.onKeyDown.add(function(M,O){if(!A(O)&&O.keyCode===f){if(m.isCollapsed()&&m.getRng(true).startOffset===0){var N=m.getNode().previousSibling;if(N&&N.nodeName&&N.nodeName.toLowerCase()==="table"){return tinymce.dom.Event.cancel(O)}}}})}function D(){if(o()>7){return}B("RespectVisibilityInDesign",true);a.contentStyles.push(".mceHideBrInPre pre br {display: none}");e.addClass(a.getBody(),"mceHideBrInPre");x.addNodeFilter("pre",function(M,O){var P=M.length,R,N,S,Q;while(P--){R=M[P].getAll("br");N=R.length;while(N--){S=R[N];Q=S.prev;if(Q&&Q.type===3&&Q.value.charAt(Q.value-1)!="\n"){Q.value+="\n"}else{S.parent.insert(new tinymce.html.Node("#text",3),S,true).value="\n"}}}});p.addNodeFilter("pre",function(M,O){var P=M.length,R,N,S,Q;while(P--){R=M[P].getAll("br");N=R.length;while(N--){S=R[N];Q=S.prev;if(Q&&Q.type==3){Q.value=Q.value.replace(/\r?\n$/,"")}}}})}function g(){e.bind(a.getBody(),"mouseup",function(O){var N,M=m.getNode();if(M.nodeName=="IMG"){if(N=e.getStyle(M,"width")){e.setAttrib(M,"width",N.replace(/[^0-9%]+/g,""));e.setStyle(M,"width","")}if(N=e.getStyle(M,"height")){e.setAttrib(M,"height",N.replace(/[^0-9%]+/g,""));e.setStyle(M,"height","")}}})}function d(){a.onKeyDown.add(function(S,T){var R,M,N,P,Q,U,O;R=T.keyCode==k;if(!A(T)&&(R||T.keyCode==f)&&!j.modifierPressed(T)){M=m.getRng();N=M.startContainer;P=M.startOffset;O=M.collapsed;if(N.nodeType==3&&N.nodeValue.length>0&&((P===0&&!O)||(O&&P===(R?0:1)))){U=N.previousSibling;if(U&&U.nodeName=="IMG"){return}nonEmptyElements=S.schema.getNonEmptyElements();T.preventDefault();Q=e.create("br",{id:"__tmp"});N.parentNode.insertBefore(Q,N);S.getDoc().execCommand(R?"ForwardDelete":"Delete",false,null);N=m.getRng().startContainer;U=N.previousSibling;if(U&&U.nodeType==1&&!e.isBlock(U)&&e.isEmpty(U)&&!nonEmptyElements[U.nodeName.toLowerCase()]){e.remove(U)}e.remove("__tmp")}}})}function H(){a.onKeyDown.add(function(Q,R){var O,N,S,M,P;if(A(R)||R.keyCode!=j.BACKSPACE){return}O=m.getRng();N=O.startContainer;S=O.startOffset;M=e.getRoot();P=N;if(!O.collapsed||S!==0){return}while(P&&P.parentNode&&P.parentNode.firstChild==P&&P.parentNode!=M){P=P.parentNode}if(P.tagName==="BLOCKQUOTE"){Q.formatter.toggle("blockquote",null,P);O=e.createRng();O.setStart(N,0);O.setEnd(N,0);m.setRng(O)}})}function G(){function M(){a._refreshContentEditable();B("StyleWithCSS",false);B("enableInlineTableEditing",false);if(!I.object_resizing){B("enableObjectResizing",false)}}if(!I.readonly){a.onBeforeExecCommand.add(M);a.onMouseDown.add(M)}}function t(){function M(N,O){F(e.select("a"),function(R){var P=R.parentNode,Q=e.getRoot();if(P.lastChild===R){while(P&&!e.isBlock(P)){if(P.parentNode.lastChild!==P||P===Q){return}P=P.parentNode}e.add(P,"br",{"data-mce-bogus":1})}})}a.onExecCommand.add(function(N,O){if(O==="CreateLink"){M(N)}});a.onSetContent.add(m.onSetContent.add(M))}function n(){if(I.forced_root_block){a.onInit.add(function(){B("DefaultParagraphSeparator",I.forced_root_block)})}}function q(){function M(O,N){if(!O||!N.initial){a.execCommand("mceRepaint")}}a.onUndo.add(M);a.onRedo.add(M);a.onSetContent.add(M)}function i(){a.onKeyDown.add(function(N,O){var M;if(!A(O)&&O.keyCode==f){M=N.getDoc().selection.createRange();if(M&&M.item){O.preventDefault();N.undoManager.beforeChange();e.remove(M.item(0));N.undoManager.add()}}})}function s(){var M;if(o()>=10){M="";F("p div h1 h2 h3 h4 h5 h6".split(" "),function(N,O){M+=(O>0?",":"")+N+":empty"});a.contentStyles.push(M+"{padding-right: 1px !important}")}}function v(){var O,N,ae,M,Z,ac,aa,ad,P,Q,ab,X,W,Y=document,U=a.getDoc();if(!I.object_resizing||I.webkit_fake_resize===false){return}B("enableObjectResizing",false);ab={n:[0.5,0,0,-1],e:[1,0.5,1,0],s:[0.5,1,0,1],w:[0,0.5,-1,0],nw:[0,0,-1,-1],ne:[1,0,1,-1],se:[1,1,1,1],sw:[0,1,-1,1]};function S(ai){var ah,ag;ah=ai.screenX-ac;ag=ai.screenY-aa;X=ah*Z[2]+ad;W=ag*Z[3]+P;X=X<5?5:X;W=W<5?5:W;if(j.modifierPressed(ai)||(ae.nodeName=="IMG"&&Z[2]*Z[3]!==0)){X=Math.round(W/Q);W=Math.round(X*Q)}e.setStyles(M,{width:X,height:W});if(Z[2]<0&&M.clientWidth<=X){e.setStyle(M,"left",O+(ad-X))}if(Z[3]<0&&M.clientHeight<=W){e.setStyle(M,"top",N+(P-W))}}function af(){function ag(ah,ai){if(ai){if(ae.style[ah]||!a.schema.isValid(ae.nodeName.toLowerCase(),ah)){e.setStyle(ae,ah,ai)}else{e.setAttrib(ae,ah,ai)}}}ag("width",X);ag("height",W);e.unbind(U,"mousemove",S);e.unbind(U,"mouseup",af);if(Y!=U){e.unbind(Y,"mousemove",S);e.unbind(Y,"mouseup",af)}e.remove(M);R(ae)}function R(aj){var ah,ai,ag;T();ah=e.getPos(aj);O=ah.x;N=ah.y;ai=aj.offsetWidth;ag=aj.offsetHeight;if(ae!=aj){ae=aj;X=W=0}F(ab,function(am,ak){var al;al=e.get("mceResizeHandle"+ak);if(!al){al=e.add(U.documentElement,"div",{id:"mceResizeHandle"+ak,"class":"mceResizeHandle",style:"cursor:"+ak+"-resize; margin:0; padding:0"});e.bind(al,"mousedown",function(an){an.preventDefault();af();ac=an.screenX;aa=an.screenY;ad=ae.clientWidth;P=ae.clientHeight;Q=P/ad;Z=am;M=ae.cloneNode(true);e.addClass(M,"mceClonedResizable");e.setStyles(M,{left:O,top:N,margin:0});U.documentElement.appendChild(M);e.bind(U,"mousemove",S);e.bind(U,"mouseup",af);if(Y!=U){e.bind(Y,"mousemove",S);e.bind(Y,"mouseup",af)}})}else{e.show(al)}e.setStyles(al,{left:(ai*am[0]+O)-(al.offsetWidth/2),top:(ag*am[1]+N)-(al.offsetHeight/2)})});if(!tinymce.isOpera&&ae.nodeName=="IMG"){ae.setAttribute("data-mce-selected","1")}}function T(){if(ae){ae.removeAttribute("data-mce-selected")}for(var ag in ab){e.hide("mceResizeHandle"+ag)}}a.contentStyles.push(".mceResizeHandle {position: absolute;border: 1px solid black;background: #FFF;width: 5px;height: 5px;z-index: 10000}.mceResizeHandle:hover {background: #000}img[data-mce-selected] {outline: 1px solid black}img.mceClonedResizable, table.mceClonedResizable {position: absolute;outline: 1px dashed black;opacity: .5;z-index: 10000}");function V(){var ag=e.getParent(m.getNode(),"table,img");F(e.select("img[data-mce-selected]"),function(ah){ah.removeAttribute("data-mce-selected")});if(ag){R(ag)}else{T()}}a.onNodeChange.add(V);e.bind(U,"selectionchange",V);a.serializer.addAttributeFilter("data-mce-selected",function(ag,ah){var ai=ag.length;while(ai--){ag[ai].attr(ah,null)}})}function E(){if(o()<9){x.addNodeFilter("noscript",function(M){var N=M.length,O,P;while(N--){O=M[N];P=O.firstChild;if(P){O.attr("data-mce-innertext",P.value)}}});p.addNodeFilter("noscript",function(M){var N=M.length,O,Q,P;while(N--){O=M[N];Q=M[N].firstChild;if(Q){Q.value=tinymce.html.Entities.decode(Q.value)}else{P=O.attributes.map["data-mce-innertext"];if(P){O.attr("data-mce-innertext",null);Q=new tinymce.html.Node("#text",3);Q.value=P;Q.raw=true;O.append(Q)}}}})}}function l(){a.contentStyles.push("body {min-height: 100px}");a.onClick.add(function(M,N){if(N.target.nodeName=="HTML"){a.execCommand("SelectAll");a.selection.collapse(true);a.nodeChanged()}})}u();H();r();if(tinymce.isWebKit){d();K();L();h();n();if(tinymce.isIDevice){b()}else{v();J()}}if(tinymce.isIE&&!tinymce.isIE11){C();y();D();g();i();s();E()}if(tinymce.isIE11){l()}if(tinymce.isGecko&&!tinymce.isIE11){C();z();c();G();t();q()}if(tinymce.isOpera){v()}};(function(j){var a,g,d,k=/[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,b=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,f=/[<>&\"\']/g,c=/&(#x|#)?([\w]+);/g,i={128:"\u20AC",130:"\u201A",131:"\u0192",132:"\u201E",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02C6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017D",145:"\u2018",146:"\u2019",147:"\u201C",148:"\u201D",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02DC",153:"\u2122",154:"\u0161",155:"\u203A",156:"\u0153",158:"\u017E",159:"\u0178"};g={'"':""","'":"'","<":"<",">":">","&":"&"};d={"<":"<",">":">","&":"&",""":'"',"'":"'"};function h(l){var m;m=document.createElement("div");m.innerHTML=l;return m.textContent||m.innerText||l}function e(m,p){var n,o,l,q={};if(m){m=m.split(",");p=p||10;for(n=0;n<m.length;n+=2){o=String.fromCharCode(parseInt(m[n],p));if(!g[o]){l="&"+m[n+1]+";";q[o]=l;q[l]=o}}return q}}a=e("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);j.html=j.html||{};j.html.Entities={encodeRaw:function(m,l){return m.replace(l?k:b,function(n){return g[n]||n})},encodeAllRaw:function(l){return(""+l).replace(f,function(m){return g[m]||m})},encodeNumeric:function(m,l){return m.replace(l?k:b,function(n){if(n.length>1){return"&#"+(((n.charCodeAt(0)-55296)*1024)+(n.charCodeAt(1)-56320)+65536)+";"}return g[n]||"&#"+n.charCodeAt(0)+";"})},encodeNamed:function(n,l,m){m=m||a;return n.replace(l?k:b,function(o){return g[o]||m[o]||o})},getEncodeFunc:function(l,o){var p=j.html.Entities;o=e(o)||a;function m(r,q){return r.replace(q?k:b,function(s){return g[s]||o[s]||"&#"+s.charCodeAt(0)+";"||s})}function n(r,q){return p.encodeNamed(r,q,o)}l=j.makeMap(l.replace(/\+/g,","));if(l.named&&l.numeric){return m}if(l.named){if(o){return n}return p.encodeNamed}if(l.numeric){return p.encodeNumeric}return p.encodeRaw},decode:function(l){return l.replace(c,function(n,m,o){if(m){o=parseInt(o,m.length===2?16:10);if(o>65535){o-=65536;return String.fromCharCode(55296+(o>>10),56320+(o&1023))}else{return i[o]||String.fromCharCode(o)}}return d[n]||a[n]||h(n)})}}})(tinymce);tinymce.html.Styles=function(d,f){var k=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,h=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,b=/\s*([^:]+):\s*([^;]+);?/g,l=/\s+$/,m=/rgb/,e,g,a={},j;d=d||{};j="\\\" \\' \\; \\: ; : \uFEFF".split(" ");for(g=0;g<j.length;g++){a[j[g]]="\uFEFF"+g;a["\uFEFF"+g]=j[g]}function c(n,q,p,i){function o(r){r=parseInt(r).toString(16);return r.length>1?r:"0"+r}return"#"+o(q)+o(p)+o(i)}return{toHex:function(i){return i.replace(k,c)},parse:function(s){var z={},q,n,x,r,v=d.url_converter,y=d.url_converter_scope||this;function p(D,G){var F,C,B,E;if(z["border-image"]==="none"){delete z["border-image"]}F=z[D+"-top"+G];if(!F){return}C=z[D+"-right"+G];if(F!=C){return}B=z[D+"-bottom"+G];if(C!=B){return}E=z[D+"-left"+G];if(B!=E){return}z[D+G]=E;delete z[D+"-top"+G];delete z[D+"-right"+G];delete z[D+"-bottom"+G];delete z[D+"-left"+G]}function u(C){var D=z[C],B;if(!D||D.indexOf(" ")<0){return}D=D.split(" ");B=D.length;while(B--){if(D[B]!==D[0]){return false}}z[C]=D[0];return true}function A(D,C,B,E){if(!u(C)){return}if(!u(B)){return}if(!u(E)){return}z[D]=z[C]+" "+z[B]+" "+z[E];delete z[C];delete z[B];delete z[E]}function t(B){r=true;return a[B]}function i(C,B){if(r){C=C.replace(/\uFEFF[0-9]/g,function(D){return a[D]})}if(!B){C=C.replace(/\\([\'\";:])/g,"$1")}return C}function o(C,B,F,E,G,D){G=G||D;if(G){G=i(G);return"'"+G.replace(/\'/g,"\\'")+"'"}B=i(B||F||E);if(v){B=v.call(y,B,"style")}return"url('"+B.replace(/\'/g,"\\'")+"')"}if(s){s=s.replace(/\\[\"\';:\uFEFF]/g,t).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(B){return B.replace(/[;:]/g,t)});while(q=b.exec(s)){n=q[1].replace(l,"").toLowerCase();x=q[2].replace(l,"");if(n&&x.length>0){if(n==="font-weight"&&x==="700"){x="bold"}else{if(n==="color"||n==="background-color"){x=x.toLowerCase()}}x=x.replace(k,c);x=x.replace(h,o);z[n]=r?i(x,true):x}b.lastIndex=q.index+q[0].length}p("border","");p("border","-width");p("border","-color");p("border","-style");p("padding","");p("margin","");A("border","border-width","border-style","border-color");if(z.border==="medium none"){delete z.border}}return z},serialize:function(p,r){var o="",n,q;function i(t){var x,u,s,v;x=f.styles[t];if(x){for(u=0,s=x.length;u<s;u++){t=x[u];v=p[t];if(v!==e&&v.length>0){o+=(o.length>0?" ":"")+t+": "+v+";"}}}}if(r&&f&&f.styles){i("*");i(r)}else{for(n in p){q=p[n];if(q!==e&&q.length>0){o+=(o.length>0?" ":"")+n+": "+q+";"}}}return o}}};(function(f){var a={},e=f.makeMap,g=f.each;function d(j,i){return j.split(i||",")}function h(m,l){var j,k={};function i(n){return n.replace(/[A-Z]+/g,function(o){return i(m[o])})}for(j in m){if(m.hasOwnProperty(j)){m[j]=i(m[j])}}i(l).replace(/#/g,"#text").replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g,function(q,o,n,p){n=d(n,"|");k[o]={attributes:e(n),attributesOrder:n,children:e(p,"|",{"#comment":{}})}});return k}function b(){var i=a.html5;if(!i){i=a.html5=h({A:"id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup",B:"#|a|abbr|area|audio|b|bdo|br|button|canvas|cite|code|command|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|meta|meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video|wbr",C:"#|a|abbr|area|address|article|aside|audio|b|bdo|blockquote|br|button|canvas|cite|code|command|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|menu|meta|meter|nav|noscript|ol|object|output|p|pre|progress|q|ruby|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|ul|var|video"},"html[A|manifest][body|head]head[A][base|command|link|meta|noscript|script|style|title]title[A][#]base[A|href|target][]link[A|href|rel|media|type|sizes][]meta[A|http-equiv|name|content|charset][]style[A|type|media|scoped][#]script[A|charset|type|src|defer|async][#]noscript[A][C]body[A][C]section[A][C]nav[A][C]article[A][C]aside[A][C]h1[A][B]h2[A][B]h3[A][B]h4[A][B]h5[A][B]h6[A][B]hgroup[A][h1|h2|h3|h4|h5|h6]header[A][C]footer[A][C]address[A][C]p[A][B]br[A][]pre[A][B]dialog[A][dd|dt]blockquote[A|cite][C]ol[A|start|reversed][li]ul[A][li]li[A|value][C]dl[A][dd|dt]dt[A][B]dd[A][C]a[A|href|target|ping|rel|media|type][B]em[A][B]strong[A][B]small[A][B]cite[A][B]q[A|cite][B]dfn[A][B]abbr[A][B]code[A][B]var[A][B]samp[A][B]kbd[A][B]sub[A][B]sup[A][B]i[A][B]b[A][B]mark[A][B]progress[A|value|max][B]meter[A|value|min|max|low|high|optimum][B]time[A|datetime][B]ruby[A][B|rt|rp]rt[A][B]rp[A][B]bdo[A][B]span[A][B]ins[A|cite|datetime][B]del[A|cite|datetime][B]figure[A][C|legend|figcaption]figcaption[A][C]img[A|alt|src|height|width|usemap|ismap][]iframe[A|name|src|height|width|sandbox|seamless][]embed[A|src|height|width|type][]object[A|data|type|height|width|usemap|name|form|classid][param]param[A|name|value][]details[A|open][C|legend]command[A|type|label|icon|disabled|checked|radiogroup][]menu[A|type|label][C|li]legend[A][C|B]div[A][C]source[A|src|type|media][]audio[A|src|autobuffer|autoplay|loop|controls][source]video[A|src|autobuffer|autoplay|loop|controls|width|height|poster][source]hr[A][]form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]fieldset[A|disabled|form|name][C|legend]label[A|form|for][B]input[A|type|accept|alt|autocomplete|autofocus|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value|name][]button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]datalist[A][B|option]optgroup[A|disabled|label][option]option[A|disabled|selected|label|value][]textarea[A|autofocus|disabled|form|maxlength|name|placeholder|readonly|required|rows|cols|wrap][]keygen[A|autofocus|challenge|disabled|form|keytype|name][]output[A|for|form|name][B]canvas[A|width|height][]map[A|name][B|C]area[A|shape|coords|href|alt|target|media|rel|ping|type][]mathml[A][]svg[A][]table[A|border][caption|colgroup|thead|tfoot|tbody|tr]caption[A][C]colgroup[A|span][col]col[A|span][]thead[A][tr]tfoot[A][tr]tbody[A][tr]tr[A][th|td]th[A|headers|rowspan|colspan|scope][B]td[A|headers|rowspan|colspan][C]wbr[A][]")}return i}function c(){var i=a.html4;if(!i){i=a.html4=h({Z:"H|K|N|O|P",Y:"X|form|R|Q",ZG:"E|span|width|align|char|charoff|valign",X:"p|T|div|U|W|isindex|fieldset|table",ZF:"E|align|char|charoff|valign",W:"pre|hr|blockquote|address|center|noframes",ZE:"abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height",ZD:"[E][S]",U:"ul|ol|dl|menu|dir",ZC:"p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q",T:"h1|h2|h3|h4|h5|h6",ZB:"X|S|Q",S:"R|P",ZA:"a|G|J|M|O|P",R:"a|H|K|N|O",Q:"noscript|P",P:"ins|del|script",O:"input|select|textarea|label|button",N:"M|L",M:"em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym",L:"sub|sup",K:"J|I",J:"tt|i|b|u|s|strike",I:"big|small|font|basefont",H:"G|F",G:"br|span|bdo",F:"object|applet|img|map|iframe",E:"A|B|C",D:"accesskey|tabindex|onfocus|onblur",C:"onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup",B:"lang|xml:lang|dir",A:"id|class|style|title"},"script[id|charset|type|language|src|defer|xml:space][]style[B|id|type|media|title|xml:space][]object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]param[id|name|value|valuetype|type][]p[E|align][#|S]a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]br[A|clear][]span[E][#|S]bdo[A|C|B][#|S]applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]h1[E|align][#|S]img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]map[B|C|A|name][X|form|Q|area]h2[E|align][#|S]iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]h3[E|align][#|S]tt[E][#|S]i[E][#|S]b[E][#|S]u[E][#|S]s[E][#|S]strike[E][#|S]big[E][#|S]small[E][#|S]font[A|B|size|color|face][#|S]basefont[id|size|color|face][]em[E][#|S]strong[E][#|S]dfn[E][#|S]code[E][#|S]q[E|cite][#|S]samp[E][#|S]kbd[E][#|S]var[E][#|S]cite[E][#|S]abbr[E][#|S]acronym[E][#|S]sub[E][#|S]sup[E][#|S]input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]optgroup[E|disabled|label][option]option[E|selected|disabled|label|value][]textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]label[E|for|accesskey|onfocus|onblur][#|S]button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]h4[E|align][#|S]ins[E|cite|datetime][#|Y]h5[E|align][#|S]del[E|cite|datetime][#|Y]h6[E|align][#|S]div[E|align][#|Y]ul[E|type|compact][li]li[E|type|value][#|Y]ol[E|type|compact|start][li]dl[E|compact][dt|dd]dt[E][#|S]dd[E][#|Y]menu[E|compact][li]dir[E|compact][li]pre[E|width|xml:space][#|ZA]hr[E|align|noshade|size|width][]blockquote[E|cite][#|Y]address[E][#|S|p]center[E][#|Y]noframes[E][#|Y]isindex[A|B|prompt][]fieldset[E][#|legend|Y]legend[E|accesskey|align][#|S]table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]caption[E|align][#|S]col[ZG][]colgroup[ZG][col]thead[ZF][tr]tr[ZF|bgcolor][th|td]th[E|ZE][#|Y]form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]noscript[E][#|Y]td[E|ZE][#|Y]tfoot[ZF][tr]tbody[ZF][tr]area[E|D|shape|coords|href|nohref|alt|target][]base[id|href|target][]body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]")}return i}f.html.Schema=function(A){var u=this,s={},k={},j=[],D,y;var o,q,z,r,v,n,p={};function m(F,E,H){var G=A[F];if(!G){G=a[F];if(!G){G=e(E," ",e(E.toUpperCase()," "));G=f.extend(G,H);a[F]=G}}else{G=e(G,",",e(G.toUpperCase()," "))}return G}A=A||{};y=A.schema=="html5"?b():c();if(A.verify_html===false){A.valid_elements="*[*]"}if(A.valid_styles){D={};g(A.valid_styles,function(F,E){D[E]=f.explode(F)})}o=m("whitespace_elements","pre script noscript style textarea");q=m("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr");z=m("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr");r=m("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls");n=m("non_empty_elements","td th iframe video audio object script",z);textBlockElementsMap=m("text_block_elements","h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside nav figure");v=m("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex samp option datalist select optgroup",textBlockElementsMap);function i(E){return new RegExp("^"+E.replace(/([?+*])/g,".$1")+"$")}function C(L){var K,G,Z,V,aa,F,I,U,X,Q,Y,ac,O,J,W,E,S,H,ab,ad,P,T,N=/^([#+\-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,R=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,M=/[*?+]/;if(L){L=d(L);if(s["@"]){S=s["@"].attributes;H=s["@"].attributesOrder}for(K=0,G=L.length;K<G;K++){F=N.exec(L[K]);if(F){W=F[1];Q=F[2];E=F[3];X=F[4];O={};J=[];I={attributes:O,attributesOrder:J};if(W==="#"){I.paddEmpty=true}if(W==="-"){I.removeEmpty=true}if(S){for(ad in S){O[ad]=S[ad]}J.push.apply(J,H)}if(X){X=d(X,"|");for(Z=0,V=X.length;Z<V;Z++){F=R.exec(X[Z]);if(F){U={};ac=F[1];Y=F[2].replace(/::/g,":");W=F[3];T=F[4];if(ac==="!"){I.attributesRequired=I.attributesRequired||[];I.attributesRequired.push(Y);U.required=true}if(ac==="-"){delete O[Y];J.splice(f.inArray(J,Y),1);continue}if(W){if(W==="="){I.attributesDefault=I.attributesDefault||[];I.attributesDefault.push({name:Y,value:T});U.defaultValue=T}if(W===":"){I.attributesForced=I.attributesForced||[];I.attributesForced.push({name:Y,value:T});U.forcedValue=T}if(W==="<"){U.validValues=e(T,"?")}}if(M.test(Y)){I.attributePatterns=I.attributePatterns||[];U.pattern=i(Y);I.attributePatterns.push(U)}else{if(!O[Y]){J.push(Y)}O[Y]=U}}}}if(!S&&Q=="@"){S=O;H=J}if(E){I.outputName=Q;s[E]=I}if(M.test(Q)){I.pattern=i(Q);j.push(I)}else{s[Q]=I}}}}}function t(E){s={};j=[];C(E);g(y,function(G,F){k[F]=G.children})}function l(F){var E=/^(~)?(.+)$/;if(F){g(d(F),function(J){var H=E.exec(J),I=H[1]==="~",K=I?"span":"div",G=H[2];k[G]=k[K];p[G]=K;if(!I){v[G.toUpperCase()]={};v[G]={}}if(!s[G]){s[G]=s[K]}g(k,function(L,M){if(L[K]){L[G]=L[K]}})})}}function x(F){var E=/^([+\-]?)(\w+)\[([^\]]+)\]$/;if(F){g(d(F),function(J){var I=E.exec(J),G,H;if(I){H=I[1];if(H){G=k[I[2]]}else{G=k[I[2]]={"#comment":{}}}G=k[I[2]];g(d(I[3],"|"),function(K){if(H==="-"){delete G[K]}else{G[K]={}}})}})}}function B(E){var G=s[E],F;if(G){return G}F=j.length;while(F--){G=j[F];if(G.pattern.test(E)){return G}}}if(!A.valid_elements){g(y,function(F,E){s[E]={attributes:F.attributes,attributesOrder:F.attributesOrder};k[E]=F.children});if(A.schema!="html5"){g(d("strong/b,em/i"),function(E){E=d(E,"/");s[E[1]].outputName=E[0]})}s.img.attributesDefault=[{name:"alt",value:""}];g(d("ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr,strong,em,b,i"),function(E){if(s[E]){s[E].removeEmpty=true}});g(d("p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption"),function(E){s[E].paddEmpty=true})}else{t(A.valid_elements)}l(A.custom_elements);x(A.valid_children);C(A.extended_valid_elements);x("+ol[ul|ol],+ul[ul|ol]");if(A.invalid_elements){f.each(f.explode(A.invalid_elements),function(E){if(s[E]){delete s[E]}})}if(!B("span")){C("span[!data-mce-type|*]")}u.children=k;u.styles=D;u.getBoolAttrs=function(){return r};u.getBlockElements=function(){return v};u.getTextBlockElements=function(){return textBlockElementsMap};u.getShortEndedElements=function(){return z};u.getSelfClosingElements=function(){return q};u.getNonEmptyElements=function(){return n};u.getWhiteSpaceElements=function(){return o};u.isValidChild=function(E,G){var F=k[E];return !!(F&&F[G])};u.isValid=function(F,E){var H,G,I=B(F);if(I){if(E){if(I.attributes[E]){return true}H=I.attributePatterns;if(H){G=H.length;while(G--){if(H[G].pattern.test(F)){return true}}}}else{return true}}return false};u.getElementRule=B;u.getCustomElements=function(){return p};u.addValidElements=C;u.setValidElements=t;u.addCustomElements=l;u.addValidChildren=x;u.elements=s}})(tinymce);(function(a){a.html.SaxParser=function(c,e){var b=this,d=function(){};c=c||{};b.schema=e=e||new a.html.Schema();if(c.fix_self_closing!==false){c.fix_self_closing=true}a.each("comment cdata text start end pi doctype".split(" "),function(f){if(f){b[f]=c[f]||d}});b.parse=function(E){var n=this,g,G=0,I,B,A=[],N,Q,C,r,z,s,M,H,O,v,m,k,t,R,o,P,F,S,L,f,J,l,D,K,h,x=0,j=a.html.Entities.decode,y,q;function u(T){var V,U;V=A.length;while(V--){if(A[V].name===T){break}}if(V>=0){for(U=A.length-1;U>=V;U--){T=A[U];if(T.valid){n.end(T.name)}}A.length=V}}function p(U,T,Y,X,W){var Z,V;T=T.toLowerCase();Y=T in H?T:j(Y||X||W||"");if(v&&!z&&T.indexOf("data-")!==0){Z=P[T];if(!Z&&F){V=F.length;while(V--){Z=F[V];if(Z.pattern.test(T)){break}}if(V===-1){Z=null}}if(!Z){return}if(Z.validValues&&!(Y in Z.validValues)){return}}N.map[T]=Y;N.push({name:T,value:Y})}l=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([^>]+)>)|(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g");D=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;K={script:/<\/script[^>]*>/gi,style:/<\/style[^>]*>/gi,noscript:/<\/noscript[^>]*>/gi};M=e.getShortEndedElements();J=c.self_closing_elements||e.getSelfClosingElements();H=e.getBoolAttrs();v=c.validate;s=c.remove_internals;y=c.fix_self_closing;q=a.isIE;o=/^:/;while(g=l.exec(E)){if(G<g.index){n.text(j(E.substr(G,g.index-G)))}if(I=g[6]){I=I.toLowerCase();if(q&&o.test(I)){I=I.substr(1)}u(I)}else{if(I=g[7]){I=I.toLowerCase();if(q&&o.test(I)){I=I.substr(1)}O=I in M;if(y&&J[I]&&A.length>0&&A[A.length-1].name===I){u(I)}if(!v||(m=e.getElementRule(I))){k=true;if(v){P=m.attributes;F=m.attributePatterns}if(R=g[8]){z=R.indexOf("data-mce-type")!==-1;if(z&&s){k=false}N=[];N.map={};R.replace(D,p)}else{N=[];N.map={}}if(v&&!z){S=m.attributesRequired;L=m.attributesDefault;f=m.attributesForced;if(f){Q=f.length;while(Q--){t=f[Q];r=t.name;h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}if(L){Q=L.length;while(Q--){t=L[Q];r=t.name;if(!(r in N.map)){h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}}if(S){Q=S.length;while(Q--){if(S[Q] in N.map){break}}if(Q===-1){k=false}}if(N.map["data-mce-bogus"]){k=false}}if(k){n.start(I,N,O)}}else{k=false}if(B=K[I]){B.lastIndex=G=g.index+g[0].length;if(g=B.exec(E)){if(k){C=E.substr(G,g.index-G)}G=g.index+g[0].length}else{C=E.substr(G);G=E.length}if(k&&C.length>0){n.text(C,true)}if(k){n.end(I)}l.lastIndex=G;continue}if(!O){if(!R||R.indexOf("/")!=R.length-1){A.push({name:I,valid:k})}else{if(k){n.end(I)}}}}else{if(I=g[1]){n.comment(I)}else{if(I=g[2]){n.cdata(I)}else{if(I=g[3]){n.doctype(I)}else{if(I=g[4]){n.pi(I,g[5])}}}}}}G=g.index+g[0].length}if(G<E.length){n.text(j(E.substr(G)))}for(Q=A.length-1;Q>=0;Q--){I=A[Q];if(I.valid){n.end(I.name)}}}}})(tinymce);(function(d){var c=/^[ \t\r\n]*$/,e={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};function a(k,l,j){var i,h,f=j?"lastChild":"firstChild",g=j?"prev":"next";if(k[f]){return k[f]}if(k!==l){i=k[g];if(i){return i}for(h=k.parent;h&&h!==l;h=h.parent){i=h[g];if(i){return i}}}}function b(f,g){this.name=f;this.type=g;if(g===1){this.attributes=[];this.attributes.map={}}}d.extend(b.prototype,{replace:function(g){var f=this;if(g.parent){g.remove()}f.insert(g,f);f.remove();return f},attr:function(h,l){var f=this,g,j,k;if(typeof h!=="string"){for(j in h){f.attr(j,h[j])}return f}if(g=f.attributes){if(l!==k){if(l===null){if(h in g.map){delete g.map[h];j=g.length;while(j--){if(g[j].name===h){g=g.splice(j,1);return f}}}return f}if(h in g.map){j=g.length;while(j--){if(g[j].name===h){g[j].value=l;break}}}else{g.push({name:h,value:l})}g.map[h]=l;return f}else{return g.map[h]}}},clone:function(){var g=this,n=new b(g.name,g.type),h,f,m,j,k;if(m=g.attributes){k=[];k.map={};for(h=0,f=m.length;h<f;h++){j=m[h];if(j.name!=="id"){k[k.length]={name:j.name,value:j.value};k.map[j.name]=j.value}}n.attributes=k}n.value=g.value;n.shortEnded=g.shortEnded;return n},wrap:function(g){var f=this;f.parent.insert(g,f);g.append(f);return f},unwrap:function(){var f=this,h,g;for(h=f.firstChild;h;){g=h.next;f.insert(h,f,true);h=g}f.remove()},remove:function(){var f=this,h=f.parent,g=f.next,i=f.prev;if(h){if(h.firstChild===f){h.firstChild=g;if(g){g.prev=null}}else{i.next=g}if(h.lastChild===f){h.lastChild=i;if(i){i.next=null}}else{g.prev=i}f.parent=f.next=f.prev=null}return f},append:function(h){var f=this,g;if(h.parent){h.remove()}g=f.lastChild;if(g){g.next=h;h.prev=g;f.lastChild=h}else{f.lastChild=f.firstChild=h}h.parent=f;return h},insert:function(h,f,i){var g;if(h.parent){h.remove()}g=f.parent||this;if(i){if(f===g.firstChild){g.firstChild=h}else{f.prev.next=h}h.prev=f.prev;h.next=f;f.prev=h}else{if(f===g.lastChild){g.lastChild=h}else{f.next.prev=h}h.next=f.next;h.prev=f;f.next=h}h.parent=g;return h},getAll:function(g){var f=this,h,i=[];for(h=f.firstChild;h;h=a(h,f)){if(h.name===g){i.push(h)}}return i},empty:function(){var g=this,f,h,j;if(g.firstChild){f=[];for(j=g.firstChild;j;j=a(j,g)){f.push(j)}h=f.length;while(h--){j=f[h];j.parent=j.firstChild=j.lastChild=j.next=j.prev=null}}g.firstChild=g.lastChild=null;return g},isEmpty:function(k){var f=this,j=f.firstChild,h,g;if(j){do{if(j.type===1){if(j.attributes.map["data-mce-bogus"]){continue}if(k[j.name]){return false}h=j.attributes.length;while(h--){g=j.attributes[h].name;if(g==="name"||g.indexOf("data-mce-")===0){return false}}}if(j.type===8){return false}if((j.type===3&&!c.test(j.value))){return false}}while(j=a(j,f))}return true},walk:function(f){return a(this,null,f)}});d.extend(b,{create:function(g,f){var i,h;i=new b(g,e[g]||1);if(f){for(h in f){i.attr(h,f[h])}}return i}});d.html.Node=b})(tinymce);(function(b){var a=b.html.Node;b.html.DomParser=function(g,h){var f=this,e={},d=[],i={},c={};g=g||{};g.validate="validate" in g?g.validate:true;g.root_name=g.root_name||"body";f.schema=h=h||new b.html.Schema();function j(n){var p,q,y,x,A,o,r,l,u,v,k,t,m,z,s;t=b.makeMap("tr,td,th,tbody,thead,tfoot,table");k=h.getNonEmptyElements();m=h.getTextBlockElements();for(p=0;p<n.length;p++){q=n[p];if(!q.parent||q.fixed){continue}if(m[q.name]&&q.parent.name=="li"){z=q.next;while(z){if(m[z.name]){z.name="li";z.fixed=true;q.parent.insert(z,q.parent)}else{break}z=z.next}q.unwrap(q);continue}x=[q];for(y=q.parent;y&&!h.isValidChild(y.name,q.name)&&!t[y.name];y=y.parent){x.push(y)}if(y&&x.length>1){x.reverse();A=o=f.filterNode(x[0].clone());for(u=0;u<x.length-1;u++){if(h.isValidChild(o.name,x[u].name)){r=f.filterNode(x[u].clone());o.append(r)}else{r=o}for(l=x[u].firstChild;l&&l!=x[u+1];){s=l.next;r.append(l);l=s}o=r}if(!A.isEmpty(k)){y.insert(A,x[0],true);y.insert(q,A)}else{y.insert(q,x[0],true)}y=x[0];if(y.isEmpty(k)||y.firstChild===y.lastChild&&y.firstChild.name==="br"){y.empty().remove()}}else{if(q.parent){if(q.name==="li"){z=q.prev;if(z&&(z.name==="ul"||z.name==="ul")){z.append(q);continue}z=q.next;if(z&&(z.name==="ul"||z.name==="ul")){z.insert(q,z.firstChild,true);continue}q.wrap(f.filterNode(new a("ul",1)));continue}if(h.isValidChild(q.parent.name,"div")&&h.isValidChild("div",q.name)){q.wrap(f.filterNode(new a("div",1)))}else{if(q.name==="style"||q.name==="script"){q.empty().remove()}else{q.unwrap()}}}}}}f.filterNode=function(m){var l,k,n;if(k in e){n=i[k];if(n){n.push(m)}else{i[k]=[m]}}l=d.length;while(l--){k=d[l].name;if(k in m.attributes.map){n=c[k];if(n){n.push(m)}else{c[k]=[m]}}}return m};f.addNodeFilter=function(k,l){b.each(b.explode(k),function(m){var n=e[m];if(!n){e[m]=n=[]}n.push(l)})};f.addAttributeFilter=function(k,l){b.each(b.explode(k),function(m){var n;for(n=0;n<d.length;n++){if(d[n].name===m){d[n].callbacks.push(l);return}}d.push({name:m,callbacks:[l]})})};f.parse=function(v,m){var n,J,B,A,D,C,x,r,F,N,z,o,E,M=[],L,t,k,y,s,p,u,q;m=m||{};i={};c={};o=b.extend(b.makeMap("script,style,head,html,body,title,meta,param"),h.getBlockElements());u=h.getNonEmptyElements();p=h.children;z=g.validate;q="forced_root_block" in m?m.forced_root_block:g.forced_root_block;s=h.getWhiteSpaceElements();E=/^[ \t\r\n]+/;t=/[ \t\r\n]+$/;k=/[ \t\r\n]+/g;y=/^[ \t\r\n]+$/;function G(){var O=J.firstChild,l,P;while(O){l=O.next;if(O.type==3||(O.type==1&&O.name!=="p"&&!o[O.name]&&!O.attr("data-mce-type"))){if(!P){P=K(q,1);J.insert(P,O);P.append(O)}else{P.append(O)}}else{P=null}O=l}}function K(l,O){var P=new a(l,O),Q;if(l in e){Q=i[l];if(Q){Q.push(P)}else{i[l]=[P]}}return P}function I(P){var Q,l,O;for(Q=P.prev;Q&&Q.type===3;){l=Q.value.replace(t,"");if(l.length>0){Q.value=l;Q=Q.prev}else{O=Q.prev;Q.remove();Q=O}}}function H(O){var P,l={};for(P in O){if(P!=="li"&&P!="p"){l[P]=O[P]}}return l}n=new b.html.SaxParser({validate:z,self_closing_elements:H(h.getSelfClosingElements()),cdata:function(l){B.append(K("#cdata",4)).value=l},text:function(P,l){var O;if(!L){P=P.replace(k," ");if(B.lastChild&&o[B.lastChild.name]){P=P.replace(E,"")}}if(P.length!==0){O=K("#text",3);O.raw=!!l;B.append(O).value=P}},comment:function(l){B.append(K("#comment",8)).value=l},pi:function(l,O){B.append(K(l,7)).value=O;I(B)},doctype:function(O){var l;l=B.append(K("#doctype",10));l.value=O;I(B)},start:function(l,W,P){var U,R,Q,O,S,X,V,T;Q=z?h.getElementRule(l):{};if(Q){U=K(Q.outputName||l,1);U.attributes=W;U.shortEnded=P;B.append(U);T=p[B.name];if(T&&p[U.name]&&!T[U.name]){M.push(U)}R=d.length;while(R--){S=d[R].name;if(S in W.map){F=c[S];if(F){F.push(U)}else{c[S]=[U]}}}if(o[l]){I(U)}if(!P){B=U}if(!L&&s[l]){L=true}}},end:function(l){var S,P,R,O,Q;P=z?h.getElementRule(l):{};if(P){if(o[l]){if(!L){S=B.firstChild;if(S&&S.type===3){R=S.value.replace(E,"");if(R.length>0){S.value=R;S=S.next}else{O=S.next;S.remove();S=O}while(S&&S.type===3){R=S.value;O=S.next;if(R.length===0||y.test(R)){S.remove();S=O}S=O}}S=B.lastChild;if(S&&S.type===3){R=S.value.replace(t,"");if(R.length>0){S.value=R;S=S.prev}else{O=S.prev;S.remove();S=O}while(S&&S.type===3){R=S.value;O=S.prev;if(R.length===0||y.test(R)){S.remove();S=O}S=O}}}}if(L&&s[l]){L=false}if(P.removeEmpty||P.paddEmpty){if(B.isEmpty(u)){if(P.paddEmpty){B.empty().append(new a("#text","3")).value="\u00a0"}else{if(!B.attributes.map.name&&!B.attributes.map.id){Q=B.parent;B.empty().remove();B=Q;return}}}}B=B.parent}}},h);J=B=new a(m.context||g.root_name,11);n.parse(v);if(z&&M.length){if(!m.context){j(M)}else{m.invalid=true}}if(q&&J.name=="body"){G()}if(!m.invalid){for(N in i){F=e[N];A=i[N];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(D=0,C=F.length;D<C;D++){F[D](A,N,m)}}for(D=0,C=d.length;D<C;D++){F=d[D];if(F.name in c){A=c[F.name];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(x=0,r=F.callbacks.length;x<r;x++){F.callbacks[x](A,F.name,m)}}}}return J};if(g.remove_trailing_brs){f.addNodeFilter("br",function(n,m){var r,q=n.length,o,v=b.extend({},h.getBlockElements()),k=h.getNonEmptyElements(),t,s,p,u;v.body=1;for(r=0;r<q;r++){o=n[r];t=o.parent;if(v[o.parent.name]&&o===t.lastChild){p=o.prev;while(p){u=p.name;if(u!=="span"||p.attr("data-mce-type")!=="bookmark"){if(u!=="br"){break}if(u==="br"){o=null;break}}p=p.prev}if(o){o.remove();if(t.isEmpty(k)){elementRule=h.getElementRule(t.name);if(elementRule){if(elementRule.removeEmpty){t.remove()}else{if(elementRule.paddEmpty){t.empty().append(new b.html.Node("#text",3)).value="\u00a0"}}}}}}else{s=o;while(t.firstChild===s&&t.lastChild===s){s=t;if(v[t.name]){break}t=t.parent}if(s===t){textNode=new b.html.Node("#text",3);textNode.value="\u00a0";o.replace(textNode)}}}})}if(!g.allow_html_in_named_anchor){f.addAttributeFilter("id,name",function(k,l){var n=k.length,p,m,o,q;while(n--){q=k[n];if(q.name==="a"&&q.firstChild&&!q.attr("href")){o=q.parent;p=q.lastChild;do{m=p.prev;o.insert(p,q);p=m}while(p)}}})}}})(tinymce);tinymce.html.Writer=function(e){var c=[],a,b,d,f,g;e=e||{};a=e.indent;b=tinymce.makeMap(e.indent_before||"");d=tinymce.makeMap(e.indent_after||"");f=tinymce.html.Entities.getEncodeFunc(e.entity_encoding||"raw",e.entities);g=e.element_format=="html";return{start:function(m,k,p){var n,j,h,o;if(a&&b[m]&&c.length>0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}c.push("<",m);if(k){for(n=0,j=k.length;n<j;n++){h=k[n];c.push(" ",h.name,'="',f(h.value,true),'"')}}if(!p||g){c[c.length]=">"}else{c[c.length]=" />"}if(p&&a&&d[m]&&c.length>0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}},end:function(h){var i;c.push("</",h,">");if(a&&d[h]&&c.length>0){i=c[c.length-1];if(i.length>0&&i!=="\n"){c.push("\n")}}},text:function(i,h){if(i.length>0){c[c.length]=h?i:f(i)}},cdata:function(h){c.push("<![CDATA[",h,"]]>")},comment:function(h){c.push("<!--",h,"-->")},pi:function(h,i){if(i){c.push("<?",h," ",i,"?>")}else{c.push("<?",h,"?>")}if(a){c.push("\n")}},doctype:function(h){c.push("<!DOCTYPE",h,">",a?"\n":"")},reset:function(){c.length=0},getContent:function(){return c.join("").replace(/\n$/,"")}}};(function(a){a.html.Serializer=function(c,d){var b=this,e=new a.html.Writer(c);c=c||{};c.validate="validate" in c?c.validate:true;b.schema=d=d||new a.html.Schema();b.writer=e;b.serialize=function(h){var g,i;i=c.validate;g={3:function(k,j){e.text(k.value,k.raw)},8:function(j){e.comment(j.value)},7:function(j){e.pi(j.name,j.value)},10:function(j){e.doctype(j.value)},4:function(j){e.cdata(j.value)},11:function(j){if((j=j.firstChild)){do{f(j)}while(j=j.next)}}};e.reset();function f(k){var t=g[k.type],j,o,s,r,p,u,n,m,q;if(!t){j=k.name;o=k.shortEnded;s=k.attributes;if(i&&s&&s.length>1){u=[];u.map={};q=d.getElementRule(k.name);for(n=0,m=q.attributesOrder.length;n<m;n++){r=q.attributesOrder[n];if(r in s.map){p=s.map[r];u.map[r]=p;u.push({name:r,value:p})}}for(n=0,m=s.length;n<m;n++){r=s[n].name;if(!(r in u.map)){p=s.map[r];u.map[r]=p;u.push({name:r,value:p})}}s=u}e.start(k.name,s,o);if(!o){if((k=k.firstChild)){do{f(k)}while(k=k.next)}e.end(j)}}else{t(k)}}if(h.type==1&&!c.inner){f(h)}else{g[11](h)}return e.getContent()}}})(tinymce);tinymce.dom={};(function(b,h){var g=!!document.addEventListener;function c(k,j,l,i){if(k.addEventListener){k.addEventListener(j,l,i||false)}else{if(k.attachEvent){k.attachEvent("on"+j,l)}}}function e(k,j,l,i){if(k.removeEventListener){k.removeEventListener(j,l,i||false)}else{if(k.detachEvent){k.detachEvent("on"+j,l)}}}function a(n,l){var i,k=l||{};function j(){return false}function m(){return true}for(i in n){if(i!=="layerX"&&i!=="layerY"){k[i]=n[i]}}if(!k.target){k.target=k.srcElement||document}k.preventDefault=function(){k.isDefaultPrevented=m;if(n){if(n.preventDefault){n.preventDefault()}else{n.returnValue=false}}};k.stopPropagation=function(){k.isPropagationStopped=m;if(n){if(n.stopPropagation){n.stopPropagation()}else{n.cancelBubble=true}}};k.stopImmediatePropagation=function(){k.isImmediatePropagationStopped=m;k.stopPropagation()};if(!k.isDefaultPrevented){k.isDefaultPrevented=j;k.isPropagationStopped=j;k.isImmediatePropagationStopped=j}return k}function d(m,n,l){var k=m.document,j={type:"ready"};function i(){if(!l.domLoaded){l.domLoaded=true;n(j)}}if(k.readyState=="complete"){i();return}if(g){c(m,"DOMContentLoaded",i)}else{c(k,"readystatechange",function(){if(k.readyState==="complete"){e(k,"readystatechange",arguments.callee);i()}});if(k.documentElement.doScroll&&m===m.top){(function(){try{k.documentElement.doScroll("left")}catch(o){setTimeout(arguments.callee,0);return}i()})()}}c(m,"load",i)}function f(k){var q=this,p={},i,o,n,m,l;m="onmouseenter" in document.documentElement;n="onfocusin" in document.documentElement;l={mouseenter:"mouseover",mouseleave:"mouseout"};i=1;q.domLoaded=false;q.events=p;function j(t,x){var s,u,r,v;s=p[x][t.type];if(s){for(u=0,r=s.length;u<r;u++){v=s[u];if(v&&v.func.call(v.scope,t)===false){t.preventDefault()}if(t.isImmediatePropagationStopped()){return}}}}q.bind=function(x,A,D,E){var s,t,u,r,B,z,C,v=window;function y(F){j(a(F||v.event),s)}if(!x||x.nodeType===3||x.nodeType===8){return}if(!x[h]){s=i++;x[h]=s;p[s]={}}else{s=x[h];if(!p[s]){p[s]={}}}E=E||x;A=A.split(" ");u=A.length;while(u--){r=A[u];z=y;B=C=false;if(r==="DOMContentLoaded"){r="ready"}if((q.domLoaded||x.readyState=="complete")&&r==="ready"){q.domLoaded=true;D.call(E,a({type:r}));continue}if(!m){B=l[r];if(B){z=function(F){var H,G;H=F.currentTarget;G=F.relatedTarget;if(G&&H.contains){G=H.contains(G)}else{while(G&&G!==H){G=G.parentNode}}if(!G){F=a(F||v.event);F.type=F.type==="mouseout"?"mouseleave":"mouseenter";F.target=H;j(F,s)}}}}if(!n&&(r==="focusin"||r==="focusout")){C=true;B=r==="focusin"?"focus":"blur";z=function(F){F=a(F||v.event);F.type=F.type==="focus"?"focusin":"focusout";j(F,s)}}t=p[s][r];if(!t){p[s][r]=t=[{func:D,scope:E}];t.fakeName=B;t.capture=C;t.nativeHandler=z;if(!g){t.proxyHandler=k(s)}if(r==="ready"){d(x,z,q)}else{c(x,B||r,g?z:t.proxyHandler,C)}}else{t.push({func:D,scope:E})}}x=t=0;return D};q.unbind=function(x,z,A){var s,u,v,B,r,t;if(!x||x.nodeType===3||x.nodeType===8){return q}s=x[h];if(s){t=p[s];if(z){z=z.split(" ");v=z.length;while(v--){r=z[v];u=t[r];if(u){if(A){B=u.length;while(B--){if(u[B].func===A){u.splice(B,1)}}}if(!A||u.length===0){delete t[r];e(x,u.fakeName||r,g?u.nativeHandler:u.proxyHandler,u.capture)}}}}else{for(r in t){u=t[r];e(x,u.fakeName||r,g?u.nativeHandler:u.proxyHandler,u.capture)}t={}}for(r in t){return q}delete p[s];try{delete x[h]}catch(y){x[h]=null}}return q};q.fire=function(u,s,r){var v,t;if(!u||u.nodeType===3||u.nodeType===8){return q}t=a(null,r);t.type=s;do{v=u[h];if(v){j(t,v)}u=u.parentNode||u.ownerDocument||u.defaultView||u.parentWindow}while(u&&!t.isPropagationStopped());return q};q.clean=function(u){var s,r,t=q.unbind;if(!u||u.nodeType===3||u.nodeType===8){return q}if(u[h]){t(u)}if(!u.getElementsByTagName){u=u.document}if(u&&u.getElementsByTagName){t(u);r=u.getElementsByTagName("*");s=r.length;while(s--){u=r[s];if(u[h]){t(u)}}}return q};q.callNativeHandler=function(s,r){if(p){p[s][r.type].nativeHandler(r)}};q.destory=function(){p={}};q.add=function(v,s,u,t){if(typeof(v)==="string"){v=document.getElementById(v)}if(v&&v instanceof Array){var r=v.length;while(r--){q.add(v[r],s,u,t)}return}if(s==="init"){s="ready"}return q.bind(v,s instanceof Array?s.join(" "):s,u,t)};q.remove=function(v,s,u,t){if(!v){return q}if(typeof(v)==="string"){v=document.getElementById(v)}if(v instanceof Array){var r=v.length;while(r--){q.remove(v[r],s,u,t)}return q}return q.unbind(v,s instanceof Array?s.join(" "):s,u)};q.clear=function(r){if(typeof(r)==="string"){r=document.getElementById(r)}return q.clean(r)};q.cancel=function(r){if(r){q.prevent(r);q.stop(r)}return false};q.prevent=function(r){if(!r.preventDefault){r=a(r)}r.preventDefault();return false};q.stop=function(r){if(!r.stopPropagation){r=a(r)}r.stopPropagation();return false}}b.EventUtils=f;b.Event=new f(function(i){return function(j){tinymce.dom.Event.callNativeHandler(i,j)}});b.Event.bind(window,"ready",function(){});b=0})(tinymce.dom,"data-mce-expando");tinymce.dom.TreeWalker=function(a,c){var b=a;function d(i,f,e,j){var h,g;if(i){if(!j&&i[f]){return i[f]}if(i!=c){h=i[e];if(h){return h}for(g=i.parentNode;g&&g!=c;g=g.parentNode){h=g[e];if(h){return h}}}}}this.current=function(){return b};this.next=function(e){return(b=d(b,"firstChild","nextSibling",e))};this.prev=function(e){return(b=d(b,"lastChild","previousSibling",e))}};(function(e){var g=e.each,d=e.is,f=e.isWebKit,b=e.isIE,h=e.html.Entities,c=/^([a-z0-9],?)+$/i,a=/^[ \t\r\n]*$/;e.create("tinymce.dom.DOMUtils",{doc:null,root:null,files:null,pixelStyles:/^(top|left|bottom|right|width|height|borderWidth)$/,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},DOMUtils:function(o,l){var k=this,i,j,n;k.doc=o;k.win=window;k.files={};k.cssFlicker=false;k.counter=0;k.stdMode=!e.isIE||o.documentMode>=8;k.boxModel=!e.isIE||o.compatMode=="CSS1Compat"||k.stdMode;k.hasOuterHTML="outerHTML" in o.createElement("a");k.settings=l=e.extend({keep_values:false,hex_colors:1},l);k.schema=l.schema;k.styles=new e.html.Styles({url_converter:l.url_converter,url_converter_scope:l.url_converter_scope},l.schema);if(e.isIE6){try{o.execCommand("BackgroundImageCache",false,true)}catch(m){k.cssFlicker=true}}k.fixDoc(o);k.events=l.ownEvents?new e.dom.EventUtils(l.proxy):e.dom.Event;e.addUnload(k.destroy,k);n=l.schema?l.schema.getBlockElements():{};k.isBlock=function(q){if(!q){return false}var p=q.nodeType;if(p){return !!(p===1&&n[q.nodeName])}return !!n[q]}},fixDoc:function(k){var j=this.settings,i;if(b&&!e.isIE11&&j.schema){("abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video").replace(/\w+/g,function(l){k.createElement(l)});for(i in j.schema.getCustomElements()){k.createElement(i)}}},clone:function(k,i){var j=this,m,l;if(!b||e.isIE11||k.nodeType!==1||i){return k.cloneNode(i)}l=j.doc;if(!i){m=l.createElement(k.nodeName);g(j.getAttribs(k),function(n){j.setAttrib(m,n.nodeName,j.getAttrib(k,n.nodeName))});return m}return m.firstChild},getRoot:function(){var i=this,j=i.settings;return(j&&i.get(j.root_element))||i.doc.body},getViewPort:function(j){var k,i;j=!j?this.win:j;k=j.document;i=this.boxModel?k.documentElement:k.body;return{x:j.pageXOffset||i.scrollLeft,y:j.pageYOffset||i.scrollTop,w:j.innerWidth||i.clientWidth,h:j.innerHeight||i.clientHeight}},getRect:function(l){var k,i=this,j;l=i.get(l);k=i.getPos(l);j=i.getSize(l);return{x:k.x,y:k.y,w:j.w,h:j.h}},getSize:function(l){var j=this,i,k;l=j.get(l);i=j.getStyle(l,"width");k=j.getStyle(l,"height");if(i.indexOf("px")===-1){i=0}if(k.indexOf("px")===-1){k=0}return{w:parseInt(i,10)||l.offsetWidth||l.clientWidth,h:parseInt(k,10)||l.offsetHeight||l.clientHeight}},getParent:function(k,j,i){return this.getParents(k,j,i,false)},getParents:function(s,m,k,q){var j=this,i,l=j.settings,p=[];s=j.get(s);q=q===undefined;if(l.strict_root){k=k||j.getRoot()}if(d(m,"string")){i=m;if(m==="*"){m=function(o){return o.nodeType==1}}else{m=function(o){return j.is(o,i)}}}while(s){if(s==k||!s.nodeType||s.nodeType===9){break}if(!m||m(s)){if(q){p.push(s)}else{return s}}s=s.parentNode}return q?p:null},get:function(i){var j;if(i&&this.doc&&typeof(i)=="string"){j=i;i=this.doc.getElementById(i);if(i&&i.id!==j){return this.doc.getElementsByName(j)[1]}}return i},getNext:function(j,i){return this._findSib(j,i,"nextSibling")},getPrev:function(j,i){return this._findSib(j,i,"previousSibling")},select:function(k,j){var i=this;return e.dom.Sizzle(k,i.get(j)||i.get(i.settings.root_element)||i.doc,[])},is:function(l,j){var k;if(l.length===undefined){if(j==="*"){return l.nodeType==1}if(c.test(j)){j=j.toLowerCase().split(/,/);l=l.nodeName.toLowerCase();for(k=j.length-1;k>=0;k--){if(j[k]==l){return true}}return false}}return e.dom.Sizzle.matches(j,l.nodeType?[l]:l).length>0},add:function(l,o,i,k,m){var j=this;return this.run(l,function(r){var q,n;q=d(o,"string")?j.doc.createElement(o):o;j.setAttribs(q,i);if(k){if(k.nodeType){q.appendChild(k)}else{j.setHTML(q,k)}}return !m?r.appendChild(q):q})},create:function(k,i,j){return this.add(this.doc.createElement(k),k,i,j,1)},createHTML:function(q,i,m){var p="",l=this,j;p+="<"+q;for(j in i){if(i.hasOwnProperty(j)){p+=" "+j+'="'+l.encode(i[j])+'"'}}if(typeof(m)!="undefined"){return p+">"+m+"</"+q+">"}return p+" />"},remove:function(i,j){return this.run(i,function(l){var m,k=l.parentNode;if(!k){return null}if(j){while(m=l.firstChild){if(!e.isIE||m.nodeType!==3||m.nodeValue){k.insertBefore(m,l)}else{l.removeChild(m)}}}return k.removeChild(l)})},setStyle:function(l,i,j){var k=this;return k.run(l,function(o){var n,m;n=o.style;i=i.replace(/-(\D)/g,function(q,p){return p.toUpperCase()});if(k.pixelStyles.test(i)&&(e.is(j,"number")||/^[\-0-9\.]+$/.test(j))){j+="px"}switch(i){case"opacity":if(b&&!e.isIE11){n.filter=j===""?"":"alpha(opacity="+(j*100)+")";if(!l.currentStyle||!l.currentStyle.hasLayout){n.display="inline-block"}}n[i]=n["-moz-opacity"]=n["-khtml-opacity"]=j||"";break;case"float":(b&&!e.isIE11)?n.styleFloat=j:n.cssFloat=j;break;default:n[i]=j||""}if(k.settings.update_styles){k.setAttrib(o,"data-mce-style")}})},getStyle:function(l,i,k){l=this.get(l);if(!l){return}if(this.doc.defaultView&&k){i=i.replace(/[A-Z]/g,function(m){return"-"+m});try{return this.doc.defaultView.getComputedStyle(l,null).getPropertyValue(i)}catch(j){return null}}i=i.replace(/-(\D)/g,function(n,m){return m.toUpperCase()});if(i=="float"){i=b?"styleFloat":"cssFloat"}if(l.currentStyle&&k){return l.currentStyle[i]}return l.style?l.style[i]:undefined},setStyles:function(l,m){var j=this,k=j.settings,i;i=k.update_styles;k.update_styles=0;g(m,function(o,p){j.setStyle(l,p,o)});k.update_styles=i;if(k.update_styles){j.setAttrib(l,k.cssText)}},removeAllAttribs:function(i){return this.run(i,function(l){var k,j=l.attributes;for(k=j.length-1;k>=0;k--){l.removeAttributeNode(j.item(k))}})},setAttrib:function(k,l,i){var j=this;if(!k||!l){return}if(j.settings.strict){l=l.toLowerCase()}return this.run(k,function(p){var o=j.settings;var m=p.getAttribute(l);if(i!==null){switch(l){case"style":if(!d(i,"string")){g(i,function(q,r){j.setStyle(p,r,q)});return}if(o.keep_values){if(i&&!j._isRes(i)){p.setAttribute("data-mce-style",i,2)}else{p.removeAttribute("data-mce-style",2)}}p.style.cssText=i;break;case"class":p.className=i||"";break;case"src":case"href":if(o.keep_values){if(o.url_converter){i=o.url_converter.call(o.url_converter_scope||j,i,l,p)}j.setAttrib(p,"data-mce-"+l,i,2)}break;case"shape":p.setAttribute("data-mce-style",i);break}}if(d(i)&&i!==null&&i.length!==0){p.setAttribute(l,""+i,2)}else{p.removeAttribute(l,2)}if(tinyMCE.activeEditor&&m!=i){var n=tinyMCE.activeEditor;n.onSetAttrib.dispatch(n,p,l,i)}})},setAttribs:function(j,k){var i=this;return this.run(j,function(l){g(k,function(m,o){i.setAttrib(l,o,m)})})},getAttrib:function(m,o,k){var i,j=this,l;m=j.get(m);if(!m||m.nodeType!==1){return k===l?false:k}if(!d(k)){k=""}if(/^(src|href|style|coords|shape)$/.test(o)){i=m.getAttribute("data-mce-"+o);if(i){return i}}if(b&&j.props[o]){i=m[j.props[o]];i=i&&i.nodeValue?i.nodeValue:i}if(!i){i=m.getAttribute(o,2)}if(/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(o)){if(m[j.props[o]]===true&&i===""){return o}return i?o:""}if(m.nodeName==="FORM"&&m.getAttributeNode(o)){return m.getAttributeNode(o).nodeValue}if(o==="style"){i=i||m.style.cssText;if(i){i=j.serializeStyle(j.parseStyle(i),m.nodeName);if(j.settings.keep_values&&!j._isRes(i)){m.setAttribute("data-mce-style",i)}}}if(f&&o==="class"&&i){i=i.replace(/(apple|webkit)\-[a-z\-]+/gi,"")}if(b){switch(o){case"rowspan":case"colspan":if(i===1){i=""}break;case"size":if(i==="+0"||i===20||i===0){i=""}break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":if(i===0){i=""}break;case"hspace":if(i===-1){i=""}break;case"maxlength":case"tabindex":if(i===32768||i===2147483647||i==="32768"){i=""}break;case"multiple":case"compact":case"noshade":case"nowrap":if(i===65535){return o}return k;case"shape":i=i.toLowerCase();break;default:if(o.indexOf("on")===0&&i){i=e._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1",""+i)}}}return(i!==l&&i!==null&&i!=="")?""+i:k},getPos:function(q,l){var j=this,i=0,p=0,m,o=j.doc,k;q=j.get(q);l=l||o.body;if(q){if(q.getBoundingClientRect){q=q.getBoundingClientRect();m=j.boxModel?o.documentElement:o.body;i=q.left+(o.documentElement.scrollLeft||o.body.scrollLeft)-m.clientTop;p=q.top+(o.documentElement.scrollTop||o.body.scrollTop)-m.clientLeft;return{x:i,y:p}}k=q;while(k&&k!=l&&k.nodeType){i+=k.offsetLeft||0;p+=k.offsetTop||0;k=k.offsetParent}k=q.parentNode;while(k&&k!=l&&k.nodeType){i-=k.scrollLeft||0;p-=k.scrollTop||0;k=k.parentNode}}return{x:i,y:p}},parseStyle:function(i){return this.styles.parse(i)},serializeStyle:function(j,i){return this.styles.serialize(j,i)},addStyle:function(j){var k=this.doc,i;styleElm=k.getElementById("mceDefaultStyles");if(!styleElm){styleElm=k.createElement("style"),styleElm.id="mceDefaultStyles";styleElm.type="text/css";i=k.getElementsByTagName("head")[0];if(i.firstChild){i.insertBefore(styleElm,i.firstChild)}else{i.appendChild(styleElm)}}if(styleElm.styleSheet){styleElm.styleSheet.cssText+=j}else{styleElm.appendChild(k.createTextNode(j))}},loadCSS:function(i){var k=this,l=k.doc,j;if(!i){i=""}j=l.getElementsByTagName("head")[0];g(i.split(","),function(m){var n;if(k.files[m]){return}k.files[m]=true;n=k.create("link",{rel:"stylesheet",href:e._addVer(m)});if(b&&!e.isIE11&&l.documentMode&&l.recalc){n.onload=function(){if(l.recalc){l.recalc()}n.onload=null}}j.appendChild(n)})},addClass:function(i,j){return this.run(i,function(k){var l;if(!j){return 0}if(this.hasClass(k,j)){return k.className}l=this.removeClass(k,j);return k.className=(l!=""?(l+" "):"")+j})},removeClass:function(k,l){var i=this,j;return i.run(k,function(n){var m;if(i.hasClass(n,l)){if(!j){j=new RegExp("(^|\\s+)"+l+"(\\s+|$)","g")}m=n.className.replace(j," ");m=e.trim(m!=" "?m:"");n.className=m;if(!m){n.removeAttribute("class");n.removeAttribute("className")}return m}return n.className})},hasClass:function(j,i){j=this.get(j);if(!j||!i){return false}return(" "+j.className+" ").indexOf(" "+i+" ")!==-1},show:function(i){return this.setStyle(i,"display","block")},hide:function(i){return this.setStyle(i,"display","none")},isHidden:function(i){i=this.get(i);return !i||i.style.display=="none"||this.getStyle(i,"display")=="none"},uniqueId:function(i){return(!i?"mce_":i)+(this.counter++)},setHTML:function(k,j){var i=this;return i.run(k,function(m){if(b){while(m.firstChild){m.removeChild(m.firstChild)}try{m.innerHTML="<br />"+j;m.removeChild(m.firstChild)}catch(l){var n=i.create("div");n.innerHTML="<br />"+j;g(e.grep(n.childNodes),function(p,o){if(o&&m.canHaveHTML){m.appendChild(p)}})}}else{m.innerHTML=j}return j})},getOuterHTML:function(k){var j,i=this;k=i.get(k);if(!k){return null}if(k.nodeType===1&&i.hasOuterHTML){return k.outerHTML}j=(k.ownerDocument||i.doc).createElement("body");j.appendChild(k.cloneNode(true));return j.innerHTML},setOuterHTML:function(l,j,m){var i=this;function k(p,o,r){var s,q;q=r.createElement("body");q.innerHTML=o;s=q.lastChild;while(s){i.insertAfter(s.cloneNode(true),p);s=s.previousSibling}i.remove(p)}return this.run(l,function(o){o=i.get(o);if(o.nodeType==1){m=m||o.ownerDocument||i.doc;if(b){try{if(b&&o.nodeType==1){o.outerHTML=j}else{k(o,j,m)}}catch(n){k(o,j,m)}}else{k(o,j,m)}}})},decode:h.decode,encode:h.encodeAllRaw,insertAfter:function(i,j){j=this.get(j);return this.run(i,function(l){var k,m;k=j.parentNode;m=j.nextSibling;if(m){k.insertBefore(l,m)}else{k.appendChild(l)}return l})},replace:function(m,l,i){var j=this;if(d(l,"array")){m=m.cloneNode(true)}return j.run(l,function(k){if(i){g(e.grep(k.childNodes),function(n){m.appendChild(n)})}return k.parentNode.replaceChild(m,k)})},rename:function(l,i){var k=this,j;if(l.nodeName!=i.toUpperCase()){j=k.create(i);g(k.getAttribs(l),function(m){k.setAttrib(j,m.nodeName,k.getAttrib(l,m.nodeName))});k.replace(j,l,1)}return j||l},findCommonAncestor:function(k,i){var l=k,j;while(l){j=i;while(j&&l!=j){j=j.parentNode}if(l==j){break}l=l.parentNode}if(!l&&k.ownerDocument){return k.ownerDocument.documentElement}return l},toHex:function(i){var k=/^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(i);function j(l){l=parseInt(l,10).toString(16);return l.length>1?l:"0"+l}if(k){i="#"+j(k[1])+j(k[2])+j(k[3]);return i}return i},getClasses:function(){var n=this,j=[],m,o={},p=n.settings.class_filter,l;if(n.classes){return n.classes}function q(i){g(i.imports,function(s){q(s)});g(i.cssRules||i.rules,function(t){switch(t.type||1){case 1:if(t.selectorText){g(t.selectorText.split(","),function(r){r=r.replace(/^\s*|\s*$|^\s\./g,"");if(/\.mce/.test(r)||!/\.[\w\-]+$/.test(r)){return}l=r;r=e._replace(/.*\.([a-z0-9_\-]+).*/i,"$1",r);if(p&&!(r=p(r,l))){return}if(!o[r]){j.push({"class":r});o[r]=1}})}break;case 3:try{q(t.styleSheet)}catch(s){}break}})}try{g(n.doc.styleSheets,q)}catch(k){}if(j.length>0){n.classes=j}return j},run:function(l,k,j){var i=this,m;if(i.doc&&typeof(l)==="string"){l=i.get(l)}if(!l){return false}j=j||this;if(!l.nodeType&&(l.length||l.length===0)){m=[];g(l,function(o,n){if(o){if(typeof(o)=="string"){o=i.doc.getElementById(o)}m.push(k.call(j,o,n))}});return m}return k.call(j,l)},getAttribs:function(j){var i;j=this.get(j);if(!j){return[]}if(b){i=[];if(j.nodeName=="OBJECT"){return j.attributes}if(j.nodeName==="OPTION"&&this.getAttrib(j,"selected")){i.push({specified:1,nodeName:"selected"})}j.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi,"").replace(/[\w:\-]+/gi,function(k){i.push({specified:1,nodeName:k})});return i}return j.attributes},isEmpty:function(m,k){var r=this,o,n,q,j,l,p=0;m=m.firstChild;if(m){j=new e.dom.TreeWalker(m,m.parentNode);k=k||r.schema?r.schema.getNonEmptyElements():null;do{q=m.nodeType;if(q===1){if(m.getAttribute("data-mce-bogus")){continue}l=m.nodeName.toLowerCase();if(k&&k[l]){if(l==="br"){p++;continue}return false}n=r.getAttribs(m);o=m.attributes.length;while(o--){l=m.attributes[o].nodeName;if(l==="name"||l==="data-mce-bookmark"){return false}}}if(q==8){return false}if((q===3&&!a.test(m.nodeValue))){return false}}while(m=j.next())}return p<=1},destroy:function(j){var i=this;i.win=i.doc=i.root=i.events=i.frag=null;if(!j){e.removeUnload(i.destroy)}},createRng:function(){var i=this.doc;return i.createRange?i.createRange():new e.dom.Range(this)},nodeIndex:function(m,n){var i=0,k,l,j;if(m){for(k=m.nodeType,m=m.previousSibling,l=m;m;m=m.previousSibling){j=m.nodeType;if(n&&j==3){if(j==k||!m.nodeValue.length){continue}}i++;k=j}}return i},split:function(m,l,p){var q=this,i=q.createRng(),n,k,o;function j(v){var t,s=v.childNodes,u=v.nodeType;function x(A){var z=A.previousSibling&&A.previousSibling.nodeName=="SPAN";var y=A.nextSibling&&A.nextSibling.nodeName=="SPAN";return z&&y}if(u==1&&v.getAttribute("data-mce-type")=="bookmark"){return}for(t=s.length-1;t>=0;t--){j(s[t])}if(u!=9){if(u==3&&v.nodeValue.length>0){var r=e.trim(v.nodeValue).length;if(!q.isBlock(v.parentNode)||r>0||r===0&&x(v)){return}}else{if(u==1){s=v.childNodes;if(s.length==1&&s[0]&&s[0].nodeType==1&&s[0].getAttribute("data-mce-type")=="bookmark"){v.parentNode.insertBefore(s[0],v)}if(s.length||/^(br|hr|input|img)$/i.test(v.nodeName)){return}}}q.remove(v)}return v}if(m&&l){i.setStart(m.parentNode,q.nodeIndex(m));i.setEnd(l.parentNode,q.nodeIndex(l));n=i.extractContents();i=q.createRng();i.setStart(l.parentNode,q.nodeIndex(l)+1);i.setEnd(m.parentNode,q.nodeIndex(m)+1);k=i.extractContents();o=m.parentNode;o.insertBefore(j(n),m);if(p){o.replaceChild(p,l)}else{o.insertBefore(l,m)}o.insertBefore(j(k),m);q.remove(m);return p||l}},bind:function(l,i,k,j){return this.events.add(l,i,k,j||this)},unbind:function(k,i,j){return this.events.remove(k,i,j)},fire:function(k,j,i){return this.events.fire(k,j,i)},getContentEditable:function(j){var i;if(j.nodeType!=1){return null}i=j.getAttribute("data-mce-contenteditable");if(i&&i!=="inherit"){return i}return j.contentEditable!=="inherit"?j.contentEditable:null},_findSib:function(l,i,j){var k=this,m=i;if(l){if(d(m,"string")){m=function(n){return k.is(n,i)}}for(l=l[j];l;l=l[j]){if(m(l)){return l}}}return null},_isRes:function(i){return/^(top|left|bottom|right|width|height)/i.test(i)||/;\s*(top|left|bottom|right|width|height)/i.test(i)}});e.DOM=new e.dom.DOMUtils(document,{process_html:0})})(tinymce);(function(a){function b(c){var O=this,e=c.doc,U=0,F=1,j=2,E=true,S=false,W="startOffset",h="startContainer",Q="endContainer",A="endOffset",k=tinymce.extend,n=c.nodeIndex;k(O,{startContainer:e,startOffset:0,endContainer:e,endOffset:0,collapsed:E,commonAncestorContainer:e,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:q,setEnd:s,setStartBefore:g,setStartAfter:J,setEndBefore:K,setEndAfter:u,collapse:B,selectNode:y,selectNodeContents:G,compareBoundaryPoints:v,deleteContents:p,extractContents:I,cloneContents:d,insertNode:D,surroundContents:N,cloneRange:L,toStringIE:T});function x(){return e.createDocumentFragment()}function q(X,t){C(E,X,t)}function s(X,t){C(S,X,t)}function g(t){q(t.parentNode,n(t))}function J(t){q(t.parentNode,n(t)+1)}function K(t){s(t.parentNode,n(t))}function u(t){s(t.parentNode,n(t)+1)}function B(t){if(t){O[Q]=O[h];O[A]=O[W]}else{O[h]=O[Q];O[W]=O[A]}O.collapsed=E}function y(t){g(t);u(t)}function G(t){q(t,0);s(t,t.nodeType===1?t.childNodes.length:t.nodeValue.length)}function v(aa,t){var ad=O[h],Y=O[W],ac=O[Q],X=O[A],ab=t.startContainer,af=t.startOffset,Z=t.endContainer,ae=t.endOffset;if(aa===0){return H(ad,Y,ab,af)}if(aa===1){return H(ac,X,ab,af)}if(aa===2){return H(ac,X,Z,ae)}if(aa===3){return H(ad,Y,Z,ae)}}function p(){l(j)}function I(){return l(U)}function d(){return l(F)}function D(aa){var X=this[h],t=this[W],Z,Y;if((X.nodeType===3||X.nodeType===4)&&X.nodeValue){if(!t){X.parentNode.insertBefore(aa,X)}else{if(t>=X.nodeValue.length){c.insertAfter(aa,X)}else{Z=X.splitText(t);X.parentNode.insertBefore(aa,Z)}}}else{if(X.childNodes.length>0){Y=X.childNodes[t]}if(Y){X.insertBefore(aa,Y)}else{X.appendChild(aa)}}}function N(X){var t=O.extractContents();O.insertNode(X);X.appendChild(t);O.selectNode(X)}function L(){return k(new b(c),{startContainer:O[h],startOffset:O[W],endContainer:O[Q],endOffset:O[A],collapsed:O.collapsed,commonAncestorContainer:O.commonAncestorContainer})}function P(t,X){var Y;if(t.nodeType==3){return t}if(X<0){return t}Y=t.firstChild;while(Y&&X>0){--X;Y=Y.nextSibling}if(Y){return Y}return t}function m(){return(O[h]==O[Q]&&O[W]==O[A])}function H(Z,ab,X,aa){var ac,Y,t,ad,af,ae;if(Z==X){if(ab==aa){return 0}if(ab<aa){return -1}return 1}ac=X;while(ac&&ac.parentNode!=Z){ac=ac.parentNode}if(ac){Y=0;t=Z.firstChild;while(t!=ac&&Y<ab){Y++;t=t.nextSibling}if(ab<=Y){return -1}return 1}ac=Z;while(ac&&ac.parentNode!=X){ac=ac.parentNode}if(ac){Y=0;t=X.firstChild;while(t!=ac&&Y<aa){Y++;t=t.nextSibling}if(Y<aa){return -1}return 1}ad=c.findCommonAncestor(Z,X);af=Z;while(af&&af.parentNode!=ad){af=af.parentNode}if(!af){af=ad}ae=X;while(ae&&ae.parentNode!=ad){ae=ae.parentNode}if(!ae){ae=ad}if(af==ae){return 0}t=ad.firstChild;while(t){if(t==af){return -1}if(t==ae){return 1}t=t.nextSibling}}function C(X,aa,Z){var t,Y;if(X){O[h]=aa;O[W]=Z}else{O[Q]=aa;O[A]=Z}t=O[Q];while(t.parentNode){t=t.parentNode}Y=O[h];while(Y.parentNode){Y=Y.parentNode}if(Y==t){if(H(O[h],O[W],O[Q],O[A])>0){O.collapse(X)}}else{O.collapse(X)}O.collapsed=m();O.commonAncestorContainer=c.findCommonAncestor(O[h],O[Q])}function l(ad){var ac,Z=0,af=0,X,ab,Y,aa,t,ae;if(O[h]==O[Q]){return f(ad)}for(ac=O[Q],X=ac.parentNode;X;ac=X,X=X.parentNode){if(X==O[h]){return r(ac,ad)}++Z}for(ac=O[h],X=ac.parentNode;X;ac=X,X=X.parentNode){if(X==O[Q]){return V(ac,ad)}++af}ab=af-Z;Y=O[h];while(ab>0){Y=Y.parentNode;ab--}aa=O[Q];while(ab<0){aa=aa.parentNode;ab++}for(t=Y.parentNode,ae=aa.parentNode;t!=ae;t=t.parentNode,ae=ae.parentNode){Y=t;aa=ae}return o(Y,aa,ad)}function f(ac){var ae,af,t,Y,Z,ad,aa,X,ab;if(ac!=j){ae=x()}if(O[W]==O[A]){return ae}if(O[h].nodeType==3){af=O[h].nodeValue;t=af.substring(O[W],O[A]);if(ac!=F){Y=O[h];X=O[W];ab=O[A]-O[W];if(X===0&&ab>=Y.nodeValue.length-1){Y.parentNode.removeChild(Y)}else{Y.deleteData(X,ab)}O.collapse(E)}if(ac==j){return}if(t.length>0){ae.appendChild(e.createTextNode(t))}return ae}Y=P(O[h],O[W]);Z=O[A]-O[W];while(Y&&Z>0){ad=Y.nextSibling;aa=z(Y,ac);if(ae){ae.appendChild(aa)}--Z;Y=ad}if(ac!=F){O.collapse(E)}return ae}function r(ad,aa){var ac,ab,X,t,Z,Y;if(aa!=j){ac=x()}ab=i(ad,aa);if(ac){ac.appendChild(ab)}X=n(ad);t=X-O[W];if(t<=0){if(aa!=F){O.setEndBefore(ad);O.collapse(S)}return ac}ab=ad.previousSibling;while(t>0){Z=ab.previousSibling;Y=z(ab,aa);if(ac){ac.insertBefore(Y,ac.firstChild)}--t;ab=Z}if(aa!=F){O.setEndBefore(ad);O.collapse(S)}return ac}function V(ab,aa){var ad,X,ac,t,Z,Y;if(aa!=j){ad=x()}ac=R(ab,aa);if(ad){ad.appendChild(ac)}X=n(ab);++X;t=O[A]-X;ac=ab.nextSibling;while(ac&&t>0){Z=ac.nextSibling;Y=z(ac,aa);if(ad){ad.appendChild(Y)}--t;ac=Z}if(aa!=F){O.setStartAfter(ab);O.collapse(E)}return ad}function o(ab,t,ae){var Y,ag,aa,ac,ad,X,af,Z;if(ae!=j){ag=x()}Y=R(ab,ae);if(ag){ag.appendChild(Y)}aa=ab.parentNode;ac=n(ab);ad=n(t);++ac;X=ad-ac;af=ab.nextSibling;while(X>0){Z=af.nextSibling;Y=z(af,ae);if(ag){ag.appendChild(Y)}af=Z;--X}Y=i(t,ae);if(ag){ag.appendChild(Y)}if(ae!=F){O.setStartAfter(ab);O.collapse(E)}return ag}function i(ac,ad){var Y=P(O[Q],O[A]-1),ae,ab,aa,t,X,Z=Y!=O[Q];if(Y==ac){return M(Y,Z,S,ad)}ae=Y.parentNode;ab=M(ae,S,S,ad);while(ae){while(Y){aa=Y.previousSibling;t=M(Y,Z,S,ad);if(ad!=j){ab.insertBefore(t,ab.firstChild)}Z=E;Y=aa}if(ae==ac){return ab}Y=ae.previousSibling;ae=ae.parentNode;X=M(ae,S,S,ad);if(ad!=j){X.appendChild(ab)}ab=X}}function R(ac,ad){var Z=P(O[h],O[W]),aa=Z!=O[h],ae,ab,Y,t,X;if(Z==ac){return M(Z,aa,E,ad)}ae=Z.parentNode;ab=M(ae,S,E,ad);while(ae){while(Z){Y=Z.nextSibling;t=M(Z,aa,E,ad);if(ad!=j){ab.appendChild(t)}aa=E;Z=Y}if(ae==ac){return ab}Z=ae.nextSibling;ae=ae.parentNode;X=M(ae,S,E,ad);if(ad!=j){X.appendChild(ab)}ab=X}}function M(t,aa,ad,ae){var Z,Y,ab,X,ac;if(aa){return z(t,ae)}if(t.nodeType==3){Z=t.nodeValue;if(ad){X=O[W];Y=Z.substring(X);ab=Z.substring(0,X)}else{X=O[A];Y=Z.substring(0,X);ab=Z.substring(X)}if(ae!=F){t.nodeValue=ab}if(ae==j){return}ac=c.clone(t,S);ac.nodeValue=Y;return ac}if(ae==j){return}return c.clone(t,S)}function z(X,t){if(t!=j){return t==F?c.clone(X,E):X}X.parentNode.removeChild(X)}function T(){return c.create("body",null,d()).outerText}return O}a.Range=b;b.prototype.toString=function(){return this.toStringIE()}})(tinymce.dom);(function(){function a(d){var b=this,h=d.dom,c=true,f=false;function e(i,j){var k,t=0,q,n,m,l,o,r,p=-1,s;k=i.duplicate();k.collapse(j);s=k.parentElement();if(s.ownerDocument!==d.dom.doc){return}while(s.contentEditable==="false"){s=s.parentNode}if(!s.hasChildNodes()){return{node:s,inside:1}}m=s.children;q=m.length-1;while(t<=q){r=Math.floor((t+q)/2);l=m[r];k.moveToElementText(l);p=k.compareEndPoints(j?"StartToStart":"EndToEnd",i);if(p>0){q=r-1}else{if(p<0){t=r+1}else{return{node:l}}}}if(p<0){if(!l){k.moveToElementText(s);k.collapse(true);l=s;n=true}else{k.collapse(false)}o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",1)===0||s!=k.parentElement()){break}o++}}else{k.collapse(true);o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",-1)===0||s!=k.parentElement()){break}o++}}return{node:l,position:p,offset:o,inside:n}}function g(){var i=d.getRng(),r=h.createRng(),l,k,p,q,m,j;l=i.item?i.item(0):i.parentElement();if(l.ownerDocument!=h.doc){return r}k=d.isCollapsed();if(i.item){r.setStart(l.parentNode,h.nodeIndex(l));r.setEnd(r.startContainer,r.startOffset+1);return r}function o(A){var u=e(i,A),s,y,z=0,x,v,t;s=u.node;y=u.offset;if(u.inside&&!s.hasChildNodes()){r[A?"setStart":"setEnd"](s,0);return}if(y===v){r[A?"setStartBefore":"setEndAfter"](s);return}if(u.position<0){x=u.inside?s.firstChild:s.nextSibling;if(!x){r[A?"setStartAfter":"setEndAfter"](s);return}if(!y){if(x.nodeType==3){r[A?"setStart":"setEnd"](x,0)}else{r[A?"setStartBefore":"setEndBefore"](x)}return}while(x){t=x.nodeValue;z+=t.length;if(z>=y){s=x;z-=y;z=t.length-z;break}x=x.nextSibling}}else{x=s.previousSibling;if(!x){return r[A?"setStartBefore":"setEndBefore"](s)}if(!y){if(s.nodeType==3){r[A?"setStart":"setEnd"](x,s.nodeValue.length)}else{r[A?"setStartAfter":"setEndAfter"](x)}return}while(x){z+=x.nodeValue.length;if(z>=y){s=x;z-=y;break}x=x.previousSibling}}r[A?"setStart":"setEnd"](s,z)}try{o(true);if(!k){o()}}catch(n){if(n.number==-2147024809){m=b.getBookmark(2);p=i.duplicate();p.collapse(true);l=p.parentElement();if(!k){p=i.duplicate();p.collapse(false);q=p.parentElement();q.innerHTML=q.innerHTML}l.innerHTML=l.innerHTML;b.moveToBookmark(m);i=d.getRng();o(true);if(!k){o()}}else{throw n}}return r}this.getBookmark=function(m){var j=d.getRng(),o,i,l={};function n(u){var t,p,s,r,q=[];t=u.parentNode;p=h.getRoot().parentNode;while(t!=p&&t.nodeType!==9){s=t.children;r=s.length;while(r--){if(u===s[r]){q.push(r);break}}u=t;t=t.parentNode}return q}function k(q){var p;p=e(j,q);if(p){return{position:p.position,offset:p.offset,indexes:n(p.node),inside:p.inside}}}if(m===2){if(!j.item){l.start=k(true);if(!d.isCollapsed()){l.end=k()}}else{l.start={ctrl:true,indexes:n(j.item(0))}}}return l};this.moveToBookmark=function(k){var j,i=h.doc.body;function m(o){var r,q,n,p;r=h.getRoot();for(q=o.length-1;q>=0;q--){p=r.children;n=o[q];if(n<=p.length-1){r=p[n]}}return r}function l(r){var n=k[r?"start":"end"],q,p,o;if(n){q=n.position>0;p=i.createTextRange();p.moveToElementText(m(n.indexes));offset=n.offset;if(offset!==o){p.collapse(n.inside||q);p.moveStart("character",q?-offset:offset)}else{p.collapse(r)}j.setEndPoint(r?"StartToStart":"EndToStart",p);if(r){j.collapse(true)}}}if(k.start){if(k.start.ctrl){j=i.createControlRange();j.addElement(m(k.start.indexes));j.select()}else{j=i.createTextRange();l(true);l();j.select()}}};this.addRange=function(i){var n,l,k,p,v,q,t,s=d.dom.doc,m=s.body,r,u;function j(C){var y,B,x,A,z;x=h.create("a");y=C?k:v;B=C?p:q;A=n.duplicate();if(y==s||y==s.documentElement){y=m;B=0}if(y.nodeType==3){y.parentNode.insertBefore(x,y);A.moveToElementText(x);A.moveStart("character",B);h.remove(x);n.setEndPoint(C?"StartToStart":"EndToEnd",A)}else{z=y.childNodes;if(z.length){if(B>=z.length){h.insertAfter(x,z[z.length-1])}else{y.insertBefore(x,z[B])}A.moveToElementText(x)}else{if(y.canHaveHTML){y.innerHTML="<span>\uFEFF</span>";x=y.firstChild;A.moveToElementText(x);A.collapse(f)}}n.setEndPoint(C?"StartToStart":"EndToEnd",A);h.remove(x)}}k=i.startContainer;p=i.startOffset;v=i.endContainer;q=i.endOffset;n=m.createTextRange();if(k==v&&k.nodeType==1){if(p==q&&!k.hasChildNodes()){if(k.canHaveHTML){t=k.previousSibling;if(t&&!t.hasChildNodes()&&h.isBlock(t)){t.innerHTML="\uFEFF"}else{t=null}k.innerHTML="<span>\uFEFF</span><span>\uFEFF</span>";n.moveToElementText(k.lastChild);n.select();h.doc.selection.clear();k.innerHTML="";if(t){t.innerHTML=""}return}else{p=h.nodeIndex(k);k=k.parentNode}}if(p==q-1){try{u=k.childNodes[p];l=m.createControlRange();l.addElement(u);l.select();r=d.getRng();if(r.item&&u===r.item(0)){return}}catch(o){}}}j(true);j();n.select()};this.getRangeAt=g}tinymce.dom.TridentSelection=a})();(function(){var n=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,i="sizcache",o=0,r=Object.prototype.toString,h=false,g=true,q=/\\/g,u=/\r\n/g,x=/\W/;[0,0].sort(function(){g=false;return 0});var d=function(C,e,F,G){F=F||[];e=e||document;var I=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!C||typeof C!=="string"){return F}var z,K,N,y,J,M,L,E,B=true,A=d.isXML(e),D=[],H=C;do{n.exec("");z=n.exec(H);if(z){H=z[3];D.push(z[1]);if(z[2]){y=z[3];break}}}while(z);if(D.length>1&&j.exec(C)){if(D.length===2&&k.relative[D[0]]){K=s(D[0]+D[1],e,G)}else{K=k.relative[D[0]]?[e]:d(D.shift(),e);while(D.length){C=D.shift();if(k.relative[C]){C+=D.shift()}K=s(C,K,G)}}}else{if(!G&&D.length>1&&e.nodeType===9&&!A&&k.match.ID.test(D[0])&&!k.match.ID.test(D[D.length-1])){J=d.find(D.shift(),e,A);e=J.expr?d.filter(J.expr,J.set)[0]:J.set[0]}if(e){J=G?{expr:D.pop(),set:l(G)}:d.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&e.parentNode?e.parentNode:e,A);K=J.expr?d.filter(J.expr,J.set):J.set;if(D.length>0){N=l(K)}else{B=false}while(D.length){M=D.pop();L=M;if(!k.relative[M]){M=""}else{L=D.pop()}if(L==null){L=e}k.relative[M](N,L,A)}}else{N=D=[]}}if(!N){N=K}if(!N){d.error(M||C)}if(r.call(N)==="[object Array]"){if(!B){F.push.apply(F,N)}else{if(e&&e.nodeType===1){for(E=0;N[E]!=null;E++){if(N[E]&&(N[E]===true||N[E].nodeType===1&&d.contains(e,N[E]))){F.push(K[E])}}}else{for(E=0;N[E]!=null;E++){if(N[E]&&N[E].nodeType===1){F.push(K[E])}}}}}else{l(N,F)}if(y){d(y,I,F,G);d.uniqueSort(F)}return F};d.uniqueSort=function(y){if(p){h=g;y.sort(p);if(h){for(var e=1;e<y.length;e++){if(y[e]===y[e-1]){y.splice(e--,1)}}}}return y};d.matches=function(e,y){return d(e,null,null,y)};d.matchesSelector=function(e,y){return d(y,null,null,[e]).length>0};d.find=function(E,e,F){var D,z,B,A,C,y;if(!E){return[]}for(z=0,B=k.order.length;z<B;z++){C=k.order[z];if((A=k.leftMatch[C].exec(E))){y=A[1];A.splice(1,1);if(y.substr(y.length-1)!=="\\"){A[1]=(A[1]||"").replace(q,"");D=k.find[C](A,e,F);if(D!=null){E=E.replace(k.match[C],"");break}}}}if(!D){D=typeof e.getElementsByTagName!=="undefined"?e.getElementsByTagName("*"):[]}return{set:D,expr:E}};d.filter=function(I,H,L,B){var D,e,G,N,K,y,A,C,J,z=I,M=[],F=H,E=H&&H[0]&&d.isXML(H[0]);while(I&&H.length){for(G in k.filter){if((D=k.leftMatch[G].exec(I))!=null&&D[2]){y=k.filter[G];A=D[1];e=false;D.splice(1,1);if(A.substr(A.length-1)==="\\"){continue}if(F===M){M=[]}if(k.preFilter[G]){D=k.preFilter[G](D,F,L,M,B,E);if(!D){e=N=true}else{if(D===true){continue}}}if(D){for(C=0;(K=F[C])!=null;C++){if(K){N=y(K,D,C,F);J=B^N;if(L&&N!=null){if(J){e=true}else{F[C]=false}}else{if(J){M.push(K);e=true}}}}}if(N!==undefined){if(!L){F=M}I=I.replace(k.match[G],"");if(!e){return[]}break}}}if(I===z){if(e==null){d.error(I)}else{break}}z=I}return F};d.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};var b=d.getText=function(B){var z,A,e=B.nodeType,y="";if(e){if(e===1||e===9||e===11){if(typeof B.textContent==="string"){return B.textContent}else{if(typeof B.innerText==="string"){return B.innerText.replace(u,"")}else{for(B=B.firstChild;B;B=B.nextSibling){y+=b(B)}}}}else{if(e===3||e===4){return B.nodeValue}}}else{for(z=0;(A=B[z]);z++){if(A.nodeType!==8){y+=b(A)}}}return y};var k=d.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")},type:function(e){return e.getAttribute("type")}},relative:{"+":function(D,y){var A=typeof y==="string",C=A&&!x.test(y),E=A&&!C;if(C){y=y.toLowerCase()}for(var z=0,e=D.length,B;z<e;z++){if((B=D[z])){while((B=B.previousSibling)&&B.nodeType!==1){}D[z]=E||B&&B.nodeName.toLowerCase()===y?B||false:B===y}}if(E){d.filter(y,D,true)}},">":function(D,y){var C,B=typeof y==="string",z=0,e=D.length;if(B&&!x.test(y)){y=y.toLowerCase();for(;z<e;z++){C=D[z];if(C){var A=C.parentNode;D[z]=A.nodeName.toLowerCase()===y?A:false}}}else{for(;z<e;z++){C=D[z];if(C){D[z]=B?C.parentNode:C.parentNode===y}}if(B){d.filter(y,D,true)}}},"":function(A,y,C){var B,z=o++,e=t;if(typeof y==="string"&&!x.test(y)){y=y.toLowerCase();B=y;e=a}e("parentNode",y,z,A,B,C)},"~":function(A,y,C){var B,z=o++,e=t;if(typeof y==="string"&&!x.test(y)){y=y.toLowerCase();B=y;e=a}e("previousSibling",y,z,A,B,C)}},find:{ID:function(y,z,A){if(typeof z.getElementById!=="undefined"&&!A){var e=z.getElementById(y[1]);return e&&e.parentNode?[e]:[]}},NAME:function(z,C){if(typeof C.getElementsByName!=="undefined"){var y=[],B=C.getElementsByName(z[1]);for(var A=0,e=B.length;A<e;A++){if(B[A].getAttribute("name")===z[1]){y.push(B[A])}}return y.length===0?null:y}},TAG:function(e,y){if(typeof y.getElementsByTagName!=="undefined"){return y.getElementsByTagName(e[1])}}},preFilter:{CLASS:function(A,y,z,e,D,E){A=" "+A[1].replace(q,"")+" ";if(E){return A}for(var B=0,C;(C=y[B])!=null;B++){if(C){if(D^(C.className&&(" "+C.className+" ").replace(/[\t\n\r]/g," ").indexOf(A)>=0)){if(!z){e.push(C)}}else{if(z){y[B]=false}}}}return false},ID:function(e){return e[1].replace(q,"")},TAG:function(y,e){return y[1].replace(q,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){d.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var y=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(y[1]+(y[2]||1))-0;e[3]=y[3]-0}else{if(e[2]){d.error(e[0])}}e[0]=o++;return e},ATTR:function(B,y,z,e,C,D){var A=B[1]=B[1].replace(q,"");if(!D&&k.attrMap[A]){B[1]=k.attrMap[A]}B[4]=(B[4]||B[5]||"").replace(q,"");if(B[2]==="~="){B[4]=" "+B[4]+" "}return B},PSEUDO:function(B,y,z,e,C){if(B[1]==="not"){if((n.exec(B[3])||"").length>1||/^\w/.test(B[3])){B[3]=d(B[3],null,null,y)}else{var A=d.filter(B[3],y,z,true^C);if(!z){e.push.apply(e,A)}return false}}else{if(k.match.POS.test(B[0])||k.match.CHILD.test(B[0])){return true}}return B},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(z,y,e){return !!d(e[3],z).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(z){var e=z.getAttribute("type"),y=z.type;return z.nodeName.toLowerCase()==="input"&&"text"===y&&(e===y||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===y.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===y.type},button:function(y){var e=y.nodeName.toLowerCase();return e==="input"&&"button"===y.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(y,e){return e===0},last:function(z,y,e,A){return y===A.length-1},even:function(y,e){return e%2===0},odd:function(y,e){return e%2===1},lt:function(z,y,e){return y<e[3]-0},gt:function(z,y,e){return y>e[3]-0},nth:function(z,y,e){return e[3]-0===y},eq:function(z,y,e){return e[3]-0===y}},filter:{PSEUDO:function(z,E,D,F){var e=E[1],y=k.filters[e];if(y){return y(z,D,E,F)}else{if(e==="contains"){return(z.textContent||z.innerText||b([z])||"").indexOf(E[3])>=0}else{if(e==="not"){var A=E[3];for(var C=0,B=A.length;C<B;C++){if(A[C]===z){return false}}return true}else{d.error(e)}}}},CHILD:function(z,B){var A,H,D,G,e,C,F,E=B[1],y=z;switch(E){case"only":case"first":while((y=y.previousSibling)){if(y.nodeType===1){return false}}if(E==="first"){return true}y=z;case"last":while((y=y.nextSibling)){if(y.nodeType===1){return false}}return true;case"nth":A=B[2];H=B[3];if(A===1&&H===0){return true}D=B[0];G=z.parentNode;if(G&&(G[i]!==D||!z.nodeIndex)){C=0;for(y=G.firstChild;y;y=y.nextSibling){if(y.nodeType===1){y.nodeIndex=++C}}G[i]=D}F=z.nodeIndex-H;if(A===0){return F===0}else{return(F%A===0&&F/A>=0)}}},ID:function(y,e){return y.nodeType===1&&y.getAttribute("id")===e},TAG:function(y,e){return(e==="*"&&y.nodeType===1)||!!y.nodeName&&y.nodeName.toLowerCase()===e},CLASS:function(y,e){return(" "+(y.className||y.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(C,A){var z=A[1],e=d.attr?d.attr(C,z):k.attrHandle[z]?k.attrHandle[z](C):C[z]!=null?C[z]:C.getAttribute(z),D=e+"",B=A[2],y=A[4];return e==null?B==="!=":!B&&d.attr?e!=null:B==="="?D===y:B==="*="?D.indexOf(y)>=0:B==="~="?(" "+D+" ").indexOf(y)>=0:!y?D&&e!==false:B==="!="?D!==y:B==="^="?D.indexOf(y)===0:B==="$="?D.substr(D.length-y.length)===y:B==="|="?D===y||D.substr(0,y.length+1)===y+"-":false},POS:function(B,y,z,C){var e=y[2],A=k.setFilters[e];if(A){return A(B,z,y,C)}}}};var j=k.match.POS,c=function(y,e){return"\\"+(e-0+1)};for(var f in k.match){k.match[f]=new RegExp(k.match[f].source+(/(?![^\[]*\])(?![^\(]*\))/.source));k.leftMatch[f]=new RegExp(/(^(?:.|\r|\n)*?)/.source+k.match[f].source.replace(/\\(\d+)/g,c))}k.match.globalPOS=j;var l=function(y,e){y=Array.prototype.slice.call(y,0);if(e){e.push.apply(e,y);return e}return y};try{Array.prototype.slice.call(document.documentElement.childNodes,0)[0].nodeType}catch(v){l=function(B,A){var z=0,y=A||[];if(r.call(B)==="[object Array]"){Array.prototype.push.apply(y,B)}else{if(typeof B.length==="number"){for(var e=B.length;z<e;z++){y.push(B[z])}}else{for(;B[z];z++){y.push(B[z])}}}return y}}var p,m;if(document.documentElement.compareDocumentPosition){p=function(y,e){if(y===e){h=true;return 0}if(!y.compareDocumentPosition||!e.compareDocumentPosition){return y.compareDocumentPosition?-1:1}return y.compareDocumentPosition(e)&4?-1:1}}else{p=function(F,E){if(F===E){h=true;return 0}else{if(F.sourceIndex&&E.sourceIndex){return F.sourceIndex-E.sourceIndex}}var C,y,z=[],e=[],B=F.parentNode,D=E.parentNode,G=B;if(B===D){return m(F,E)}else{if(!B){return -1}else{if(!D){return 1}}}while(G){z.unshift(G);G=G.parentNode}G=D;while(G){e.unshift(G);G=G.parentNode}C=z.length;y=e.length;for(var A=0;A<C&&A<y;A++){if(z[A]!==e[A]){return m(z[A],e[A])}}return A===C?m(F,e[A],-1):m(z[A],E,1)};m=function(y,e,z){if(y===e){return z}var A=y.nextSibling;while(A){if(A===e){return -1}A=A.nextSibling}return 1}}(function(){var y=document.createElement("div"),z="script"+(new Date()).getTime(),e=document.documentElement;y.innerHTML="<a name='"+z+"'/>";e.insertBefore(y,e.firstChild);if(document.getElementById(z)){k.find.ID=function(B,C,D){if(typeof C.getElementById!=="undefined"&&!D){var A=C.getElementById(B[1]);return A?A.id===B[1]||typeof A.getAttributeNode!=="undefined"&&A.getAttributeNode("id").nodeValue===B[1]?[A]:undefined:[]}};k.filter.ID=function(C,A){var B=typeof C.getAttributeNode!=="undefined"&&C.getAttributeNode("id");return C.nodeType===1&&B&&B.nodeValue===A}}e.removeChild(y);e=y=null})();(function(){var e=document.createElement("div");e.appendChild(document.createComment(""));if(e.getElementsByTagName("*").length>0){k.find.TAG=function(y,C){var B=C.getElementsByTagName(y[1]);if(y[1]==="*"){var A=[];for(var z=0;B[z];z++){if(B[z].nodeType===1){A.push(B[z])}}B=A}return B}}e.innerHTML="<a href='#'></a>";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){k.attrHandle.href=function(y){return y.getAttribute("href",2)}}e=null})();if(document.querySelectorAll){(function(){var e=d,A=document.createElement("div"),z="__sizzle__";A.innerHTML="<p class='TEST'></p>";if(A.querySelectorAll&&A.querySelectorAll(".TEST").length===0){return}d=function(L,C,G,K){C=C||document;if(!K&&!d.isXML(C)){var J=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(L);if(J&&(C.nodeType===1||C.nodeType===9)){if(J[1]){return l(C.getElementsByTagName(L),G)}else{if(J[2]&&k.find.CLASS&&C.getElementsByClassName){return l(C.getElementsByClassName(J[2]),G)}}}if(C.nodeType===9){if(L==="body"&&C.body){return l([C.body],G)}else{if(J&&J[3]){var F=C.getElementById(J[3]);if(F&&F.parentNode){if(F.id===J[3]){return l([F],G)}}else{return l([],G)}}}try{return l(C.querySelectorAll(L),G)}catch(H){}}else{if(C.nodeType===1&&C.nodeName.toLowerCase()!=="object"){var D=C,E=C.getAttribute("id"),B=E||z,N=C.parentNode,M=/^\s*[+~]/.test(L);if(!E){C.setAttribute("id",B)}else{B=B.replace(/'/g,"\\$&")}if(M&&N){C=C.parentNode}try{if(!M||N){return l(C.querySelectorAll("[id='"+B+"'] "+L),G)}}catch(I){}finally{if(!E){D.removeAttribute("id")}}}}}return e(L,C,G,K)};for(var y in e){d[y]=e[y]}A=null})()}(function(){var e=document.documentElement,z=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(z){var B=!z.call(document.createElement("div"),"div"),y=false;try{z.call(document.documentElement,"[test!='']:sizzle")}catch(A){y=true}d.matchesSelector=function(D,F){F=F.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!d.isXML(D)){try{if(y||!k.match.PSEUDO.test(F)&&!/!=/.test(F)){var C=z.call(D,F);if(C||!B||D.document&&D.document.nodeType!==11){return C}}}catch(E){}}return d(F,null,null,[D]).length>0}}})();(function(){var e=document.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}k.order.splice(1,0,"CLASS");k.find.CLASS=function(y,z,A){if(typeof z.getElementsByClassName!=="undefined"&&!A){return z.getElementsByClassName(y[1])}};e=null})();function a(y,D,C,G,E,F){for(var A=0,z=G.length;A<z;A++){var e=G[A];if(e){var B=false;e=e[y];while(e){if(e[i]===C){B=G[e.sizset];break}if(e.nodeType===1&&!F){e[i]=C;e.sizset=A}if(e.nodeName.toLowerCase()===D){B=e;break}e=e[y]}G[A]=B}}}function t(y,D,C,G,E,F){for(var A=0,z=G.length;A<z;A++){var e=G[A];if(e){var B=false;e=e[y];while(e){if(e[i]===C){B=G[e.sizset];break}if(e.nodeType===1){if(!F){e[i]=C;e.sizset=A}if(typeof D!=="string"){if(e===D){B=true;break}}else{if(d.filter(D,[e]).length>0){B=e;break}}}e=e[y]}G[A]=B}}}if(document.documentElement.contains){d.contains=function(y,e){return y!==e&&(y.contains?y.contains(e):true)}}else{if(document.documentElement.compareDocumentPosition){d.contains=function(y,e){return !!(y.compareDocumentPosition(e)&16)}}else{d.contains=function(){return false}}}d.isXML=function(e){var y=(e?e.ownerDocument||e:0).documentElement;return y?y.nodeName!=="HTML":false};var s=function(z,e,D){var C,E=[],B="",F=e.nodeType?[e]:e;while((C=k.match.PSEUDO.exec(z))){B+=C[0];z=z.replace(k.match.PSEUDO,"")}z=k.relative[z]?z+"*":z;for(var A=0,y=F.length;A<y;A++){d(z,F[A],E,D)}return d.filter(B,E)};window.tinymce.dom.Sizzle=d})();(function(a){a.dom.Element=function(f,d){var b=this,e,c;b.settings=d=d||{};b.id=f;b.dom=e=d.dom||a.DOM;if(!a.isIE){c=e.get(b.id)}a.each(("getPos,getRect,getParent,add,setStyle,getStyle,setStyles,setAttrib,setAttribs,getAttrib,addClass,removeClass,hasClass,getOuterHTML,setOuterHTML,remove,show,hide,isHidden,setHTML,get").split(/,/),function(g){b[g]=function(){var h=[f],j;for(j=0;j<arguments.length;j++){h.push(arguments[j])}h=e[g].apply(e,h);b.update(g);return h}});a.extend(b,{on:function(i,h,g){return a.dom.Event.add(b.id,i,h,g)},getXY:function(){return{x:parseInt(b.getStyle("left")),y:parseInt(b.getStyle("top"))}},getSize:function(){var g=e.get(b.id);return{w:parseInt(b.getStyle("width")||g.clientWidth),h:parseInt(b.getStyle("height")||g.clientHeight)}},moveTo:function(g,h){b.setStyles({left:g,top:h})},moveBy:function(g,i){var h=b.getXY();b.moveTo(h.x+g,h.y+i)},resizeTo:function(g,i){b.setStyles({width:g,height:i})},resizeBy:function(g,j){var i=b.getSize();b.resizeTo(i.w+g,i.h+j)},update:function(h){var g;if(a.isIE6&&d.blocker){h=h||"";if(h.indexOf("get")===0||h.indexOf("has")===0||h.indexOf("is")===0){return}if(h=="remove"){e.remove(b.blocker);return}if(!b.blocker){b.blocker=e.uniqueId();g=e.add(d.container||e.getRoot(),"iframe",{id:b.blocker,style:"position:absolute;",frameBorder:0,src:'javascript:""'});e.setStyle(g,"opacity",0)}else{g=e.get(b.blocker)}e.setStyles(g,{left:b.getStyle("left",1),top:b.getStyle("top",1),width:b.getStyle("width",1),height:b.getStyle("height",1),display:b.getStyle("display",1),zIndex:parseInt(b.getStyle("zIndex",1)||0)-1})}}})}})(tinymce);(function(d){function f(g){return g.replace(/[\n\r]+/g,"")}var c=d.is,b=d.isIE,e=d.each,a=d.dom.TreeWalker;d.create("tinymce.dom.Selection",{Selection:function(k,j,i,h){var g=this;g.dom=k;g.win=j;g.serializer=i;g.editor=h;e(["onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent"],function(l){g[l]=new d.util.Dispatcher(g)});if(!g.win.getSelection){g.tridentSel=new d.dom.TridentSelection(g)}if(d.isIE&&!d.isIE11&&k.boxModel){this._fixIESelection()}d.addUnload(g.destroy,g)},setCursorLocation:function(i,j){var g=this;var h=g.dom.createRng();h.setStart(i,j);h.setEnd(i,j);g.setRng(h);g.collapse(false)},getContent:function(h){var g=this,i=g.getRng(),m=g.dom.create("body"),k=g.getSel(),j,l,o;h=h||{};j=l="";h.get=true;h.format=h.format||"html";h.forced_root_block="";g.onBeforeGetContent.dispatch(g,h);if(h.format=="text"){return g.isCollapsed()?"":(i.text||(k.toString?k.toString():""))}if(i.cloneContents){o=i.cloneContents();if(o){m.appendChild(o)}}else{if(c(i.item)||c(i.htmlText)){m.innerHTML="<br>"+(i.item?i.item(0).outerHTML:i.htmlText);m.removeChild(m.firstChild)}else{m.innerHTML=i.toString()}}if(/^\s/.test(m.innerHTML)){j=" "}if(/\s+$/.test(m.innerHTML)){l=" "}h.getInner=true;h.content=g.isCollapsed()?"":j+g.serializer.serialize(m,h)+l;g.onGetContent.dispatch(g,h);return h.content},setContent:function(h,j){var o=this,g=o.getRng(),k,l=o.win.document,n,m;j=j||{format:"html"};j.set=true;h=j.content=h;if(!j.no_events){o.onBeforeSetContent.dispatch(o,j)}h=j.content;if(g.insertNode){h+='<span id="__caret">_</span>';if(g.startContainer==l&&g.endContainer==l){l.body.innerHTML=h}else{g.deleteContents();if(l.body.childNodes.length===0){l.body.innerHTML=h}else{if(g.createContextualFragment){g.insertNode(g.createContextualFragment(h))}else{n=l.createDocumentFragment();m=l.createElement("div");n.appendChild(m);m.outerHTML=h;g.insertNode(n)}}}k=o.dom.get("__caret");g=l.createRange();g.setStartBefore(k);g.setEndBefore(k);o.setRng(g);o.dom.remove("__caret");try{o.setRng(g)}catch(i){}}else{if(g.item){l.execCommand("Delete",false,null);g=o.getRng()}if(/^\s+/.test(h)){g.pasteHTML('<span id="__mce_tmp">_</span>'+h);o.dom.remove("__mce_tmp")}else{g.pasteHTML(h)}}if(!j.no_events){o.onSetContent.dispatch(o,j)}},getStart:function(){var i=this,h=i.getRng(),j,g,l,k;if(h.duplicate||h.item){if(h.item){return h.item(0)}l=h.duplicate();l.collapse(1);j=l.parentElement();if(j.ownerDocument!==i.dom.doc){j=i.dom.getRoot()}g=k=h.parentElement();while(k=k.parentNode){if(k==j){j=g;break}}return j}else{j=h.startContainer;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[Math.min(j.childNodes.length-1,h.startOffset)]}if(j&&j.nodeType==3){return j.parentNode}return j}},getEnd:function(){var h=this,g=h.getRng(),j,i;if(g.duplicate||g.item){if(g.item){return g.item(0)}g=g.duplicate();g.collapse(0);j=g.parentElement();if(j.ownerDocument!==h.dom.doc){j=h.dom.getRoot()}if(j&&j.nodeName=="BODY"){return j.lastChild||j}return j}else{j=g.endContainer;i=g.endOffset;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[i>0?i-1:i]}if(j&&j.nodeType==3){return j.parentNode}return j}},getBookmark:function(s,v){var y=this,n=y.dom,h,k,j,o,i,p,q,m="\uFEFF",x;function g(z,A){var t=0;e(n.select(z),function(C,B){if(C==A){t=B}});return t}function u(t){function z(E){var A,D,C,B=E?"start":"end";A=t[B+"Container"];D=t[B+"Offset"];if(A.nodeType==1&&A.nodeName=="TR"){C=A.childNodes;A=C[Math.min(E?D:D-1,C.length-1)];if(A){D=E?0:A.childNodes.length;t["set"+(E?"Start":"End")](A,D)}}}z(true);z();return t}function l(){var z=y.getRng(true),t=n.getRoot(),A={};function B(E,J){var D=E[J?"startContainer":"endContainer"],I=E[J?"startOffset":"endOffset"],C=[],F,H,G=0;if(D.nodeType==3){if(v){for(F=D.previousSibling;F&&F.nodeType==3;F=F.previousSibling){I+=F.nodeValue.length}}C.push(I)}else{H=D.childNodes;if(I>=H.length&&H.length){G=1;I=Math.max(0,H.length-1)}C.push(y.dom.nodeIndex(H[I],v)+G)}for(;D&&D!=t;D=D.parentNode){C.push(y.dom.nodeIndex(D,v))}return C}A.start=B(z,true);if(!y.isCollapsed()){A.end=B(z)}return A}if(s==2){if(y.tridentSel){return y.tridentSel.getBookmark(s)}return l()}if(s){h=y.getRng();if(h.setStart){h={startContainer:h.startContainer,startOffset:h.startOffset,endContainer:h.endContainer,endOffset:h.endOffset}}return{rng:h}}h=y.getRng();j=n.uniqueId();o=tinyMCE.activeEditor.selection.isCollapsed();x="overflow:hidden;line-height:0px";if(h.duplicate||h.item){if(!h.item){k=h.duplicate();try{h.collapse();h.pasteHTML('<span data-mce-type="bookmark" id="'+j+'_start" style="'+x+'">'+m+"</span>");if(!o){k.collapse(false);h.moveToElementText(k.parentElement());if(h.compareEndPoints("StartToEnd",k)===0){k.move("character",-1)}k.pasteHTML('<span data-mce-type="bookmark" id="'+j+'_end" style="'+x+'">'+m+"</span>")}}catch(r){return null}}else{p=h.item(0);i=p.nodeName;return{name:i,index:g(i,p)}}}else{p=y.getNode();i=p.nodeName;if(i=="IMG"){return{name:i,index:g(i,p)}}k=u(h.cloneRange());if(!o){k.collapse(false);k.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_end",style:x},m))}h=u(h);h.collapse(true);h.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_start",style:x},m))}y.moveToBookmark({id:j,keep:1});return{id:j}},moveToBookmark:function(q){var v=this,n=v.dom,l,j,g,i,u,k,x,r,s;function h(C){var t=q[C?"start":"end"],z,A,B,y;if(t){B=t[0];for(A=u,z=t.length-1;z>=1;z--){y=A.childNodes;if(t[z]>y.length-1){return}A=y[t[z]]}if(A.nodeType===3){B=Math.min(t[0],A.nodeValue.length)}if(A.nodeType===1){B=Math.min(t[0],A.childNodes.length)}if(C){g.setStart(A,B)}else{g.setEnd(A,B)}}return true}function m(D){var y=n.get(q.id+"_"+D),C,t,A,B,z=q.keep;if(y){C=y.parentNode;if(D=="start"){if(!z){t=n.nodeIndex(y)}else{C=y.firstChild;t=1}k=x=C;r=s=t}else{if(!z){t=n.nodeIndex(y)}else{C=y.firstChild;t=1}x=C;s=t}if(!z){B=y.previousSibling;A=y.nextSibling;e(d.grep(y.childNodes),function(E){if(E.nodeType==3){E.nodeValue=E.nodeValue.replace(/\uFEFF/g,"")}});while(y=n.get(q.id+"_"+D)){n.remove(y,1)}if(B&&A&&B.nodeType==A.nodeType&&B.nodeType==3&&!d.isOpera){t=B.nodeValue.length;B.appendData(A.nodeValue);n.remove(A);if(D=="start"){k=x=B;r=s=t}else{x=B;s=t}}}}}function o(t){if(n.isBlock(t)&&!t.innerHTML&&!b){t.innerHTML='<br data-mce-bogus="1" />'}return t}if(q){if(q.start){g=n.createRng();u=n.getRoot();if(v.tridentSel){return v.tridentSel.moveToBookmark(q)}if(h(true)&&h()){v.setRng(g)}}else{if(q.id){m("start");m("end");if(k){g=n.createRng();g.setStart(o(k),r);g.setEnd(o(x),s);v.setRng(g)}}else{if(q.name){v.select(n.select(q.name)[q.index])}else{if(q.rng){g=q.rng;if(g.startContainer){i=v.dom.createRng();try{i.setStart(g.startContainer,g.startOffset);i.setEnd(g.endContainer,g.endOffset)}catch(p){}g=i}v.setRng(g)}}}}}},select:function(l,k){var j=this,m=j.dom,h=m.createRng(),g;function i(n,p){var o=new a(n,n);do{if(n.nodeType==3&&d.trim(n.nodeValue).length!==0){if(p){h.setStart(n,0)}else{h.setEnd(n,n.nodeValue.length)}return}if(n.nodeName=="BR"){if(p){h.setStartBefore(n)}else{h.setEndBefore(n)}return}}while(n=(p?o.next():o.prev()))}if(l){g=m.nodeIndex(l);h.setStart(l.parentNode,g);h.setEnd(l.parentNode,g+1);if(k){i(l,1);i(l)}j.setRng(h)}return l},isCollapsed:function(){var g=this,i=g.getRng(),h=g.getSel();if(!i||i.item){return false}if(i.compareEndPoints){return i.compareEndPoints("StartToEnd",i)===0}return !h||i.collapsed},collapse:function(g){var i=this,h=i.getRng(),j;if(h.item){j=h.item(0);h=i.win.document.body.createTextRange();h.moveToElementText(j)}h.collapse(!!g);i.setRng(h)},getSel:function(){var h=this,g=this.win;return g.getSelection?g.getSelection():g.document.selection},getRng:function(m){var h=this,j,g,l,k=h.win.document;if(m&&h.tridentSel){return h.tridentSel.getRangeAt(0)}try{if(j=h.getSel()){g=j.rangeCount>0?j.getRangeAt(0):(j.createRange?j.createRange():k.createRange())}}catch(i){}if(d.isIE&&!d.isIE11&&g&&g.setStart&&k.selection.createRange().item){l=k.selection.createRange().item(0);g=k.createRange();g.setStartBefore(l);g.setEndAfter(l)}if(!g){g=k.createRange?k.createRange():k.body.createTextRange()}if(g.setStart&&g.startContainer.nodeType===9&&g.collapsed){l=h.dom.getRoot();g.setStart(l,0);g.setEnd(l,0)}if(h.selectedRange&&h.explicitRange){if(g.compareBoundaryPoints(g.START_TO_START,h.selectedRange)===0&&g.compareBoundaryPoints(g.END_TO_END,h.selectedRange)===0){g=h.explicitRange}else{h.selectedRange=null;h.explicitRange=null}}return g},setRng:function(k,g){var j,i=this;if(!i.tridentSel){j=i.getSel();if(j){i.explicitRange=k;try{j.removeAllRanges()}catch(h){}j.addRange(k);if(g===false&&j.extend){j.collapse(k.endContainer,k.endOffset);j.extend(k.startContainer,k.startOffset)}i.selectedRange=j.rangeCount>0?j.getRangeAt(0):null}}else{if(k.cloneRange){try{i.tridentSel.addRange(k);return}catch(h){}}try{k.select()}catch(h){}}},setNode:function(h){var g=this;g.setContent(g.dom.getOuterHTML(h));return h},getNode:function(){var i=this,h=i.getRng(),j=i.getSel(),m,l=h.startContainer,g=h.endContainer;function k(q,o){var p=q;while(q&&q.nodeType===3&&q.length===0){q=o?q.nextSibling:q.previousSibling}return q||p}if(!h){return i.dom.getRoot()}if(h.setStart){m=h.commonAncestorContainer;if(!h.collapsed){if(h.startContainer==h.endContainer){if(h.endOffset-h.startOffset<2){if(h.startContainer.hasChildNodes()){m=h.startContainer.childNodes[h.startOffset]}}}if(l.nodeType===3&&g.nodeType===3){if(l.length===h.startOffset){l=k(l.nextSibling,true)}else{l=l.parentNode}if(h.endOffset===0){g=k(g.previousSibling,false)}else{g=g.parentNode}if(l&&l===g){return l}}}if(m&&m.nodeType==3){return m.parentNode}return m}return h.item?h.item(0):h.parentElement()},getSelectedBlocks:function(p,h){var o=this,k=o.dom,m,l,i,j=[];m=k.getParent(p||o.getStart(),k.isBlock);l=k.getParent(h||o.getEnd(),k.isBlock);if(m){j.push(m)}if(m&&l&&m!=l){i=m;var g=new a(m,k.getRoot());while((i=g.next())&&i!=l){if(k.isBlock(i)){j.push(i)}}}if(l&&m!=l){j.push(l)}return j},isForward:function(){var i=this.dom,g=this.getSel(),j,h;if(!g||g.anchorNode==null||g.focusNode==null){return true}j=i.createRng();j.setStart(g.anchorNode,g.anchorOffset);j.collapse(true);h=i.createRng();h.setStart(g.focusNode,g.focusOffset);h.collapse(true);return j.compareBoundaryPoints(j.START_TO_START,h)<=0},normalize:function(){var h=this,g,m,l,j,i;function k(p){var o,r,n,s=h.dom,u=s.getRoot(),q,t,v;function y(z,A){var B=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(z=B[A?"prev":"next"]()){if(z.nodeName==="BR"){return true}}}function x(B,z){var C,A;z=z||o;C=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(q=C[B?"prev":"next"]()){if(q.nodeType===3&&q.nodeValue.length>0){o=q;r=B?q.nodeValue.length:0;m=true;return}if(s.isBlock(q)||t[q.nodeName.toLowerCase()]){return}A=q}if(l&&A){o=A;m=true;r=0}}o=g[(p?"start":"end")+"Container"];r=g[(p?"start":"end")+"Offset"];t=s.schema.getNonEmptyElements();if(o.nodeType===9){o=s.getRoot();r=0}if(o===u){if(p){q=o.childNodes[r>0?r-1:0];if(q){v=q.nodeName.toLowerCase();if(t[q.nodeName]||q.nodeName=="TABLE"){return}}}if(o.hasChildNodes()){o=o.childNodes[Math.min(!p&&r>0?r-1:r,o.childNodes.length-1)];r=0;if(o.hasChildNodes()&&!/TABLE/.test(o.nodeName)){q=o;n=new a(o,u);do{if(q.nodeType===3&&q.nodeValue.length>0){r=p?0:q.nodeValue.length;o=q;m=true;break}if(t[q.nodeName.toLowerCase()]){r=s.nodeIndex(q);o=q.parentNode;if(q.nodeName=="IMG"&&!p){r++}m=true;break}}while(q=(p?n.next():n.prev()))}}}if(l){if(o.nodeType===3&&r===0){x(true)}if(o.nodeType===1){q=o.childNodes[r];if(q&&q.nodeName==="BR"&&!y(q)&&!y(q,true)){x(true,o.childNodes[r])}}}if(p&&!l&&o.nodeType===3&&r===o.nodeValue.length){x(false)}if(m){g["set"+(p?"Start":"End")](o,r)}}if(d.isIE){return}g=h.getRng();l=g.collapsed;k(true);if(!l){k()}if(m){if(l){g.collapse(true)}h.setRng(g,h.isForward())}},selectorChanged:function(g,j){var h=this,i;if(!h.selectorChangedData){h.selectorChangedData={};i={};h.editor.onNodeChange.addToTop(function(l,k,o){var p=h.dom,m=p.getParents(o,null,p.getRoot()),n={};e(h.selectorChangedData,function(r,q){e(m,function(s){if(p.is(s,q)){if(!i[q]){e(r,function(t){t(true,{node:s,selector:q,parents:m})});i[q]=r}n[q]=r;return false}})});e(i,function(r,q){if(!n[q]){delete i[q];e(r,function(s){s(false,{node:o,selector:q,parents:m})})}})})}if(!h.selectorChangedData[g]){h.selectorChangedData[g]=[]}h.selectorChangedData[g].push(j);return h},scrollIntoView:function(k){var j,h,g=this,i=g.dom;h=i.getViewPort(g.editor.getWin());j=i.getPos(k).y;if(j<h.y||j+25>h.y+h.h){g.editor.getWin().scrollTo(0,j<h.y?j:j-h.h+25)}},destroy:function(h){var g=this;g.win=null;if(!h){d.removeUnload(g.destroy)}},_fixIESelection:function(){var h=this.dom,n=h.doc,i=n.body,k,o,g;function j(p,s){var q=i.createTextRange();try{q.moveToPoint(p,s)}catch(r){q=null}return q}function m(q){var p;if(q.button){p=j(q.x,q.y);if(p){if(p.compareEndPoints("StartToStart",o)>0){p.setEndPoint("StartToStart",o)}else{p.setEndPoint("EndToEnd",o)}p.select()}}else{l()}}function l(){var p=n.selection.createRange();if(o&&!p.item&&p.compareEndPoints("StartToEnd",p)===0){o.select()}h.unbind(n,"mouseup",l);h.unbind(n,"mousemove",m);o=k=0}n.documentElement.unselectable=true;h.bind(n,["mousedown","contextmenu"],function(p){if(p.target.nodeName==="HTML"){if(k){l()}g=n.documentElement;if(g.scrollHeight>g.clientHeight){return}k=1;o=j(p.x,p.y);if(o){h.bind(n,"mouseup",l);h.bind(n,"mousemove",m);h.win.focus();o.select()}}})}})})(tinymce);(function(a){a.dom.Serializer=function(e,i,f){var h,b,d=a.isIE,g=a.each,c;if(!e.apply_source_formatting){e.indent=false}i=i||a.DOM;f=f||new a.html.Schema(e);e.entity_encoding=e.entity_encoding||"named";e.remove_trailing_brs="remove_trailing_brs" in e?e.remove_trailing_brs:true;h=new a.util.Dispatcher(self);b=new a.util.Dispatcher(self);c=new a.html.DomParser(e,f);c.addAttributeFilter("src,href,style",function(k,j){var o=k.length,l,q,n="data-mce-"+j,p=e.url_converter,r=e.url_converter_scope,m;while(o--){l=k[o];q=l.attributes.map[n];if(q!==m){l.attr(j,q.length>0?q:null);l.attr(n,null)}else{q=l.attributes.map[j];if(j==="style"){q=i.serializeStyle(i.parseStyle(q),l.name)}else{if(p){q=p.call(r,q,j,l.name)}}l.attr(j,q.length>0?q:null)}}});c.addAttributeFilter("class",function(j,k){var l=j.length,m,n;while(l--){m=j[l];n=m.attr("class").replace(/(?:^|\s)mce(Item\w+|Selected)(?!\S)/g,"");m.attr("class",n.length>0?n:null)}});c.addAttributeFilter("data-mce-type",function(j,l,k){var m=j.length,n;while(m--){n=j[m];if(n.attributes.map["data-mce-type"]==="bookmark"&&!k.cleanup){n.remove()}}});c.addAttributeFilter("data-mce-expando",function(j,l,k){var m=j.length;while(m--){j[m].attr(l,null)}});c.addNodeFilter("noscript",function(j){var k=j.length,l;while(k--){l=j[k].firstChild;if(l){l.value=a.html.Entities.decode(l.value)}}});c.addNodeFilter("script,style",function(k,l){var m=k.length,n,o;function j(p){return p.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}while(m--){n=k[m];o=n.firstChild?n.firstChild.value:"";if(l==="script"){n.attr("type",(n.attr("type")||"text/javascript").replace(/^mce\-/,""));if(o.length>0){n.firstChild.value="// <![CDATA[\n"+j(o)+"\n// ]]>"}}else{if(o.length>0){n.firstChild.value="<!--\n"+j(o)+"\n-->"}}}});c.addNodeFilter("#comment",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.value.indexOf("[CDATA[")===0){m.name="#cdata";m.type=4;m.value=m.value.replace(/^\[CDATA\[|\]\]$/g,"")}else{if(m.value.indexOf("mce:protected ")===0){m.name="#text";m.type=3;m.raw=true;m.value=unescape(m.value).substr(14)}}}});c.addNodeFilter("xml:namespace,input",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.type===7){m.remove()}else{if(m.type===1){if(k==="input"&&!("type" in m.attributes.map)){m.attr("type","text")}}}}});if(e.fix_list_elements){c.addNodeFilter("ul,ol",function(k,l){var m=k.length,n,j;while(m--){n=k[m];j=n.parent;if(j.name==="ul"||j.name==="ol"){if(n.prev&&n.prev.name==="li"){n.prev.append(n)}}}})}c.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style",function(j,k){var l=j.length;while(l--){j[l].attr(k,null)}});return{schema:f,addNodeFilter:c.addNodeFilter,addAttributeFilter:c.addAttributeFilter,onPreProcess:h,onPostProcess:b,serialize:function(o,m){var l,p,k,j,n;if(d&&i.select("script,style,select,map").length>0){n=o.innerHTML;o=o.cloneNode(false);i.setHTML(o,n)}else{o=o.cloneNode(true)}l=o.ownerDocument.implementation;if(l.createHTMLDocument){p=l.createHTMLDocument("");g(o.nodeName=="BODY"?o.childNodes:[o],function(q){p.body.appendChild(p.importNode(q,true))});if(o.nodeName!="BODY"){o=p.body.firstChild}else{o=p.body}k=i.doc;i.doc=p}m=m||{};m.format=m.format||"html";if(!m.no_events){m.node=o;h.dispatch(self,m)}j=new a.html.Serializer(e,f);m.content=j.serialize(c.parse(a.trim(m.getInner?o.innerHTML:i.getOuterHTML(o)),m));if(!m.cleanup){m.content=m.content.replace(/\uFEFF/g,"")}if(!m.no_events){b.dispatch(self,m)}if(k){i.doc=k}m.node=null;return m.content},addRules:function(j){f.addValidElements(j)},setRules:function(j){f.setValidElements(j)}}}})(tinymce);(function(a){a.dom.ScriptLoader=function(h){var c=0,k=1,i=2,l={},j=[],e={},d=[],g=0,f;function b(m,v){var x=this,q=a.DOM,s,o,r,n;function p(){q.remove(n);if(s){s.onreadystatechange=s.onload=s=null}v()}function u(){if(typeof(console)!=="undefined"&&console.log){console.log("Failed to load: "+m)}}n=q.uniqueId();if(a.isIE6){o=new a.util.URI(m);r=location;if(o.host==r.hostname&&o.port==r.port&&(o.protocol+":")==r.protocol&&o.protocol.toLowerCase()!="file"){a.util.XHR.send({url:a._addVer(o.getURI()),success:function(y){var t=q.create("script",{type:"text/javascript"});t.text=y;document.getElementsByTagName("head")[0].appendChild(t);q.remove(t);p()},error:u});return}}s=document.createElement("script");s.id=n;s.type="text/javascript";s.src=a._addVer(m);if(!a.isIE||a.isIE11){s.onload=p}s.onerror=u;if(!a.isOpera){s.onreadystatechange=function(){var t=s.readyState;if(t=="complete"||t=="loaded"){p()}}}(document.getElementsByTagName("head")[0]||document.body).appendChild(s)}this.isDone=function(m){return l[m]==i};this.markDone=function(m){l[m]=i};this.add=this.load=function(m,q,n){var o,p=l[m];if(p==f){j.push(m);l[m]=c}if(q){if(!e[m]){e[m]=[]}e[m].push({func:q,scope:n||this})}};this.loadQueue=function(n,m){this.loadScripts(j,n,m)};this.loadScripts=function(m,q,p){var o;function n(r){a.each(e[r],function(s){s.func.call(s.scope)});e[r]=f}d.push({func:q,scope:p||this});o=function(){var r=a.grep(m);m.length=0;a.each(r,function(s){if(l[s]==i){n(s);return}if(l[s]!=k){l[s]=k;g++;b(s,function(){l[s]=i;g--;n(s);o()})}});if(!g){a.each(d,function(s){s.func.call(s.scope)});d.length=0}};o()}};a.ScriptLoader=new a.dom.ScriptLoader()})(tinymce);(function(a){a.dom.RangeUtils=function(c){var b="\uFEFF";this.walk=function(d,s){var i=d.startContainer,l=d.startOffset,t=d.endContainer,m=d.endOffset,j,g,o,h,r,q,e;e=c.select("td.mceSelected,th.mceSelected");if(e.length>0){a.each(e,function(u){s([u])});return}function f(u){var v;v=u[0];if(v.nodeType===3&&v===i&&l>=v.nodeValue.length){u.splice(0,1)}v=u[u.length-1];if(m===0&&u.length>0&&v===t&&v.nodeType===3){u.splice(u.length-1,1)}return u}function p(x,v,u){var y=[];for(;x&&x!=u;x=x[v]){y.push(x)}return y}function n(v,u){do{if(v.parentNode==u){return v}v=v.parentNode}while(v)}function k(x,v,y){var u=y?"nextSibling":"previousSibling";for(h=x,r=h.parentNode;h&&h!=v;h=r){r=h.parentNode;q=p(h==x?h:h[u],u);if(q.length){if(!y){q.reverse()}s(f(q))}}}if(i.nodeType==1&&i.hasChildNodes()){i=i.childNodes[l]}if(t.nodeType==1&&t.hasChildNodes()){t=t.childNodes[Math.min(m-1,t.childNodes.length-1)]}if(i==t){return s(f([i]))}j=c.findCommonAncestor(i,t);for(h=i;h;h=h.parentNode){if(h===t){return k(i,j,true)}if(h===j){break}}for(h=t;h;h=h.parentNode){if(h===i){return k(t,j)}if(h===j){break}}g=n(i,j)||i;o=n(t,j)||t;k(i,g,true);q=p(g==i?g:g.nextSibling,"nextSibling",o==t?o.nextSibling:o);if(q.length){s(f(q))}k(t,o)};this.split=function(e){var h=e.startContainer,d=e.startOffset,i=e.endContainer,g=e.endOffset;function f(j,k){return j.splitText(k)}if(h==i&&h.nodeType==3){if(d>0&&d<h.nodeValue.length){i=f(h,d);h=i.previousSibling;if(g>d){g=g-d;h=i=f(i,g).previousSibling;g=i.nodeValue.length;d=0}else{g=0}}}else{if(h.nodeType==3&&d>0&&d<h.nodeValue.length){h=f(h,d);d=0}if(i.nodeType==3&&g>0&&g<i.nodeValue.length){i=f(i,g).previousSibling;g=i.nodeValue.length}}return{startContainer:h,startOffset:d,endContainer:i,endOffset:g}}};a.dom.RangeUtils.compareRanges=function(c,b){if(c&&b){if(c.item||c.duplicate){if(c.item&&b.item&&c.item(0)===b.item(0)){return true}if(c.isEqual&&b.isEqual&&b.isEqual(c)){return true}}else{return c.startContainer==b.startContainer&&c.startOffset==b.startOffset}}return false}})(tinymce);(function(b){var a=b.dom.Event,c=b.each;b.create("tinymce.ui.KeyboardNavigation",{KeyboardNavigation:function(e,f){var q=this,n=e.root,m=e.items,o=e.enableUpDown,i=e.enableLeftRight||!e.enableUpDown,l=e.excludeFromTabOrder,k,h,p,d,g;f=f||b.DOM;k=function(r){g=r.target.id};h=function(r){f.setAttrib(r.target.id,"tabindex","-1")};d=function(r){var s=f.get(g);f.setAttrib(s,"tabindex","0");s.focus()};q.focus=function(){f.get(g).focus()};q.destroy=function(){c(m,function(s){var t=f.get(s.id);f.unbind(t,"focus",k);f.unbind(t,"blur",h)});var r=f.get(n);f.unbind(r,"focus",d);f.unbind(r,"keydown",p);m=f=n=q.focus=k=h=p=d=null;q.destroy=function(){}};q.moveFocus=function(v,s){var r=-1,u=q.controls,t;if(!g){return}c(m,function(y,x){if(y.id===g){r=x;return false}});r+=v;if(r<0){r=m.length-1}else{if(r>=m.length){r=0}}t=m[r];f.setAttrib(g,"tabindex","-1");f.setAttrib(t.id,"tabindex","0");f.get(t.id).focus();if(e.actOnFocus){e.onAction(t.id)}if(s){a.cancel(s)}};p=function(z){var v=37,u=39,y=38,A=40,r=27,t=14,s=13,x=32;switch(z.keyCode){case v:if(i){q.moveFocus(-1)}a.cancel(z);break;case u:if(i){q.moveFocus(1)}a.cancel(z);break;case y:if(o){q.moveFocus(-1)}a.cancel(z);break;case A:if(o){q.moveFocus(1)}a.cancel(z);break;case r:if(e.onCancel){e.onCancel();a.cancel(z)}break;case t:case s:case x:if(e.onAction){e.onAction(g);a.cancel(z)}break}};c(m,function(t,r){var s,u;if(!t.id){t.id=f.uniqueId("_mce_item_")}u=f.get(t.id);if(l){f.bind(u,"blur",h);s="-1"}else{s=(r===0?"0":"-1")}u.setAttribute("tabindex",s);f.bind(u,"focus",k)});if(m[0]){g=m[0].id}f.setAttrib(n,"tabindex","-1");var j=f.get(n);f.bind(j,"focus",d);f.bind(j,"keydown",p)}})})(tinymce);(function(c){var b=c.DOM,a=c.is;c.create("tinymce.ui.Control",{Control:function(f,e,d){this.id=f;this.settings=e=e||{};this.rendered=false;this.onRender=new c.util.Dispatcher(this);this.classPrefix="";this.scope=e.scope||this;this.disabled=0;this.active=0;this.editor=d},setAriaProperty:function(f,e){var d=b.get(this.id+"_aria")||b.get(this.id);if(d){b.setAttrib(d,"aria-"+f,!!e)}},focus:function(){b.get(this.id).focus()},setDisabled:function(d){if(d!=this.disabled){this.setAriaProperty("disabled",d);this.setState("Disabled",d);this.setState("Enabled",!d);this.disabled=d}},isDisabled:function(){return this.disabled},setActive:function(d){if(d!=this.active){this.setState("Active",d);this.active=d;this.setAriaProperty("pressed",d)}},isActive:function(){return this.active},setState:function(f,d){var e=b.get(this.id);f=this.classPrefix+f;if(d){b.addClass(e,f)}else{b.removeClass(e,f)}},isRendered:function(){return this.rendered},renderHTML:function(){},renderTo:function(d){b.setHTML(d,this.renderHTML())},postRender:function(){var e=this,d;if(a(e.disabled)){d=e.disabled;e.disabled=-1;e.setDisabled(d)}if(a(e.active)){d=e.active;e.active=-1;e.setActive(d)}},remove:function(){b.remove(this.id);this.destroy()},destroy:function(){c.dom.Event.clear(this.id)}})})(tinymce);tinymce.create("tinymce.ui.Container:tinymce.ui.Control",{Container:function(c,b,a){this.parent(c,b,a);this.controls=[];this.lookup={}},add:function(a){this.lookup[a.id]=a;this.controls.push(a);return a},get:function(a){return this.lookup[a]}});tinymce.create("tinymce.ui.Separator:tinymce.ui.Control",{Separator:function(b,a){this.parent(b,a);this.classPrefix="mceSeparator";this.setDisabled(true)},renderHTML:function(){return tinymce.DOM.createHTML("span",{"class":this.classPrefix,role:"separator","aria-orientation":"vertical",tabindex:"-1"})}});(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.MenuItem:tinymce.ui.Control",{MenuItem:function(g,f){this.parent(g,f);this.classPrefix="mceMenuItem"},setSelected:function(f){this.setState("Selected",f);this.setAriaProperty("checked",!!f);this.selected=f},isSelected:function(){return this.selected},postRender:function(){var f=this;f.parent();if(c(f.selected)){f.setSelected(f.selected)}}})})(tinymce);(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.Menu:tinymce.ui.MenuItem",{Menu:function(h,g){var f=this;f.parent(h,g);f.items={};f.collapsed=false;f.menuCount=0;f.onAddItem=new d.util.Dispatcher(this)},expand:function(g){var f=this;if(g){a(f,function(h){if(h.expand){h.expand()}},"items",f)}f.collapsed=false},collapse:function(g){var f=this;if(g){a(f,function(h){if(h.collapse){h.collapse()}},"items",f)}f.collapsed=true},isCollapsed:function(){return this.collapsed},add:function(f){if(!f.settings){f=new d.ui.MenuItem(f.id||b.uniqueId(),f)}this.onAddItem.dispatch(this,f);return this.items[f.id]=f},addSeparator:function(){return this.add({separator:true})},addMenu:function(f){if(!f.collapse){f=this.createMenu(f)}this.menuCount++;return this.add(f)},hasMenus:function(){return this.menuCount!==0},remove:function(f){delete this.items[f.id]},removeAll:function(){var f=this;a(f,function(g){if(g.removeAll){g.removeAll()}else{g.remove()}g.destroy()},"items",f);f.items={}},createMenu:function(g){var f=new d.ui.Menu(g.id||b.uniqueId(),g);f.onAddItem.add(this.onAddItem.dispatch,this.onAddItem);return f}})})(tinymce);(function(e){var d=e.is,c=e.DOM,f=e.each,a=e.dom.Event,b=e.dom.Element;e.create("tinymce.ui.DropMenu:tinymce.ui.Menu",{DropMenu:function(h,g){g=g||{};g.container=g.container||c.doc.body;g.offset_x=g.offset_x||0;g.offset_y=g.offset_y||0;g.vp_offset_x=g.vp_offset_x||0;g.vp_offset_y=g.vp_offset_y||0;if(d(g.icons)&&!g.icons){g["class"]+=" mceNoIcons"}this.parent(h,g);this.onShowMenu=new e.util.Dispatcher(this);this.onHideMenu=new e.util.Dispatcher(this);this.classPrefix="mceMenu"},createMenu:function(j){var h=this,i=h.settings,g;j.container=j.container||i.container;j.parent=h;j.constrain=j.constrain||i.constrain;j["class"]=j["class"]||i["class"];j.vp_offset_x=j.vp_offset_x||i.vp_offset_x;j.vp_offset_y=j.vp_offset_y||i.vp_offset_y;j.keyboard_focus=i.keyboard_focus;g=new e.ui.DropMenu(j.id||c.uniqueId(),j);g.onAddItem.add(h.onAddItem.dispatch,h.onAddItem);return g},focus:function(){var g=this;if(g.keyboardNav){g.keyboardNav.focus()}},update:function(){var i=this,j=i.settings,g=c.get("menu_"+i.id+"_tbl"),l=c.get("menu_"+i.id+"_co"),h,k;h=j.max_width?Math.min(g.offsetWidth,j.max_width):g.offsetWidth;k=j.max_height?Math.min(g.offsetHeight,j.max_height):g.offsetHeight;if(!c.boxModel){i.element.setStyles({width:h+2,height:k+2})}else{i.element.setStyles({width:h,height:k})}if(j.max_width){c.setStyle(l,"width",h)}if(j.max_height){c.setStyle(l,"height",k);if(g.clientHeight<j.max_height){c.setStyle(l,"overflow","hidden")}}},showMenu:function(p,n,r){var z=this,A=z.settings,o,g=c.getViewPort(),u,l,v,q,i=2,k,j,m=z.classPrefix;z.collapse(1);if(z.isMenuVisible){return}if(!z.rendered){o=c.add(z.settings.container,z.renderNode());f(z.items,function(h){h.postRender()});z.element=new b("menu_"+z.id,{blocker:1,container:A.container})}else{o=c.get("menu_"+z.id)}if(!e.isOpera){c.setStyles(o,{left:-65535,top:-65535})}c.show(o);z.update();p+=A.offset_x||0;n+=A.offset_y||0;g.w-=4;g.h-=4;if(A.constrain){u=o.clientWidth-i;l=o.clientHeight-i;v=g.x+g.w;q=g.y+g.h;if((p+A.vp_offset_x+u)>v){p=r?r-u:Math.max(0,(v-A.vp_offset_x)-u)}if((n+A.vp_offset_y+l)>q){n=Math.max(0,(q-A.vp_offset_y)-l)}}c.setStyles(o,{left:p,top:n});z.element.update();z.isMenuVisible=1;z.mouseClickFunc=a.add(o,"click",function(s){var h;s=s.target;if(s&&(s=c.getParent(s,"tr"))&&!c.hasClass(s,m+"ItemSub")){h=z.items[s.id];if(h.isDisabled()){return}k=z;while(k){if(k.hideMenu){k.hideMenu()}k=k.settings.parent}if(h.settings.onclick){h.settings.onclick(s)}return false}});if(z.hasMenus()){z.mouseOverFunc=a.add(o,"mouseover",function(x){var h,t,s;x=x.target;if(x&&(x=c.getParent(x,"tr"))){h=z.items[x.id];if(z.lastMenu){z.lastMenu.collapse(1)}if(h.isDisabled()){return}if(x&&c.hasClass(x,m+"ItemSub")){t=c.getRect(x);h.showMenu((t.x+t.w-i),t.y-i,t.x);z.lastMenu=h;c.addClass(c.get(h.id).firstChild,m+"ItemActive")}}})}a.add(o,"keydown",z._keyHandler,z);z.onShowMenu.dispatch(z);if(A.keyboard_focus){z._setupKeyboardNav()}},hideMenu:function(j){var g=this,i=c.get("menu_"+g.id),h;if(!g.isMenuVisible){return}if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(i,"mouseover",g.mouseOverFunc);a.remove(i,"click",g.mouseClickFunc);a.remove(i,"keydown",g._keyHandler);c.hide(i);g.isMenuVisible=0;if(!j){g.collapse(1)}if(g.element){g.element.hide()}if(h=c.get(g.id)){c.removeClass(h.firstChild,g.classPrefix+"ItemActive")}g.onHideMenu.dispatch(g)},add:function(i){var g=this,h;i=g.parent(i);if(g.isRendered&&(h=c.get("menu_"+g.id))){g._add(c.select("tbody",h)[0],i)}return i},collapse:function(g){this.parent(g);this.hideMenu(1)},remove:function(g){c.remove(g.id);this.destroy();return this.parent(g)},destroy:function(){var g=this,h=c.get("menu_"+g.id);if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(h,"mouseover",g.mouseOverFunc);a.remove(c.select("a",h),"focus",g.mouseOverFunc);a.remove(h,"click",g.mouseClickFunc);a.remove(h,"keydown",g._keyHandler);if(g.element){g.element.remove()}c.remove(h)},renderNode:function(){var i=this,j=i.settings,l,h,k,g;g=c.create("div",{role:"listbox",id:"menu_"+i.id,"class":j["class"],style:"position:absolute;left:0;top:0;z-index:200000;outline:0"});if(i.settings.parent){c.setAttrib(g,"aria-parent","menu_"+i.settings.parent.id)}k=c.add(g,"div",{role:"presentation",id:"menu_"+i.id+"_co","class":i.classPrefix+(j["class"]?" "+j["class"]:"")});i.element=new b("menu_"+i.id,{blocker:1,container:j.container});if(j.menu_line){c.add(k,"span",{"class":i.classPrefix+"Line"})}l=c.add(k,"table",{role:"presentation",id:"menu_"+i.id+"_tbl",border:0,cellPadding:0,cellSpacing:0});h=c.add(l,"tbody");f(i.items,function(m){i._add(h,m)});i.rendered=true;return g},_setupKeyboardNav:function(){var i,h,g=this;i=c.get("menu_"+g.id);h=c.select("a[role=option]","menu_"+g.id);h.splice(0,0,i);g.keyboardNav=new e.ui.KeyboardNavigation({root:"menu_"+g.id,items:h,onCancel:function(){g.hideMenu()},enableUpDown:true});i.focus()},_keyHandler:function(g){var h=this,i;switch(g.keyCode){case 37:if(h.settings.parent){h.hideMenu();h.settings.parent.focus();a.cancel(g)}break;case 39:if(h.mouseOverFunc){h.mouseOverFunc(g)}break}},_add:function(j,h){var i,q=h.settings,p,l,k,m=this.classPrefix,g;if(q.separator){l=c.add(j,"tr",{id:h.id,"class":m+"ItemSeparator"});c.add(l,"td",{"class":m+"ItemSeparator"});if(i=l.previousSibling){c.addClass(i,"mceLast")}return}i=l=c.add(j,"tr",{id:h.id,"class":m+"Item "+m+"ItemEnabled"});i=k=c.add(i,q.titleItem?"th":"td");i=p=c.add(i,"a",{id:h.id+"_aria",role:q.titleItem?"presentation":"option",href:"javascript:;",onclick:"return false;",onmousedown:"return false;"});if(q.parent){c.setAttrib(p,"aria-haspopup","true");c.setAttrib(p,"aria-owns","menu_"+h.id)}c.addClass(k,q["class"]);g=c.add(i,"span",{"class":"mceIcon"+(q.icon?" mce_"+q.icon:"")});if(q.icon_src){c.add(g,"img",{src:q.icon_src})}i=c.add(i,q.element||"span",{"class":"mceText",title:h.settings.title},h.settings.title);if(h.settings.style){if(typeof h.settings.style=="function"){h.settings.style=h.settings.style()}c.setAttrib(i,"style",h.settings.style)}if(j.childNodes.length==1){c.addClass(l,"mceFirst")}if((i=l.previousSibling)&&c.hasClass(i,m+"ItemSeparator")){c.addClass(l,"mceFirst")}if(h.collapse){c.addClass(l,m+"ItemSub")}if(i=l.previousSibling){c.removeClass(i,"mceLast")}c.addClass(l,"mceLast")}})})(tinymce);(function(b){var a=b.DOM;b.create("tinymce.ui.Button:tinymce.ui.Control",{Button:function(e,d,c){this.parent(e,d,c);this.classPrefix="mceButton"},renderHTML:function(){var f=this.classPrefix,e=this.settings,d,c;c=a.encode(e.label||"");d='<a role="button" id="'+this.id+'" href="javascript:;" class="'+f+" "+f+"Enabled "+e["class"]+(c?" "+f+"Labeled":"")+'" onmousedown="return false;" onclick="return false;" aria-labelledby="'+this.id+'_voice" title="'+a.encode(e.title)+'">';if(e.image&&!(this.editor&&this.editor.forcedHighContrastMode)){d+='<span class="mceIcon '+e["class"]+'"><img class="mceIcon" src="'+e.image+'" alt="'+a.encode(e.title)+'" /></span>'+(c?'<span class="'+f+'Label">'+c+"</span>":"")}else{d+='<span class="mceIcon '+e["class"]+'"></span>'+(c?'<span class="'+f+'Label">'+c+"</span>":"")}d+='<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="'+this.id+'_voice">'+e.title+"</span>";d+="</a>";return d},postRender:function(){var d=this,e=d.settings,c;if(b.isIE&&d.editor){b.dom.Event.add(d.id,"mousedown",function(f){var g=d.editor.selection.getNode().nodeName;c=g==="IMG"?d.editor.selection.getBookmark():null})}b.dom.Event.add(d.id,"click",function(f){if(!d.isDisabled()){if(b.isIE&&d.editor&&c!==null){d.editor.selection.moveToBookmark(c)}return e.onclick.call(e.scope,f)}});b.dom.Event.add(d.id,"keydown",function(f){if(!d.isDisabled()&&f.keyCode==b.VK.SPACEBAR){b.dom.Event.cancel(f);return e.onclick.call(e.scope,f)}})}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.ListBox:tinymce.ui.Control",{ListBox:function(j,i,g){var h=this;h.parent(j,i,g);h.items=[];h.onChange=new a(h);h.onPostRender=new a(h);h.onAdd=new a(h);h.onRenderMenu=new e.util.Dispatcher(this);h.classPrefix="mceListBox";h.marked={}},select:function(h){var g=this,j,i;g.marked={};if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){var i=this,j,k,h;i.marked={};if(g!=i.selectedIndex){j=d.get(i.id+"_text");h=d.get(i.id+"_voiceDesc");k=i.items[g];if(k){i.selectedValue=k.value;i.selectedIndex=g;d.setHTML(j,d.encode(k.title));d.setHTML(h,i.settings.title+" - "+k.title);d.removeClass(j,"mceTitle");d.setAttrib(i.id,"aria-valuenow",k.title)}else{d.setHTML(j,d.encode(i.settings.title));d.setHTML(h,d.encode(i.settings.title));d.addClass(j,"mceTitle");i.selectedValue=i.selectedIndex=null;d.setAttrib(i.id,"aria-valuenow",i.settings.title)}j=0}},mark:function(g){this.marked[g]=true},add:function(j,g,i){var h=this;i=i||{};i=e.extend(i,{title:j,value:g});h.items.push(i);h.onAdd.dispatch(h,i)},getLength:function(){return this.items.length},renderHTML:function(){var j="",g=this,i=g.settings,k=g.classPrefix;j='<span role="listbox" aria-haspopup="true" aria-labelledby="'+g.id+'_voiceDesc" aria-describedby="'+g.id+'_voiceDesc"><table role="presentation" tabindex="0" id="'+g.id+'" cellpadding="0" cellspacing="0" class="'+k+" "+k+"Enabled"+(i["class"]?(" "+i["class"]):"")+'"><tbody><tr>';j+="<td>"+d.createHTML("span",{id:g.id+"_voiceDesc","class":"voiceLabel",style:"display:none;"},g.settings.title);j+=d.createHTML("a",{id:g.id+"_text",tabindex:-1,href:"javascript:;","class":"mceText",onclick:"return false;",onmousedown:"return false;"},d.encode(g.settings.title))+"</td>";j+="<td>"+d.createHTML("a",{id:g.id+"_open",tabindex:-1,href:"javascript:;","class":"mceOpen",onclick:"return false;",onmousedown:"return false;"},'<span><span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span></span>')+"</td>";j+="</tr></tbody></table></span>";return j},showMenu:function(){var h=this,j,i=d.get(this.id),g;if(h.isDisabled()||h.items.length===0){return}if(h.menu&&h.menu.isMenuVisible){return h.hideMenu()}if(!h.isMenuRendered){h.renderMenu();h.isMenuRendered=true}j=d.getPos(i);g=h.menu;g.settings.offset_x=j.x;g.settings.offset_y=j.y;g.settings.keyboard_focus=!e.isOpera;f(h.items,function(k){if(g.items[k.id]){g.items[k.id].setSelected(0)}});f(h.items,function(k){if(g.items[k.id]&&h.marked[k.value]){g.items[k.id].setSelected(1)}if(k.value===h.selectedValue){g.items[k.id].setSelected(1)}});g.showMenu(0,i.clientHeight);b.add(d.doc,"mousedown",h.hideMenu,h);d.addClass(h.id,h.classPrefix+"Selected")},hideMenu:function(h){var g=this;if(g.menu&&g.menu.isMenuVisible){d.removeClass(g.id,g.classPrefix+"Selected");if(h&&h.type=="mousedown"&&(h.target.id==g.id+"_text"||h.target.id==g.id+"_open")){return}if(!h||!d.getParent(h.target,".mceMenu")){d.removeClass(g.id,g.classPrefix+"Selected");b.remove(d.doc,"mousedown",g.hideMenu,g);g.menu.hideMenu()}}},renderMenu:function(){var h=this,g;g=h.settings.control_manager.createDropMenu(h.id+"_menu",{menu_line:1,"class":h.classPrefix+"Menu mceNoIcons",max_width:250,max_height:150});g.onHideMenu.add(function(){h.hideMenu();h.focus()});g.add({title:h.settings.title,"class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}});f(h.items,function(i){if(i.value===c){g.add({title:i.title,role:"option","class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}})}else{i.id=d.uniqueId();i.role="option";i.onclick=function(){if(h.settings.onselect(i.value)!==false){h.select(i.value)}};g.add(i)}});h.onRenderMenu.dispatch(h,g);h.menu=g},postRender:function(){var g=this,h=g.classPrefix;b.add(g.id,"click",g.showMenu,g);b.add(g.id,"keydown",function(i){if(i.keyCode==32){g.showMenu(i);b.cancel(i)}});b.add(g.id,"focus",function(){if(!g._focused){g.keyDownHandler=b.add(g.id,"keydown",function(i){if(i.keyCode==40){g.showMenu();b.cancel(i)}});g.keyPressHandler=b.add(g.id,"keypress",function(j){var i;if(j.keyCode==13){i=g.selectedValue;g.selectedValue=null;b.cancel(j);g.settings.onselect(i)}})}g._focused=1});b.add(g.id,"blur",function(){b.remove(g.id,"keydown",g.keyDownHandler);b.remove(g.id,"keypress",g.keyPressHandler);g._focused=0});if(e.isIE6||!d.boxModel){b.add(g.id,"mouseover",function(){if(!d.hasClass(g.id,h+"Disabled")){d.addClass(g.id,h+"Hover")}});b.add(g.id,"mouseout",function(){if(!d.hasClass(g.id,h+"Disabled")){d.removeClass(g.id,h+"Hover")}})}g.onPostRender.dispatch(g,d.get(g.id))},destroy:function(){this.parent();b.clear(this.id+"_text");b.clear(this.id+"_open")}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.NativeListBox:tinymce.ui.ListBox",{NativeListBox:function(h,g){this.parent(h,g);this.classPrefix="mceNativeListBox"},setDisabled:function(g){d.get(this.id).disabled=g;this.setAriaProperty("disabled",g)},isDisabled:function(){return d.get(this.id).disabled},select:function(h){var g=this,j,i;if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){d.get(this.id).selectedIndex=g+1;this.selectedValue=this.items[g]?this.items[g].value:null},add:function(k,h,g){var j,i=this;g=g||{};g.value=h;if(i.isRendered()){d.add(d.get(this.id),"option",g,k)}j={title:k,value:h,attribs:g};i.items.push(j);i.onAdd.dispatch(i,j)},getLength:function(){return this.items.length},renderHTML:function(){var i,g=this;i=d.createHTML("option",{value:""},"-- "+g.settings.title+" --");f(g.items,function(h){i+=d.createHTML("option",{value:h.value},h.title)});i=d.createHTML("select",{id:g.id,"class":"mceNativeListBox","aria-labelledby":g.id+"_aria"},i);i+=d.createHTML("span",{id:g.id+"_aria",style:"display: none"},g.settings.title);return i},postRender:function(){var h=this,i,j=true;h.rendered=true;function g(l){var k=h.items[l.target.selectedIndex-1];if(k&&(k=k.value)){h.onChange.dispatch(h,k);if(h.settings.onselect){h.settings.onselect(k)}}}b.add(h.id,"change",g);b.add(h.id,"keydown",function(q){var n,p=37,m=39,l=38,r=40,k=13,o=32;b.remove(h.id,"change",i);j=false;n=b.add(h.id,"blur",function(){if(j){return}j=true;b.add(h.id,"change",g);b.remove(h.id,"blur",n)});if(q.keyCode==k||q.keyCode==o){g(q);return b.cancel(q)}else{if(q.keyCode==r||q.keyCode==l){q.stopImmediatePropagation()}}});h.onPostRender.dispatch(h,d.get(h.id))}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.MenuButton:tinymce.ui.Button",{MenuButton:function(g,f,e){this.parent(g,f,e);this.onRenderMenu=new c.util.Dispatcher(this);f.menu_container=f.menu_container||b.doc.body},showMenu:function(){var g=this,j,i,h=b.get(g.id),f;if(g.isDisabled()){return}if(!g.isMenuRendered){g.renderMenu();g.isMenuRendered=true}if(g.isMenuVisible){return g.hideMenu()}j=b.getPos(g.settings.menu_container);i=b.getPos(h);f=g.menu;f.settings.offset_x=i.x;f.settings.offset_y=i.y;f.settings.vp_offset_x=i.x;f.settings.vp_offset_y=i.y;f.settings.keyboard_focus=g._focused;f.showMenu(0,h.firstChild.clientHeight);a.add(b.doc,"mousedown",g.hideMenu,g);g.setState("Selected",1);g.isMenuVisible=1},renderMenu:function(){var f=this,e;e=f.settings.control_manager.createDropMenu(f.id+"_menu",{menu_line:1,"class":this.classPrefix+"Menu",icons:f.settings.icons});e.onHideMenu.add(function(){f.hideMenu();f.focus()});f.onRenderMenu.dispatch(f,e);f.menu=e},hideMenu:function(g){var f=this;if(g&&g.type=="mousedown"&&b.getParent(g.target,function(h){return h.id===f.id||h.id===f.id+"_open"})){return}if(!g||!b.getParent(g.target,".mceMenu")){f.setState("Selected",0);a.remove(b.doc,"mousedown",f.hideMenu,f);if(f.menu){f.menu.hideMenu()}}f.isMenuVisible=0},postRender:function(){var e=this,f=e.settings;a.add(e.id,"click",function(){if(!e.isDisabled()){if(f.onclick){f.onclick(e.value)}e.showMenu()}})}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.SplitButton:tinymce.ui.MenuButton",{SplitButton:function(g,f,e){this.parent(g,f,e);this.classPrefix="mceSplitButton"},renderHTML:function(){var i,f=this,g=f.settings,e;i="<tbody><tr>";if(g.image){e=b.createHTML("img ",{src:g.image,role:"presentation","class":"mceAction "+g["class"]})}else{e=b.createHTML("span",{"class":"mceAction "+g["class"]},"")}e+=b.createHTML("span",{"class":"mceVoiceLabel mceIconOnly",id:f.id+"_voice",style:"display:none;"},g.title);i+="<td >"+b.createHTML("a",{role:"button",id:f.id+"_action",tabindex:"-1",href:"javascript:;","class":"mceAction "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"</td>";e=b.createHTML("span",{"class":"mceOpen "+g["class"]},'<span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span>');i+="<td >"+b.createHTML("a",{role:"button",id:f.id+"_open",tabindex:"-1",href:"javascript:;","class":"mceOpen "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"</td>";i+="</tr></tbody>";i=b.createHTML("table",{role:"presentation","class":"mceSplitButton mceSplitButtonEnabled "+g["class"],cellpadding:"0",cellspacing:"0",title:g.title},i);return b.createHTML("div",{id:f.id,role:"button",tabindex:"0","aria-labelledby":f.id+"_voice","aria-haspopup":"true"},i)},postRender:function(){var e=this,g=e.settings,f;if(g.onclick){f=function(h){if(!e.isDisabled()){g.onclick(e.value);a.cancel(h)}};a.add(e.id+"_action","click",f);a.add(e.id,["click","keydown"],function(h){var k=32,m=14,i=13,j=38,l=40;if((h.keyCode===32||h.keyCode===13||h.keyCode===14)&&!h.altKey&&!h.ctrlKey&&!h.metaKey){f();a.cancel(h)}else{if(h.type==="click"||h.keyCode===l){e.showMenu();a.cancel(h)}}})}a.add(e.id+"_open","click",function(h){e.showMenu();a.cancel(h)});a.add([e.id,e.id+"_open"],"focus",function(){e._focused=1});a.add([e.id,e.id+"_open"],"blur",function(){e._focused=0});if(c.isIE6||!b.boxModel){a.add(e.id,"mouseover",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.addClass(e.id,"mceSplitButtonHover")}});a.add(e.id,"mouseout",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.removeClass(e.id,"mceSplitButtonHover")}})}},destroy:function(){this.parent();a.clear(this.id+"_action");a.clear(this.id+"_open");a.clear(this.id)}})})(tinymce);(function(d){var c=d.DOM,a=d.dom.Event,b=d.is,e=d.each;d.create("tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton",{ColorSplitButton:function(i,h,f){var g=this;g.parent(i,h,f);g.settings=h=d.extend({colors:"000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF",grid_width:8,default_color:"#888888"},g.settings);g.onShowMenu=new d.util.Dispatcher(g);g.onHideMenu=new d.util.Dispatcher(g);g.value=h.default_color},showMenu:function(){var f=this,g,j,i,h;if(f.isDisabled()){return}if(!f.isMenuRendered){f.renderMenu();f.isMenuRendered=true}if(f.isMenuVisible){return f.hideMenu()}i=c.get(f.id);c.show(f.id+"_menu");c.addClass(i,"mceSplitButtonSelected");h=c.getPos(i);c.setStyles(f.id+"_menu",{left:h.x,top:h.y+i.firstChild.clientHeight,zIndex:200000});i=0;a.add(c.doc,"mousedown",f.hideMenu,f);f.onShowMenu.dispatch(f);if(f._focused){f._keyHandler=a.add(f.id+"_menu","keydown",function(k){if(k.keyCode==27){f.hideMenu()}});c.select("a",f.id+"_menu")[0].focus()}f.keyboardNav=new d.ui.KeyboardNavigation({root:f.id+"_menu",items:c.select("a",f.id+"_menu"),onCancel:function(){f.hideMenu();f.focus()}});f.keyboardNav.focus();f.isMenuVisible=1},hideMenu:function(g){var f=this;if(f.isMenuVisible){if(g&&g.type=="mousedown"&&c.getParent(g.target,function(h){return h.id===f.id+"_open"})){return}if(!g||!c.getParent(g.target,".mceSplitButtonMenu")){c.removeClass(f.id,"mceSplitButtonSelected");a.remove(c.doc,"mousedown",f.hideMenu,f);a.remove(f.id+"_menu","keydown",f._keyHandler);c.hide(f.id+"_menu")}f.isMenuVisible=0;f.onHideMenu.dispatch();f.keyboardNav.destroy()}},renderMenu:function(){var p=this,h,k=0,q=p.settings,g,j,l,o,f;o=c.add(q.menu_container,"div",{role:"listbox",id:p.id+"_menu","class":q.menu_class+" "+q["class"],style:"position:absolute;left:0;top:-1000px;"});h=c.add(o,"div",{"class":q["class"]+" mceSplitButtonMenu"});c.add(h,"span",{"class":"mceMenuLine"});g=c.add(h,"table",{role:"presentation","class":"mceColorSplitMenu"});j=c.add(g,"tbody");k=0;e(b(q.colors,"array")?q.colors:q.colors.split(","),function(m){m=m.replace(/^#/,"");if(!k--){l=c.add(j,"tr");k=q.grid_width-1}g=c.add(l,"td");var i={href:"javascript:;",style:{backgroundColor:"#"+m},title:p.editor.getLang("colors."+m,m),"data-mce-color":"#"+m};if(!d.isIE){i.role="option"}g=c.add(g,"a",i);if(p.editor.forcedHighContrastMode){g=c.add(g,"canvas",{width:16,height:16,"aria-hidden":"true"});if(g.getContext&&(f=g.getContext("2d"))){f.fillStyle="#"+m;f.fillRect(0,0,16,16)}else{c.remove(g)}}});if(q.more_colors_func){g=c.add(j,"tr");g=c.add(g,"td",{colspan:q.grid_width,"class":"mceMoreColors"});g=c.add(g,"a",{role:"option",id:p.id+"_more",href:"javascript:;",onclick:"return false;","class":"mceMoreColors"},q.more_colors_title);a.add(g,"click",function(i){q.more_colors_func.call(q.more_colors_scope||this);return a.cancel(i)})}c.addClass(h,"mceColorSplitMenu");a.add(p.id+"_menu","mousedown",function(i){return a.cancel(i)});a.add(p.id+"_menu","click",function(i){var m;i=c.getParent(i.target,"a",j);if(i&&i.nodeName.toLowerCase()=="a"&&(m=i.getAttribute("data-mce-color"))){p.setColor(m)}return false});return o},setColor:function(f){this.displayColor(f);this.hideMenu();this.settings.onselect(f)},displayColor:function(g){var f=this;c.setStyle(f.id+"_preview","backgroundColor",g);f.value=g},postRender:function(){var f=this,g=f.id;f.parent();c.add(g+"_action","div",{id:g+"_preview","class":"mceColorPreview"});c.setStyle(f.id+"_preview","backgroundColor",f.value)},destroy:function(){var f=this;f.parent();a.clear(f.id+"_menu");a.clear(f.id+"_more");c.remove(f.id+"_menu");if(f.keyboardNav){f.keyboardNav.destroy()}}})})(tinymce);(function(b){var d=b.DOM,c=b.each,a=b.dom.Event;b.create("tinymce.ui.ToolbarGroup:tinymce.ui.Container",{renderHTML:function(){var f=this,i=[],e=f.controls,j=b.each,g=f.settings;i.push('<div id="'+f.id+'" role="group" aria-labelledby="'+f.id+'_voice">');i.push("<span role='application'>");i.push('<span id="'+f.id+'_voice" class="mceVoiceLabel" style="display:none;">'+d.encode(g.name)+"</span>");j(e,function(h){i.push(h.renderHTML())});i.push("</span>");i.push("</div>");return i.join("")},focus:function(){var e=this;d.get(e.id).focus()},postRender:function(){var f=this,e=[];c(f.controls,function(g){c(g.controls,function(h){if(h.id){e.push(h)}})});f.keyNav=new b.ui.KeyboardNavigation({root:f.id,items:e,onCancel:function(){if(b.isWebKit){d.get(f.editor.id+"_ifr").focus()}f.editor.focus()},excludeFromTabOrder:!f.settings.tab_focus_toolbar})},destroy:function(){var e=this;e.parent();e.keyNav.destroy();a.clear(e.id)}})})(tinymce);(function(a){var c=a.DOM,b=a.each;a.create("tinymce.ui.Toolbar:tinymce.ui.Container",{renderHTML:function(){var m=this,f="",j,k,n=m.settings,e,d,g,l;l=m.controls;for(e=0;e<l.length;e++){k=l[e];d=l[e-1];g=l[e+1];if(e===0){j="mceToolbarStart";if(k.Button){j+=" mceToolbarStartButton"}else{if(k.SplitButton){j+=" mceToolbarStartSplitButton"}else{if(k.ListBox){j+=" mceToolbarStartListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,"<!-- IE -->"))}if(d&&k.ListBox){if(d.Button||d.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarEnd"},c.createHTML("span",null,"<!-- IE -->"))}}if(c.stdMode){f+='<td style="position: relative">'+k.renderHTML()+"</td>"}else{f+="<td>"+k.renderHTML()+"</td>"}if(g&&k.ListBox){if(g.Button||g.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarStart"},c.createHTML("span",null,"<!-- IE -->"))}}}j="mceToolbarEnd";if(k.Button){j+=" mceToolbarEndButton"}else{if(k.SplitButton){j+=" mceToolbarEndSplitButton"}else{if(k.ListBox){j+=" mceToolbarEndListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,"<!-- IE -->"));return c.createHTML("table",{id:m.id,"class":"mceToolbar"+(n["class"]?" "+n["class"]:""),cellpadding:"0",cellspacing:"0",align:m.settings.align||"",role:"presentation",tabindex:"-1"},"<tbody><tr>"+f+"</tr></tbody>")}})})(tinymce);(function(b){var a=b.util.Dispatcher,c=b.each;b.create("tinymce.AddOnManager",{AddOnManager:function(){var d=this;d.items=[];d.urls={};d.lookup={};d.onAdd=new a(d)},get:function(d){if(this.lookup[d]){return this.lookup[d].instance}else{return undefined}},dependencies:function(e){var d;if(this.lookup[e]){d=this.lookup[e].dependencies}return d||[]},requireLangPack:function(e){var d=b.settings;if(d&&d.language&&d.language_load!==false){b.ScriptLoader.add(this.urls[e]+"/langs/"+d.language+".js")}},add:function(f,e,d){this.items.push(e);this.lookup[f]={instance:e,dependencies:d};this.onAdd.dispatch(this,f,e);return e},createUrl:function(d,e){if(typeof e==="object"){return e}else{return{prefix:d.prefix,resource:e,suffix:d.suffix}}},addComponents:function(f,d){var e=this.urls[f];b.each(d,function(g){b.ScriptLoader.add(e+"/"+g)})},load:function(j,f,d,h){var g=this,e=f;function i(){var k=g.dependencies(j);b.each(k,function(m){var l=g.createUrl(f,m);g.load(l.resource,l,undefined,undefined)});if(d){if(h){d.call(h)}else{d.call(b.ScriptLoader)}}}if(g.urls[j]){return}if(typeof f==="object"){e=f.prefix+f.resource+f.suffix}if(e.indexOf("/")!==0&&e.indexOf("://")==-1){e=b.baseURL+"/"+e}g.urls[j]=e.substring(0,e.lastIndexOf("/"));if(g.lookup[j]){i()}else{b.ScriptLoader.add(e,i,h)}}});b.PluginManager=new b.AddOnManager();b.ThemeManager=new b.AddOnManager()}(tinymce));(function(j){var g=j.each,d=j.extend,k=j.DOM,i=j.dom.Event,f=j.ThemeManager,b=j.PluginManager,e=j.explode,h=j.util.Dispatcher,a,c=0;j.documentBaseURL=window.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,"");if(!/[\/\\]$/.test(j.documentBaseURL)){j.documentBaseURL+="/"}j.baseURL=new j.util.URI(j.documentBaseURL).toAbsolute(j.baseURL);j.baseURI=new j.util.URI(j.baseURL);j.onBeforeUnload=new h(j);i.add(window,"beforeunload",function(l){j.onBeforeUnload.dispatch(j,l)});j.onAddEditor=new h(j);j.onRemoveEditor=new h(j);j.EditorManager=d(j,{editors:[],i18n:{},activeEditor:null,init:function(x){var v=this,o,n=j.ScriptLoader,u,l=[],r;function q(t){var s=t.id;if(!s){s=t.name;if(s&&!k.get(s)){s=t.name}else{s=k.uniqueId()}t.setAttribute("id",s)}return s}function m(z,A,t){var y=z[A];if(!y){return}if(j.is(y,"string")){t=y.replace(/\.\w+$/,"");t=t?j.resolve(t):0;y=j.resolve(y)}return y.apply(t||this,Array.prototype.slice.call(arguments,2))}function p(t,s){return s.constructor===RegExp?s.test(t.className):k.hasClass(t,s)}v.settings=x;i.bind(window,"ready",function(){var s,t;m(x,"onpageload");switch(x.mode){case"exact":s=x.elements||"";if(s.length>0){g(e(s),function(y){if(k.get(y)){r=new j.Editor(y,x);l.push(r);r.render(1)}else{g(document.forms,function(z){g(z.elements,function(A){if(A.name===y){y="mce_editor_"+c++;k.setAttrib(A,"id",y);r=new j.Editor(y,x);l.push(r);r.render(1)}})})}})}break;case"textareas":case"specific_textareas":g(k.select("textarea"),function(y){if(x.editor_deselector&&p(y,x.editor_deselector)){return}if(!x.editor_selector||p(y,x.editor_selector)){r=new j.Editor(q(y),x);l.push(r);r.render(1)}});break;default:if(x.types){g(x.types,function(y){g(k.select(y.selector),function(A){var z=new j.Editor(q(A),j.extend({},x,y));l.push(z);z.render(1)})})}else{if(x.selector){g(k.select(x.selector),function(z){var y=new j.Editor(q(z),x);l.push(y);y.render(1)})}}}if(x.oninit){s=t=0;g(l,function(y){t++;if(!y.initialized){y.onInit.add(function(){s++;if(s==t){m(x,"oninit")}})}else{s++}if(s==t){m(x,"oninit")}})}})},get:function(l){if(l===a){return this.editors}if(!this.editors.hasOwnProperty(l)){return a}return this.editors[l]},getInstanceById:function(l){return this.get(l)},add:function(m){var l=this,n=l.editors;n[m.id]=m;n.push(m);l._setActive(m);l.onAddEditor.dispatch(l,m);return m},remove:function(n){var m=this,l,o=m.editors;if(!o[n.id]){return null}delete o[n.id];for(l=0;l<o.length;l++){if(o[l]==n){o.splice(l,1);break}}if(m.activeEditor==n){m._setActive(o[0])}n.destroy();m.onRemoveEditor.dispatch(m,n);return n},execCommand:function(r,p,o){var q=this,n=q.get(o),l;function m(){n.destroy();l.detachEvent("onunload",m);l=l.tinyMCE=l.tinymce=null}switch(r){case"mceFocus":n.focus();return true;case"mceAddEditor":case"mceAddControl":if(!q.get(o)){new j.Editor(o,q.settings).render()}return true;case"mceAddFrameControl":l=o.window;l.tinyMCE=tinyMCE;l.tinymce=j;j.DOM.doc=l.document;j.DOM.win=l;n=new j.Editor(o.element_id,o);n.render();if(j.isIE&&!j.isIE11){l.attachEvent("onunload",m)}o.page_window=null;return true;case"mceRemoveEditor":case"mceRemoveControl":if(n){n.remove()}return true;case"mceToggleEditor":if(!n){q.execCommand("mceAddControl",0,o);return true}if(n.isHidden()){n.show()}else{n.hide()}return true}if(q.activeEditor){return q.activeEditor.execCommand(r,p,o)}return false},execInstanceCommand:function(p,o,n,m){var l=this.get(p);if(l){return l.execCommand(o,n,m)}return false},triggerSave:function(){g(this.editors,function(l){l.save()})},addI18n:function(n,q){var l,m=this.i18n;if(!j.is(n,"string")){g(n,function(r,p){g(r,function(t,s){g(t,function(v,u){if(s==="common"){m[p+"."+u]=v}else{m[p+"."+s+"."+u]=v}})})})}else{g(q,function(r,p){m[n+"."+p]=r})}},_setActive:function(l){this.selectedInstance=this.activeEditor=l}})})(tinymce);(function(k){var l=k.DOM,j=k.dom.Event,f=k.extend,i=k.each,a=k.isGecko,b=k.isIE,e=k.isWebKit,d=k.is,h=k.ThemeManager,c=k.PluginManager,g=k.explode;k.create("tinymce.Editor",{Editor:function(p,o){var m=this,n=true;m.settings=o=f({id:p,language:"en",theme:"advanced",skin:"default",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:k.documentBaseURL,add_form_submit_trigger:n,submit_patch:n,add_unload_trigger:n,convert_urls:n,relative_urls:n,remove_script_host:n,table_inline_editing:false,object_resizing:n,accessibility_focus:n,doctype:k.isIE6?'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">':"<!DOCTYPE>",visual:n,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",apply_source_formatting:n,directionality:"ltr",forced_root_block:"p",hidden_input:n,padd_empty_editor:n,render_ui:n,indentation:"30px",fix_table_elements:n,inline_styles:n,convert_fonts_to_spans:n,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",validate:n,entity_encoding:"named",url_converter:m.convertURL,url_converter_scope:m,ie7_compat:n},o);m.id=m.editorId=p;m.isNotDirty=false;m.plugins={};m.documentBaseURI=new k.util.URI(o.document_base_url||k.documentBaseURL,{base_uri:tinyMCE.baseURI});m.baseURI=k.baseURI;m.contentCSS=[];m.contentStyles=[];m.setupEvents();m.execCommands={};m.queryStateCommands={};m.queryValueCommands={};m.execCallback("setup",m)},render:function(o){var p=this,q=p.settings,r=p.id,m=k.ScriptLoader;if(!j.domLoaded){j.add(window,"ready",function(){p.render()});return}tinyMCE.settings=q;if(!p.getElement()){return}if(k.isIDevice&&!k.isIOS5){return}if(!/TEXTAREA|INPUT/i.test(p.getElement().nodeName)&&q.hidden_input&&l.getParent(r,"form")){l.insertAfter(l.create("input",{type:"hidden",name:r}),r)}if(!q.content_editable){p.orgVisibility=p.getElement().style.visibility;p.getElement().style.visibility="hidden"}if(k.WindowManager){p.windowManager=new k.WindowManager(p)}if(q.encoding=="xml"){p.onGetContent.add(function(s,t){if(t.save){t.content=l.encode(t.content)}})}if(q.add_form_submit_trigger){p.onSubmit.addToTop(function(){if(p.initialized){p.save();p.isNotDirty=1}})}if(q.add_unload_trigger){p._beforeUnload=tinyMCE.onBeforeUnload.add(function(){if(p.initialized&&!p.destroyed&&!p.isHidden()){p.save({format:"raw",no_events:true})}})}k.addUnload(p.destroy,p);if(q.submit_patch){p.onBeforeRenderUI.add(function(){var s=p.getElement().form;if(!s){return}if(s._mceOldSubmit){return}if(!s.submit.nodeType&&!s.submit.length){p.formElement=s;s._mceOldSubmit=s.submit;s.submit=function(){k.triggerSave();p.isNotDirty=1;return p.formElement._mceOldSubmit(p.formElement)}}s=null})}function n(){if(q.language&&q.language_load!==false){m.add(k.baseURL+"/langs/"+q.language+".js")}if(q.theme&&typeof q.theme!="function"&&q.theme.charAt(0)!="-"&&!h.urls[q.theme]){h.load(q.theme,"themes/"+q.theme+"/editor_template"+k.suffix+".js")}i(g(q.plugins),function(t){if(t&&!c.urls[t]){if(t.charAt(0)=="-"){t=t.substr(1,t.length);var s=c.dependencies(t);i(s,function(v){var u={prefix:"plugins/",resource:v,suffix:"/editor_plugin"+k.suffix+".js"};v=c.createUrl(u,v);c.load(v.resource,v)})}else{if(t=="safari"){return}c.load(t,{prefix:"plugins/",resource:t,suffix:"/editor_plugin"+k.suffix+".js"})}}});m.loadQueue(function(){if(!p.removed){p.init()}})}n()},init:function(){var q,G=this,H=G.settings,D,y,z,C=G.getElement(),p,m,E,v,B,F,x,r=[];k.add(G);H.aria_label=H.aria_label||l.getAttrib(C,"aria-label",G.getLang("aria.rich_text_area"));if(H.theme){if(typeof H.theme!="function"){H.theme=H.theme.replace(/-/,"");p=h.get(H.theme);G.theme=new p();if(G.theme.init){G.theme.init(G,h.urls[H.theme]||k.documentBaseURL.replace(/\/$/,""))}}else{G.theme=H.theme}}function A(s){var t=c.get(s),o=c.urls[s]||k.documentBaseURL.replace(/\/$/,""),n;if(t&&k.inArray(r,s)===-1){i(c.dependencies(s),function(u){A(u)});n=new t(G,o);G.plugins[s]=n;if(n.init){n.init(G,o);r.push(s)}}}i(g(H.plugins.replace(/\-/g,"")),A);if(H.popup_css!==false){if(H.popup_css){H.popup_css=G.documentBaseURI.toAbsolute(H.popup_css)}else{H.popup_css=G.baseURI.toAbsolute("themes/"+H.theme+"/skins/"+H.skin+"/dialog.css")}}if(H.popup_css_add){H.popup_css+=","+G.documentBaseURI.toAbsolute(H.popup_css_add)}G.controlManager=new k.ControlManager(G);G.onBeforeRenderUI.dispatch(G,G.controlManager);if(H.render_ui&&G.theme){G.orgDisplay=C.style.display;if(typeof H.theme!="function"){D=H.width||C.style.width||C.offsetWidth;y=H.height||C.style.height||C.offsetHeight;z=H.min_height||100;F=/^[0-9\.]+(|px)$/i;if(F.test(""+D)){D=Math.max(parseInt(D,10)+(p.deltaWidth||0),100)}if(F.test(""+y)){y=Math.max(parseInt(y,10)+(p.deltaHeight||0),z)}p=G.theme.renderUI({targetNode:C,width:D,height:y,deltaWidth:H.delta_width,deltaHeight:H.delta_height});l.setStyles(p.sizeContainer||p.editorContainer,{width:D,height:y});y=(p.iframeHeight||y)+(typeof(y)=="number"?(p.deltaHeight||0):"");if(y<z){y=z}}else{p=H.theme(G,C);if(p.editorContainer.nodeType){p.editorContainer=p.editorContainer.id=p.editorContainer.id||G.id+"_parent"}if(p.iframeContainer.nodeType){p.iframeContainer=p.iframeContainer.id=p.iframeContainer.id||G.id+"_iframecontainer"}y=p.iframeHeight||C.offsetHeight;if(b){G.onInit.add(function(n){n.dom.bind(n.getBody(),"beforedeactivate keydown keyup",function(){n.bookmark=n.selection.getBookmark(1)})});G.onNodeChange.add(function(n){if(document.activeElement.id==n.id+"_ifr"){n.bookmark=n.selection.getBookmark(1)}})}}G.editorContainer=p.editorContainer}if(H.content_css){i(g(H.content_css),function(n){G.contentCSS.push(G.documentBaseURI.toAbsolute(n))})}if(H.content_style){G.contentStyles.push(H.content_style)}if(H.content_editable){C=q=p=null;return G.initContentBody()}if(document.domain&&location.hostname!=document.domain){k.relaxedDomain=document.domain}G.iframeHTML=H.doctype+'<html><head xmlns="http://www.w3.org/1999/xhtml">';if(H.document_base_url!=k.documentBaseURL){G.iframeHTML+='<base href="'+G.documentBaseURI.getURI()+'" />'}if(k.isIE8){if(H.ie7_compat){G.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=7" />'}else{G.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=edge" />'}}G.iframeHTML+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';for(x=0;x<G.contentCSS.length;x++){G.iframeHTML+='<link type="text/css" rel="stylesheet" href="'+G.contentCSS[x]+'" />'}G.contentCSS=[];v=H.body_id||"tinymce";if(v.indexOf("=")!=-1){v=G.getParam("body_id","","hash");v=v[G.id]||v}B=H.body_class||"";if(B.indexOf("=")!=-1){B=G.getParam("body_class","","hash");B=B[G.id]||""}G.iframeHTML+='</head><body id="'+v+'" class="mceContentBody '+B+'" onload="window.parent.tinyMCE.get(\''+G.id+"').onLoad.dispatch();\"><br></body></html>";if(k.relaxedDomain&&(b||(k.isOpera&&parseFloat(opera.version())<11))){E='javascript:(function(){document.open();document.domain="'+document.domain+'";var ed = window.parent.tinyMCE.get("'+G.id+'");document.write(ed.iframeHTML);document.close();ed.initContentBody();})()'}q=l.add(p.iframeContainer,"iframe",{id:G.id+"_ifr",src:E||'javascript:""',frameBorder:"0",allowTransparency:"true",title:H.aria_label,style:{width:"100%",height:y,display:"block"}});G.contentAreaContainer=p.iframeContainer;if(p.editorContainer){l.get(p.editorContainer).style.display=G.orgDisplay}C.style.visibility=G.orgVisibility;l.get(G.id).style.display="none";l.setAttrib(G.id,"aria-hidden",true);if(!k.relaxedDomain||!E){G.initContentBody()}C=q=p=null},initContentBody:function(){var n=this,p=n.settings,q=l.get(n.id),r=n.getDoc(),o,m,s;if((!b||!k.relaxedDomain)&&!p.content_editable){r.open();r.write(n.iframeHTML);r.close();if(k.relaxedDomain){r.domain=k.relaxedDomain}}if(p.content_editable){l.addClass(q,"mceContentBody");n.contentDocument=r=p.content_document||document;n.contentWindow=p.content_window||window;n.bodyElement=q;p.content_document=p.content_window=null}m=n.getBody();m.disabled=true;if(!p.readonly){m.contentEditable=n.getParam("content_editable_state",true)}m.disabled=false;n.schema=new k.html.Schema(p);n.dom=new k.dom.DOMUtils(r,{keep_values:true,url_converter:n.convertURL,url_converter_scope:n,hex_colors:p.force_hex_style_colors,class_filter:p.class_filter,update_styles:true,root_element:p.content_editable?n.id:null,schema:n.schema});n.parser=new k.html.DomParser(p,n.schema);n.parser.addAttributeFilter("src,href,style",function(t,u){var v=t.length,y,A=n.dom,z,x;while(v--){y=t[v];z=y.attr(u);x="data-mce-"+u;if(!y.attributes.map[x]){if(u==="style"){y.attr(x,A.serializeStyle(A.parseStyle(z),y.name))}else{y.attr(x,n.convertURL(z,u,y.name))}}}});n.parser.addNodeFilter("script",function(t,u){var v=t.length,x;while(v--){x=t[v];x.attr("type","mce-"+(x.attr("type")||"text/javascript"))}});n.parser.addNodeFilter("#cdata",function(t,u){var v=t.length,x;while(v--){x=t[v];x.type=8;x.name="#comment";x.value="[CDATA["+x.value+"]]"}});n.parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(u,v){var x=u.length,y,t=n.schema.getNonEmptyElements();while(x--){y=u[x];if(y.isEmpty(t)){y.empty().append(new k.html.Node("br",1)).shortEnded=true}}});n.serializer=new k.dom.Serializer(p,n.dom,n.schema);n.selection=new k.dom.Selection(n.dom,n.getWin(),n.serializer,n);n.formatter=new k.Formatter(n);n.undoManager=new k.UndoManager(n);n.forceBlocks=new k.ForceBlocks(n);n.enterKey=new k.EnterKey(n);n.editorCommands=new k.EditorCommands(n);n.onExecCommand.add(function(t,u){if(!/^(FontName|FontSize)$/.test(u)){n.nodeChanged()}});n.serializer.onPreProcess.add(function(t,u){return n.onPreProcess.dispatch(n,u,t)});n.serializer.onPostProcess.add(function(t,u){return n.onPostProcess.dispatch(n,u,t)});n.onPreInit.dispatch(n);if(!p.browser_spellcheck&&!p.gecko_spellcheck){r.body.spellcheck=false}if(!p.readonly){n.bindNativeEvents()}n.controlManager.onPostRender.dispatch(n,n.controlManager);n.onPostRender.dispatch(n);n.quirks=k.util.Quirks(n);if(p.directionality){m.dir=p.directionality}if(p.nowrap){m.style.whiteSpace="nowrap"}if(p.protect){n.onBeforeSetContent.add(function(t,u){i(p.protect,function(v){u.content=u.content.replace(v,function(x){return"<!--mce:protected "+escape(x)+"-->"})})})}n.onSetContent.add(function(){n.addVisual(n.getBody())});if(p.padd_empty_editor){n.onPostProcess.add(function(t,u){u.content=u.content.replace(/^(<p[^>]*>( | |\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/,"")})}n.load({initial:true,format:"html"});n.startContent=n.getContent({format:"raw"});n.initialized=true;n.onInit.dispatch(n);n.execCallback("setupcontent_callback",n.id,m,r);n.execCallback("init_instance_callback",n);n.focus(true);n.nodeChanged({initial:true});if(n.contentStyles.length>0){s="";i(n.contentStyles,function(t){s+=t+"\r\n"});n.dom.addStyle(s)}i(n.contentCSS,function(t){n.dom.loadCSS(t)});if(p.auto_focus){setTimeout(function(){var t=k.get(p.auto_focus);t.selection.select(t.getBody(),1);t.selection.collapse(1);t.getBody().focus();t.getWin().focus()},100)}q=r=m=null},focus:function(p){var o,u=this,t=u.selection,q=u.settings.content_editable,n,r,s=u.getDoc(),m;if(!p){if(u.bookmark){t.moveToBookmark(u.bookmark);u.bookmark=null}n=t.getRng();if(n.item){r=n.item(0)}u._refreshContentEditable();if(!q){u.getWin().focus()}if(k.isGecko||q){m=u.getBody();if(m.setActive&&!k.isIE11){m.setActive()}else{m.focus()}if(q){t.normalize()}}if(r&&r.ownerDocument==s){n=s.body.createControlRange();n.addElement(r);n.select()}}if(k.activeEditor!=u){if((o=k.activeEditor)!=null){o.onDeactivate.dispatch(o,u)}u.onActivate.dispatch(u,o)}k._setActive(u)},execCallback:function(q){var m=this,p=m.settings[q],o;if(!p){return}if(m.callbackLookup&&(o=m.callbackLookup[q])){p=o.func;o=o.scope}if(d(p,"string")){o=p.replace(/\.\w+$/,"");o=o?k.resolve(o):0;p=k.resolve(p);m.callbackLookup=m.callbackLookup||{};m.callbackLookup[q]={func:p,scope:o}}return p.apply(o||m,Array.prototype.slice.call(arguments,1))},translate:function(m){var o=this.settings.language||"en",n=k.i18n;if(!m){return""}return n[o+"."+m]||m.replace(/\{\#([^\}]+)\}/g,function(q,p){return n[o+"."+p]||"{#"+p+"}"})},getLang:function(o,m){return k.i18n[(this.settings.language||"en")+"."+o]||(d(m)?m:"{#"+o+"}")},getParam:function(t,q,m){var r=k.trim,p=d(this.settings[t])?this.settings[t]:q,s;if(m==="hash"){s={};if(d(p,"string")){i(p.indexOf("=")>0?p.split(/[;,](?![^=;,]*(?:[;,]|$))/):p.split(","),function(n){n=n.split("=");if(n.length>1){s[r(n[0])]=r(n[1])}else{s[r(n[0])]=r(n)}})}else{s=p}return s}return p},nodeChanged:function(q){var m=this,n=m.selection,p;if(m.initialized){q=q||{};p=n.getStart()||m.getBody();p=b&&p.ownerDocument!=m.getDoc()?m.getBody():p;q.parents=[];m.dom.getParent(p,function(o){if(o.nodeName=="BODY"){return true}q.parents.push(o)});m.onNodeChange.dispatch(m,q?q.controlManager||m.controlManager:m.controlManager,p,n.isCollapsed(),q)}},addButton:function(n,o){var m=this;m.buttons=m.buttons||{};m.buttons[n]=o},addCommand:function(m,o,n){this.execCommands[m]={func:o,scope:n||this}},addQueryStateHandler:function(m,o,n){this.queryStateCommands[m]={func:o,scope:n||this}},addQueryValueHandler:function(m,o,n){this.queryValueCommands[m]={func:o,scope:n||this}},addShortcut:function(o,q,m,p){var n=this,r;if(n.settings.custom_shortcuts===false){return false}n.shortcuts=n.shortcuts||{};if(d(m,"string")){r=m;m=function(){n.execCommand(r,false,null)}}if(d(m,"object")){r=m;m=function(){n.execCommand(r[0],r[1],r[2])}}i(g(o),function(s){var t={func:m,scope:p||this,desc:n.translate(q),alt:false,ctrl:false,shift:false};i(g(s,"+"),function(u){switch(u){case"alt":case"ctrl":case"shift":t[u]=true;break;default:t.charCode=u.charCodeAt(0);t.keyCode=u.toUpperCase().charCodeAt(0)}});n.shortcuts[(t.ctrl?"ctrl":"")+","+(t.alt?"alt":"")+","+(t.shift?"shift":"")+","+t.keyCode]=t});return true},execCommand:function(u,r,x,m){var p=this,q=0,v,n;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(u)&&(!m||!m.skip_focus)){p.focus()}m=f({},m);p.onBeforeExecCommand.dispatch(p,u,r,x,m);if(m.terminate){return false}if(p.execCallback("execcommand_callback",p.id,p.selection.getNode(),u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(v=p.execCommands[u]){n=v.func.call(v.scope,r,x);if(n!==true){p.onExecCommand.dispatch(p,u,r,x,m);return n}}i(p.plugins,function(o){if(o.execCommand&&o.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);q=1;return false}});if(q){return true}if(p.theme&&p.theme.execCommand&&p.theme.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(p.editorCommands.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}p.getDoc().execCommand(u,r,x);p.onExecCommand.dispatch(p,u,r,x,m)},queryCommandState:function(q){var n=this,r,p;if(n._isHidden()){return}if(r=n.queryStateCommands[q]){p=r.func.call(r.scope);if(p!==true){return p}}r=n.editorCommands.queryCommandState(q);if(r!==-1){return r}try{return this.getDoc().queryCommandState(q)}catch(m){}},queryCommandValue:function(r){var n=this,q,p;if(n._isHidden()){return}if(q=n.queryValueCommands[r]){p=q.func.call(q.scope);if(p!==true){return p}}q=n.editorCommands.queryCommandValue(r);if(d(q)){return q}try{return this.getDoc().queryCommandValue(r)}catch(m){}},show:function(){var m=this;l.show(m.getContainer());l.hide(m.id);m.load()},hide:function(){var m=this,n=m.getDoc();if(b&&n){n.execCommand("SelectAll")}m.save();l.hide(m.getContainer());l.setStyle(m.id,"display",m.orgDisplay)},isHidden:function(){return !l.isHidden(this.id)},setProgressState:function(m,n,p){this.onSetProgressState.dispatch(this,m,n,p);return m},load:function(q){var m=this,p=m.getElement(),n;if(p){q=q||{};q.load=true;n=m.setContent(d(p.value)?p.value:p.innerHTML,q);q.element=p;if(!q.no_events){m.onLoadContent.dispatch(m,q)}q.element=p=null;return n}},save:function(r){var m=this,q=m.getElement(),n,p;if(!q||!m.initialized){return}r=r||{};r.save=true;r.element=q;n=r.content=m.getContent(r);if(!r.no_events){m.onSaveContent.dispatch(m,r)}n=r.content;if(!/TEXTAREA|INPUT/i.test(q.nodeName)){q.innerHTML=n;if(p=l.getParent(m.id,"form")){i(p.elements,function(o){if(o.name==m.id){o.value=n;return false}})}}else{q.value=n}r.element=q=null;return n},setContent:function(r,p){var o=this,n,m=o.getBody(),q;p=p||{};p.format=p.format||"html";p.set=true;p.content=r;if(!p.no_events){o.onBeforeSetContent.dispatch(o,p)}r=p.content;if(!k.isIE&&(r.length===0||/^\s+$/.test(r))){q=o.settings.forced_root_block;if(q){r="<"+q+'><br data-mce-bogus="1"></'+q+">"}else{r='<br data-mce-bogus="1">'}m.innerHTML=r;o.selection.select(m,true);o.selection.collapse(true);return}if(p.format!=="raw"){r=new k.html.Serializer({},o.schema).serialize(o.parser.parse(r))}p.content=k.trim(r);o.dom.setHTML(m,p.content);if(!p.no_events){o.onSetContent.dispatch(o,p)}if(!o.settings.content_editable||document.activeElement===o.getBody()){o.selection.normalize()}return p.content},getContent:function(o){var n=this,p,m=n.getBody();o=o||{};o.format=o.format||"html";o.get=true;o.getInner=true;if(!o.no_events){n.onBeforeGetContent.dispatch(n,o)}if(o.format=="raw"){p=m.innerHTML}else{if(o.format=="text"){p=m.innerText||m.textContent}else{p=n.serializer.serialize(m,o)}}if(o.format!="text"){o.content=k.trim(p)}else{o.content=p}if(!o.no_events){n.onGetContent.dispatch(n,o)}return o.content},isDirty:function(){var m=this;return k.trim(m.startContent)!=k.trim(m.getContent({format:"raw",no_events:1}))&&!m.isNotDirty},getContainer:function(){var m=this;if(!m.container){m.container=l.get(m.editorContainer||m.id+"_parent")}return m.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return l.get(this.settings.content_element||this.id)},getWin:function(){var m=this,n;if(!m.contentWindow){n=l.get(m.id+"_ifr");if(n){m.contentWindow=n.contentWindow}}return m.contentWindow},getDoc:function(){var m=this,n;if(!m.contentDocument){n=m.getWin();if(n){m.contentDocument=n.document}}return m.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(o,n,q){var m=this,p=m.settings;if(p.urlconverter_callback){return m.execCallback("urlconverter_callback",o,q,true,n)}if(!p.convert_urls||(q&&q.nodeName=="LINK")||o.indexOf("file:")===0){return o}if(p.relative_urls){return m.documentBaseURI.toRelative(o)}o=m.documentBaseURI.toAbsolute(o,p.remove_script_host);return o},addVisual:function(q){var n=this,o=n.settings,p=n.dom,m;q=q||n.getBody();if(!d(n.hasVisual)){n.hasVisual=o.visual}i(p.select("table,a",q),function(s){var r;switch(s.nodeName){case"TABLE":m=o.visual_table_class||"mceItemTable";r=p.getAttrib(s,"border");if(!r||r=="0"){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}return;case"A":if(!p.getAttrib(s,"href",false)){r=p.getAttrib(s,"name")||s.id;m="mceItemAnchor";if(r){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}}return}});n.onVisualAid.dispatch(n,q,n.hasVisual)},remove:function(){var m=this,o=m.getContainer(),n=m.getDoc();if(!m.removed){m.removed=1;if(b&&n){n.execCommand("SelectAll")}m.save();l.setStyle(m.id,"display",m.orgDisplay);if(!m.settings.content_editable){j.unbind(m.getWin());j.unbind(m.getDoc())}j.unbind(m.getBody());j.clear(o);m.execCallback("remove_instance_callback",m);m.onRemove.dispatch(m);m.onExecCommand.listeners=[];k.remove(m);l.remove(o)}},destroy:function(n){var m=this;if(m.destroyed){return}if(a){j.unbind(m.getDoc());j.unbind(m.getWin());j.unbind(m.getBody())}if(!n){k.removeUnload(m.destroy);tinyMCE.onBeforeUnload.remove(m._beforeUnload);if(m.theme&&m.theme.destroy){m.theme.destroy()}m.controlManager.destroy();m.selection.destroy();m.dom.destroy()}if(m.formElement){m.formElement.submit=m.formElement._mceOldSubmit;m.formElement._mceOldSubmit=null}m.contentAreaContainer=m.formElement=m.container=m.settings.content_element=m.bodyElement=m.contentDocument=m.contentWindow=null;if(m.selection){m.selection=m.selection.win=m.selection.dom=m.selection.dom.doc=null}m.destroyed=1},_refreshContentEditable:function(){var n=this,m,o;if(n._isHidden()){m=n.getBody();o=m.parentNode;o.removeChild(m);o.appendChild(m);m.focus()}},_isHidden:function(){var m;if(!a){return 0}m=this.selection.getSel();return(!m||!m.rangeCount||m.rangeCount===0)}})})(tinymce);(function(a){var b=a.each;a.Editor.prototype.setupEvents=function(){var c=this,d=c.settings;b(["onPreInit","onBeforeRenderUI","onPostRender","onLoad","onInit","onRemove","onActivate","onDeactivate","onClick","onEvent","onMouseUp","onMouseDown","onDblClick","onKeyDown","onKeyUp","onKeyPress","onContextMenu","onSubmit","onReset","onPaste","onPreProcess","onPostProcess","onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent","onLoadContent","onSaveContent","onNodeChange","onChange","onBeforeExecCommand","onExecCommand","onUndo","onRedo","onVisualAid","onSetProgressState","onSetAttrib"],function(e){c[e]=new a.util.Dispatcher(c)});if(d.cleanup_callback){c.onBeforeSetContent.add(function(e,f){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)});c.onPreProcess.add(function(e,f){if(f.set){e.execCallback("cleanup_callback","insert_to_editor_dom",f.node,f)}if(f.get){e.execCallback("cleanup_callback","get_from_editor_dom",f.node,f)}});c.onPostProcess.add(function(e,f){if(f.set){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)}if(f.get){f.content=e.execCallback("cleanup_callback","get_from_editor",f.content,f)}})}if(d.save_callback){c.onGetContent.add(function(e,f){if(f.save){f.content=e.execCallback("save_callback",e.id,f.content,e.getBody())}})}if(d.handle_event_callback){c.onEvent.add(function(f,g,h){if(c.execCallback("handle_event_callback",g,f,h)===false){g.preventDefault();g.stopPropagation()}})}if(d.handle_node_change_callback){c.onNodeChange.add(function(f,e,g){f.execCallback("handle_node_change_callback",f.id,g,-1,-1,true,f.selection.isCollapsed())})}if(d.save_callback){c.onSaveContent.add(function(e,g){var f=e.execCallback("save_callback",e.id,g.content,e.getBody());if(f){g.content=f}})}if(d.onchange_callback){c.onChange.add(function(f,e){f.execCallback("onchange_callback",f,e)})}};a.Editor.prototype.bindNativeEvents=function(){var l=this,f,d=l.settings,e=l.dom,h;h={mouseup:"onMouseUp",mousedown:"onMouseDown",click:"onClick",keyup:"onKeyUp",keydown:"onKeyDown",keypress:"onKeyPress",submit:"onSubmit",reset:"onReset",contextmenu:"onContextMenu",dblclick:"onDblClick",paste:"onPaste"};function c(i,m){var n=i.type;if(l.removed){return}if(l.onEvent.dispatch(l,i,m)!==false){l[h[i.fakeType||i.type]].dispatch(l,i,m)}}function j(i){l.focus(true)}function k(i,m){if(m.keyCode!=65||!a.VK.metaKeyPressed(m)){l.selection.normalize()}l.nodeChanged()}b(h,function(m,n){var i=d.content_editable?l.getBody():l.getDoc();switch(n){case"contextmenu":e.bind(i,n,c);break;case"paste":e.bind(l.getBody(),n,c);break;case"submit":case"reset":e.bind(l.getElement().form||a.DOM.getParent(l.id,"form"),n,c);break;default:e.bind(i,n,c)}});e.bind(d.content_editable?l.getBody():(a.isGecko?l.getDoc():l.getWin()),"focus",function(i){l.focus(true)});if(d.content_editable&&a.isOpera){e.bind(l.getBody(),"click",j);e.bind(l.getBody(),"keydown",j)}l.onMouseUp.add(k);l.onKeyUp.add(function(i,n){var m=n.keyCode;if((m>=33&&m<=36)||(m>=37&&m<=40)||m==13||m==45||m==46||m==8||(a.isMac&&(m==91||m==93))||n.ctrlKey){k(i,n)}});l.onReset.add(function(){l.setContent(l.startContent,{format:"raw"})});function g(m,i){if(m.altKey||m.ctrlKey||m.metaKey){b(l.shortcuts,function(n){var o=a.isMac?m.metaKey:m.ctrlKey;if(n.ctrl!=o||n.alt!=m.altKey||n.shift!=m.shiftKey){return}if(m.keyCode==n.keyCode||(m.charCode&&m.charCode==n.charCode)){m.preventDefault();if(i){n.func.call(n.scope)}return true}})}}l.onKeyUp.add(function(i,m){g(m)});l.onKeyPress.add(function(i,m){g(m)});l.onKeyDown.add(function(i,m){g(m,true)});if(a.isOpera){l.onClick.add(function(i,m){m.preventDefault()})}}})(tinymce);(function(d){var e=d.each,b,a=true,c=false;d.EditorCommands=function(n){var m=n.dom,p=n.selection,j={state:{},exec:{},value:{}},k=n.settings,q=n.formatter,o;function r(z,y,x){var v;z=z.toLowerCase();if(v=j.exec[z]){v(z,y,x);return a}return c}function l(x){var v;x=x.toLowerCase();if(v=j.state[x]){return v(x)}return -1}function h(x){var v;x=x.toLowerCase();if(v=j.value[x]){return v(x)}return c}function u(v,x){x=x||"exec";e(v,function(z,y){e(y.toLowerCase().split(","),function(A){j[x][A]=z})})}d.extend(this,{execCommand:r,queryCommandState:l,queryCommandValue:h,addCommands:u});function f(y,x,v){if(x===b){x=c}if(v===b){v=null}return n.getDoc().execCommand(y,x,v)}function t(v){return q.match(v)}function s(v,x){q.toggle(v,x?{value:x}:b)}function i(v){o=p.getBookmark(v)}function g(){p.moveToBookmark(o)}u({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){n.undoManager.add()},"Cut,Copy,Paste":function(z){var y=n.getDoc(),v;try{f(z)}catch(x){v=a}if(v||!y.queryCommandSupported(z)){if(d.isGecko){n.windowManager.confirm(n.getLang("clipboard_msg"),function(A){if(A){open("http://www.mozilla.org/editor/midasdemo/securityprefs.html","_blank")}})}else{n.windowManager.alert(n.getLang("clipboard_no_support"))}}},unlink:function(v){if(p.isCollapsed()){p.select(p.getNode())}f(v);p.collapse(c)},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(v){var x=v.substring(7);e("left,center,right,full".split(","),function(y){if(x!=y){q.remove("align"+y)}});s("align"+x);r("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(y){var v,x;f(y);v=m.getParent(p.getNode(),"ol,ul");if(v){x=v.parentNode;if(/^(H[1-6]|P|ADDRESS|PRE)$/.test(x.nodeName)){i();m.split(x,v);g()}}},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){s(v)},"ForeColor,HiliteColor,FontName":function(y,x,v){s(y,v)},FontSize:function(z,y,x){var v,A;if(x>=1&&x<=7){A=d.explode(k.font_size_style_values);v=d.explode(k.font_size_classes);if(v){x=v[x-1]||x}else{x=A[x-1]||x}}s(z,x)},RemoveFormat:function(v){q.remove(v)},mceBlockQuote:function(v){s("blockquote")},FormatBlock:function(y,x,v){return s(v||"p")},mceCleanup:function(){var v=p.getBookmark();n.setContent(n.getContent({cleanup:a}),{cleanup:a});p.moveToBookmark(v)},mceRemoveNode:function(z,y,x){var v=x||p.getNode();if(v!=n.getBody()){i();n.dom.remove(v,a);g()}},mceSelectNodeDepth:function(z,y,x){var v=0;m.getParent(p.getNode(),function(A){if(A.nodeType==1&&v++==x){p.select(A);return c}},n.getBody())},mceSelectNode:function(y,x,v){p.select(v)},mceInsertContent:function(B,I,K){var y,J,E,z,F,G,D,C,L,x,A,M,v,H;y=n.parser;J=new d.html.Serializer({},n.schema);v='<span id="mce_marker" data-mce-type="bookmark">\uFEFF</span>';G={content:K,format:"html"};p.onBeforeSetContent.dispatch(p,G);K=G.content;if(K.indexOf("{$caret}")==-1){K+="{$caret}"}K=K.replace(/\{\$caret\}/,v);if(!p.isCollapsed()){n.getDoc().execCommand("Delete",false,null)}E=p.getNode();G={context:E.nodeName.toLowerCase()};F=y.parse(K,G);A=F.lastChild;if(A.attr("id")=="mce_marker"){D=A;for(A=A.prev;A;A=A.walk(true)){if(A.type==3||!m.isBlock(A.name)){A.parent.insert(D,A,A.name==="br");break}}}if(!G.invalid){K=J.serialize(F);A=E.firstChild;M=E.lastChild;if(!A||(A===M&&A.nodeName==="BR")){m.setHTML(E,K)}else{p.setContent(K)}}else{p.setContent(v);E=p.getNode();z=n.getBody();if(E.nodeType==9){E=A=z}else{A=E}while(A!==z){E=A;A=A.parentNode}K=E==z?z.innerHTML:m.getOuterHTML(E);K=J.serialize(y.parse(K.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i,function(){return J.serialize(F)})));if(E==z){m.setHTML(z,K)}else{m.setOuterHTML(E,K)}}D=m.get("mce_marker");C=m.getRect(D);L=m.getViewPort(n.getWin());if((C.y+C.h>L.y+L.h||C.y<L.y)||(C.x>L.x+L.w||C.x<L.x)){H=d.isIE?n.getDoc().documentElement:n.getBody();H.scrollLeft=C.x;H.scrollTop=C.y-L.h+25}x=m.createRng();A=D.previousSibling;if(A&&A.nodeType==3){x.setStart(A,A.nodeValue.length)}else{x.setStartBefore(D);x.setEndBefore(D)}m.remove(D);p.setRng(x);p.onSetContent.dispatch(p,G);n.addVisual()},mceInsertRawHTML:function(y,x,v){p.setContent("tiny_mce_marker");n.setContent(n.getContent().replace(/tiny_mce_marker/g,function(){return v}))},mceToggleFormat:function(y,x,v){s(v)},mceSetContent:function(y,x,v){n.setContent(v)},"Indent,Outdent":function(z){var x,v,y;x=k.indentation;v=/[a-z%]+$/i.exec(x);x=parseInt(x);if(!l("InsertUnorderedList")&&!l("InsertOrderedList")){if(!k.forced_root_block&&!m.getParent(p.getNode(),m.isBlock)){q.apply("div")}e(p.getSelectedBlocks(),function(A){if(z=="outdent"){y=Math.max(0,parseInt(A.style.paddingLeft||0)-x);m.setStyle(A,"paddingLeft",y?y+v:"")}else{m.setStyle(A,"paddingLeft",(parseInt(A.style.paddingLeft||0)+x)+v)}})}else{f(z)}},mceRepaint:function(){var x;if(d.isGecko){try{i(a);if(p.getSel()){p.getSel().selectAllChildren(n.getBody())}p.collapse(a);g()}catch(v){}}},mceToggleFormat:function(y,x,v){q.toggle(v)},InsertHorizontalRule:function(){n.execCommand("mceInsertContent",false,"<hr />")},mceToggleVisualAid:function(){n.hasVisual=!n.hasVisual;n.addVisual()},mceReplaceContent:function(y,x,v){n.execCommand("mceInsertContent",false,v.replace(/\{\$selection\}/g,p.getContent({format:"text"})))},mceInsertLink:function(z,y,x){var v;if(typeof(x)=="string"){x={href:x}}v=m.getParent(p.getNode(),"a");x.href=x.href.replace(" ","%20");if(!v||!x.href){q.remove("link")}if(x.href){q.apply("link",x,v)}},selectAll:function(){var x=m.getRoot(),v=m.createRng();if(p.getRng().setStart){v.setStart(x,0);v.setEnd(x,x.childNodes.length);p.setRng(v)}else{f("SelectAll")}}});u({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(z){var x="align"+z.substring(7);var v=p.isCollapsed()?[m.getParent(p.getNode(),m.isBlock)]:p.getSelectedBlocks();var y=d.map(v,function(A){return !!q.matchNode(A,x)});return d.inArray(y,a)!==-1},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){return t(v)},mceBlockQuote:function(){return t("blockquote")},Outdent:function(){var v;if(k.inline_styles){if((v=m.getParent(p.getStart(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}if((v=m.getParent(p.getEnd(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}}return l("InsertUnorderedList")||l("InsertOrderedList")||(!k.inline_styles&&!!m.getParent(p.getNode(),"BLOCKQUOTE"))},"InsertUnorderedList,InsertOrderedList":function(x){var v=m.getParent(p.getNode(),"ul,ol");return v&&(x==="insertunorderedlist"&&v.tagName==="UL"||x==="insertorderedlist"&&v.tagName==="OL")}},"state");u({"FontSize,FontName":function(y){var x=0,v;if(v=m.getParent(p.getNode(),"span")){if(y=="fontsize"){x=v.style.fontSize}else{x=v.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()}}return x}},"value");u({Undo:function(){n.undoManager.undo()},Redo:function(){n.undoManager.redo()}})}})(tinymce);(function(b){var a=b.util.Dispatcher;b.UndoManager=function(h){var l,i=0,e=[],g,k,j,f;function c(){return b.trim(h.getContent({format:"raw",no_events:1}).replace(/<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>/g,""))}function d(){l.typing=false;l.add()}onBeforeAdd=new a(l);k=new a(l);j=new a(l);f=new a(l);k.add(function(m,n){if(m.hasUndo()){return h.onChange.dispatch(h,n,m)}});j.add(function(m,n){return h.onUndo.dispatch(h,n,m)});f.add(function(m,n){return h.onRedo.dispatch(h,n,m)});h.onInit.add(function(){l.add()});h.onBeforeExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.beforeChange()}});h.onExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.add()}});h.onSaveContent.add(d);h.dom.bind(h.dom.getRoot(),"dragend",d);h.dom.bind(h.getBody(),"focusout",function(m){if(!h.removed&&l.typing){d()}});h.onKeyUp.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45||n==13||o.ctrlKey){d()}});h.onKeyDown.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45){if(l.typing){d()}return}if((n<16||n>20)&&n!=224&&n!=91&&!l.typing){l.beforeChange();l.typing=true;l.add()}});h.onMouseDown.add(function(m,n){if(l.typing){d()}});h.addShortcut("ctrl+z","undo_desc","Undo");h.addShortcut("ctrl+y","redo_desc","Redo");l={data:e,typing:false,onBeforeAdd:onBeforeAdd,onAdd:k,onUndo:j,onRedo:f,beforeChange:function(){g=h.selection.getBookmark(2,true)},add:function(p){var m,n=h.settings,o;p=p||{};p.content=c();l.onBeforeAdd.dispatch(l,p);o=e[i];if(o&&o.content==p.content){return null}if(e[i]){e[i].beforeBookmark=g}if(n.custom_undo_redo_levels){if(e.length>n.custom_undo_redo_levels){for(m=0;m<e.length-1;m++){e[m]=e[m+1]}e.length--;i=e.length}}p.bookmark=h.selection.getBookmark(2,true);if(i<e.length-1){e.length=i+1}e.push(p);i=e.length-1;l.onAdd.dispatch(l,p);h.isNotDirty=0;return p},undo:function(){var n,m;if(l.typing){l.add();l.typing=false}if(i>0){n=e[--i];h.setContent(n.content,{format:"raw"});h.selection.moveToBookmark(n.beforeBookmark);l.onUndo.dispatch(l,n)}return n},redo:function(){var m;if(i<e.length-1){m=e[++i];h.setContent(m.content,{format:"raw"});h.selection.moveToBookmark(m.bookmark);l.onRedo.dispatch(l,m)}return m},clear:function(){e=[];i=0;l.typing=false},hasUndo:function(){return i>0||this.typing},hasRedo:function(){return i<e.length-1&&!this.typing}};return l}})(tinymce);tinymce.ForceBlocks=function(c){var b=c.settings,e=c.dom,a=c.selection,d=c.schema.getBlockElements();function f(){var j=a.getStart(),h=c.getBody(),g,k,o,s,q,i,l,m=-16777215,p,r;if(!j||j.nodeType!==1||!b.forced_root_block){return}while(j&&j!=h){if(d[j.nodeName]){return}j=j.parentNode}g=a.getRng();if(g.setStart){k=g.startContainer;o=g.startOffset;s=g.endContainer;q=g.endOffset}else{if(g.item){j=g.item(0);g=c.getDoc().body.createTextRange();g.moveToElementText(j)}r=g.parentElement().ownerDocument===c.getDoc();tmpRng=g.duplicate();tmpRng.collapse(true);o=tmpRng.move("character",m)*-1;if(!tmpRng.collapsed){tmpRng=g.duplicate();tmpRng.collapse(false);q=(tmpRng.move("character",m)*-1)-o}}j=h.firstChild;while(j){if(j.nodeType===3||(j.nodeType==1&&!d[j.nodeName])){if(j.nodeType===3&&j.nodeValue.length==0){l=j;j=j.nextSibling;e.remove(l);continue}if(!i){i=e.create(b.forced_root_block);j.parentNode.insertBefore(i,j);p=true}l=j;j=j.nextSibling;i.appendChild(l)}else{i=null;j=j.nextSibling}}if(p){if(g.setStart){g.setStart(k,o);g.setEnd(s,q);a.setRng(g)}else{if(r){try{g=c.getDoc().body.createTextRange();g.moveToElementText(h);g.collapse(true);g.moveStart("character",o);if(q>0){g.moveEnd("character",q)}g.select()}catch(n){}}}c.nodeChanged()}}if(b.forced_root_block){c.onKeyUp.add(f);c.onNodeChange.add(f)}};(function(c){var b=c.DOM,a=c.dom.Event,d=c.each,e=c.extend;c.create("tinymce.ControlManager",{ControlManager:function(f,j){var h=this,g;j=j||{};h.editor=f;h.controls={};h.onAdd=new c.util.Dispatcher(h);h.onPostRender=new c.util.Dispatcher(h);h.prefix=j.prefix||f.id+"_";h._cls={};h.onPostRender.add(function(){d(h.controls,function(i){i.postRender()})})},get:function(f){return this.controls[this.prefix+f]||this.controls[f]},setActive:function(h,f){var g=null;if(g=this.get(h)){g.setActive(f)}return g},setDisabled:function(h,f){var g=null;if(g=this.get(h)){g.setDisabled(f)}return g},add:function(g){var f=this;if(g){f.controls[g.id]=g;f.onAdd.dispatch(g,f)}return g},createControl:function(j){var o,k,g,h=this,m=h.editor,n,f;if(!h.controlFactories){h.controlFactories=[];d(m.plugins,function(i){if(i.createControl){h.controlFactories.push(i)}})}n=h.controlFactories;for(k=0,g=n.length;k<g;k++){o=n[k].createControl(j,h);if(o){return h.add(o)}}if(j==="|"||j==="separator"){return h.createSeparator()}if(m.buttons&&(o=m.buttons[j])){return h.createButton(j,o)}return h.add(o)},createDropMenu:function(f,n,h){var m=this,i=m.editor,j,g,k,l;n=e({"class":"mceDropDown",constrain:i.settings.constrain_menus},n);n["class"]=n["class"]+" "+i.getParam("skin")+"Skin";if(k=i.getParam("skin_variant")){n["class"]+=" "+i.getParam("skin")+"Skin"+k.substring(0,1).toUpperCase()+k.substring(1)}n["class"]+=i.settings.directionality=="rtl"?" mceRtl":"";f=m.prefix+f;l=h||m._cls.dropmenu||c.ui.DropMenu;j=m.controls[f]=new l(f,n);j.onAddItem.add(function(r,q){var p=q.settings;p.title=i.getLang(p.title,p.title);if(!p.onclick){p.onclick=function(o){if(p.cmd){i.execCommand(p.cmd,p.ui||false,p.value)}}}});i.onRemove.add(function(){j.destroy()});if(c.isIE){j.onShowMenu.add(function(){i.focus();g=i.selection.getBookmark(1)});j.onHideMenu.add(function(){if(g){i.selection.moveToBookmark(g);g=0}})}return m.add(j)},createListBox:function(f,n,h){var l=this,j=l.editor,i,k,m;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,scope:n.scope,control_manager:l},n);f=l.prefix+f;function g(o){return o.settings.use_accessible_selects&&!c.isGecko}if(j.settings.use_native_selects||g(j)){k=new c.ui.NativeListBox(f,n)}else{m=h||l._cls.listbox||c.ui.ListBox;k=new m(f,n,j)}l.controls[f]=k;if(c.isWebKit){k.onPostRender.add(function(p,o){a.add(o,"mousedown",function(){j.bookmark=j.selection.getBookmark(1)});a.add(o,"focus",function(){j.selection.moveToBookmark(j.bookmark);j.bookmark=null})})}if(k.hideMenu){j.onMouseDown.add(k.hideMenu,k)}return l.add(k)},createButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.label=g.translate(i.label);i.scope=i.scope||g;if(!i.onclick&&!i.menu_button){i.onclick=function(){g.execCommand(i.cmd,i.ui||false,i.value)}}i=e({title:i.title,"class":"mce_"+m,unavailable_prefix:g.getLang("unavailable",""),scope:i.scope,control_manager:h},i);m=h.prefix+m;if(i.menu_button){f=l||h._cls.menubutton||c.ui.MenuButton;k=new f(m,i,g);g.onMouseDown.add(k.hideMenu,k)}else{f=h._cls.button||c.ui.Button;k=new f(m,i,g)}return h.add(k)},createMenuButton:function(h,f,g){f=f||{};f.menu_button=1;return this.createButton(h,f,g)},createSplitButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.scope=i.scope||g;if(!i.onclick){i.onclick=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}if(!i.onselect){i.onselect=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}i=e({title:i.title,"class":"mce_"+m,scope:i.scope,control_manager:h},i);m=h.prefix+m;f=l||h._cls.splitbutton||c.ui.SplitButton;k=h.add(new f(m,i,g));g.onMouseDown.add(k.hideMenu,k);return k},createColorSplitButton:function(f,n,h){var l=this,j=l.editor,i,k,m,g;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onclick){n.onclick=function(o){if(c.isIE){g=j.selection.getBookmark(1)}j.execCommand(n.cmd,n.ui||false,o||n.value)}}if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,menu_class:j.getParam("skin")+"Skin",scope:n.scope,more_colors_title:j.getLang("more_colors")},n);f=l.prefix+f;m=h||l._cls.colorsplitbutton||c.ui.ColorSplitButton;k=new m(f,n,j);j.onMouseDown.add(k.hideMenu,k);j.onRemove.add(function(){k.destroy()});if(c.isIE){k.onShowMenu.add(function(){j.focus();g=j.selection.getBookmark(1)});k.onHideMenu.add(function(){if(g){j.selection.moveToBookmark(g);g=0}})}return l.add(k)},createToolbar:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||g._cls.toolbar||c.ui.Toolbar;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createToolbarGroup:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||this._cls.toolbarGroup||c.ui.ToolbarGroup;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createSeparator:function(g){var f=g||this._cls.separator||c.ui.Separator;return new f()},setControlType:function(g,f){return this._cls[g.toLowerCase()]=f},destroy:function(){d(this.controls,function(f){f.destroy()});this.controls=null}})})(tinymce);(function(d){var a=d.util.Dispatcher,e=d.each,c=d.isIE,b=d.isOpera;d.create("tinymce.WindowManager",{WindowManager:function(f){var g=this;g.editor=f;g.onOpen=new a(g);g.onClose=new a(g);g.params={};g.features={}},open:function(z,h){var v=this,k="",n,m,i=v.editor.settings.dialog_type=="modal",q,o,j,g=d.DOM.getViewPort(),r;z=z||{};h=h||{};o=b?g.w:screen.width;j=b?g.h:screen.height;z.name=z.name||"mc_"+new Date().getTime();z.width=parseInt(z.width||320);z.height=parseInt(z.height||240);z.resizable=true;z.left=z.left||parseInt(o/2)-(z.width/2);z.top=z.top||parseInt(j/2)-(z.height/2);h.inline=false;h.mce_width=z.width;h.mce_height=z.height;h.mce_auto_focus=z.auto_focus;if(i){if(c){z.center=true;z.help=false;z.dialogWidth=z.width+"px";z.dialogHeight=z.height+"px";z.scroll=z.scrollbars||false}}e(z,function(p,f){if(d.is(p,"boolean")){p=p?"yes":"no"}if(!/^(name|url)$/.test(f)){if(c&&i){k+=(k?";":"")+f+":"+p}else{k+=(k?",":"")+f+"="+p}}});v.features=z;v.params=h;v.onOpen.dispatch(v,z,h);r=z.url||z.file;r=d._addVer(r);try{if(c&&i){q=1;window.showModalDialog(r,window,k)}else{q=window.open(r,z.name,k)}}catch(l){}if(!q){alert(v.editor.getLang("popup_blocked"))}},close:function(f){f.close();this.onClose.dispatch(this)},createInstance:function(i,h,g,m,l,k){var j=d.resolve(i);return new j(h,g,m,l,k)},confirm:function(h,f,i,g){g=g||window;f.call(i||this,g.confirm(this._decode(this.editor.getLang(h,h))))},alert:function(h,f,j,g){var i=this;g=g||window;g.alert(i._decode(i.editor.getLang(h,h)));if(f){f.call(j||i)}},resizeBy:function(f,g,h){h.resizeBy(f,g)},_decode:function(f){return d.DOM.decode(f).replace(/\\n/g,"\n")}})}(tinymce));(function(a){a.Formatter=function(aa){var Q={},T=a.each,c=aa.dom,r=aa.selection,t=a.dom.TreeWalker,N=new a.dom.RangeUtils(c),d=aa.schema.isValidChild,A=a.isArray,H=c.isBlock,m=aa.settings.forced_root_block,s=c.nodeIndex,G="\uFEFF",e=/^(src|href|style)$/,X=false,C=true,P,D,x=c.getContentEditable;function I(ab){if(ab.nodeType){ab=ab.nodeName}return !!aa.schema.getTextBlockElements()[ab.toLowerCase()]}function n(ac,ab){return c.getParents(ac,ab,c.getRoot())}function b(ab){return ab.nodeType===1&&ab.id==="_mce_caret"}function j(){l({alignleft:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"left"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"center"},defaultBlock:"div"},{selector:"img",collapsed:false,styles:{display:"block",marginLeft:"auto",marginRight:"auto"}},{selector:"table",collapsed:false,styles:{marginLeft:"auto",marginRight:"auto"}}],alignright:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"right"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"right"}}],alignfull:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"justify"},defaultBlock:"div"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:true},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:true},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},wrap_links:false},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},wrap_links:false},fontname:{inline:"span",styles:{fontFamily:"%value"}},fontsize:{inline:"span",styles:{fontSize:"%value"}},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},link:{inline:"a",selector:"a",remove:"all",split:true,deep:true,onmatch:function(ab){return true},onformat:function(ad,ab,ac){T(ac,function(af,ae){c.setAttrib(ad,ae,af)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike",remove:"all",split:true,expand:false,block_expand:true,deep:true},{selector:"span",attributes:["style","class"],remove:"empty",split:true,expand:false,deep:true},{selector:"*",attributes:["style","class"],split:false,expand:false,deep:true}]});T("p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp".split(/\s/),function(ab){l(ab,{block:ab,remove:"all"})});l(aa.settings.formats)}function W(){aa.addShortcut("ctrl+b","bold_desc","Bold");aa.addShortcut("ctrl+i","italic_desc","Italic");aa.addShortcut("ctrl+u","underline_desc","Underline");for(var ab=1;ab<=6;ab++){aa.addShortcut("ctrl+"+ab,"",["FormatBlock",false,"h"+ab])}aa.addShortcut("ctrl+7","",["FormatBlock",false,"p"]);aa.addShortcut("ctrl+8","",["FormatBlock",false,"div"]);aa.addShortcut("ctrl+9","",["FormatBlock",false,"address"])}function V(ab){return ab?Q[ab]:Q}function l(ab,ac){if(ab){if(typeof(ab)!=="string"){T(ab,function(ae,ad){l(ad,ae)})}else{ac=ac.length?ac:[ac];T(ac,function(ad){if(ad.deep===D){ad.deep=!ad.selector}if(ad.split===D){ad.split=!ad.selector||ad.inline}if(ad.remove===D&&ad.selector&&!ad.inline){ad.remove="none"}if(ad.selector&&ad.inline){ad.mixed=true;ad.block_expand=true}if(typeof(ad.classes)==="string"){ad.classes=ad.classes.split(/\s+/)}});Q[ab]=ac}}}var i=function(ac){var ab;aa.dom.getParent(ac,function(ad){ab=aa.dom.getStyle(ad,"text-decoration");return ab&&ab!=="none"});return ab};var L=function(ab){var ac;if(ab.nodeType===1&&ab.parentNode&&ab.parentNode.nodeType===1){ac=i(ab.parentNode);if(aa.dom.getStyle(ab,"color")&&ac){aa.dom.setStyle(ab,"text-decoration",ac)}else{if(aa.dom.getStyle(ab,"textdecoration")===ac){aa.dom.setStyle(ab,"text-decoration",null)}}}};function Y(ae,al,ag){var ah=V(ae),am=ah[0],ak,ac,aj,ai=r.isCollapsed();function ab(aq,ap){ap=ap||am;if(aq){if(ap.onformat){ap.onformat(aq,ap,al,ag)}T(ap.styles,function(at,ar){c.setStyle(aq,ar,q(at,al))});T(ap.attributes,function(at,ar){c.setAttrib(aq,ar,q(at,al))});T(ap.classes,function(ar){ar=q(ar,al);if(!c.hasClass(aq,ar)){c.addClass(aq,ar)}})}}function af(){function ar(ay,aw){var ax=new t(aw);for(ag=ax.current();ag;ag=ax.prev()){if(ag.childNodes.length>1||ag==ay||ag.tagName=="BR"){return ag}}}var aq=aa.selection.getRng();var av=aq.startContainer;var ap=aq.endContainer;if(av!=ap&&aq.endOffset===0){var au=ar(av,ap);var at=au.nodeType==3?au.length:au.childNodes.length;aq.setEnd(au,at)}return aq}function ad(at,ay,aw,av,aq){var ap=[],ar=-1,ax,aA=-1,au=-1,az;T(at.childNodes,function(aC,aB){if(aC.nodeName==="UL"||aC.nodeName==="OL"){ar=aB;ax=aC;return false}});T(at.childNodes,function(aC,aB){if(aC.nodeName==="SPAN"&&c.getAttrib(aC,"data-mce-type")=="bookmark"){if(aC.id==ay.id+"_start"){aA=aB}else{if(aC.id==ay.id+"_end"){au=aB}}}});if(ar<=0||(aA<ar&&au>ar)){T(a.grep(at.childNodes),aq);return 0}else{az=c.clone(aw,X);T(a.grep(at.childNodes),function(aC,aB){if((aA<ar&&aB<ar)||(aA>ar&&aB>ar)){ap.push(aC);aC.parentNode.removeChild(aC)}});if(aA<ar){at.insertBefore(az,ax)}else{if(aA>ar){at.insertBefore(az,ax.nextSibling)}}av.push(az);T(ap,function(aB){az.appendChild(aB)});return az}}function an(aq,at,aw){var ap=[],av,ar,au=true;av=am.inline||am.block;ar=c.create(av);ab(ar);N.walk(aq,function(ax){var ay;function az(aA){var aF,aD,aB,aC,aE;aE=au;aF=aA.nodeName.toLowerCase();aD=aA.parentNode.nodeName.toLowerCase();if(aA.nodeType===1&&x(aA)){aE=au;au=x(aA)==="true";aC=true}if(g(aF,"br")){ay=0;if(am.block){c.remove(aA)}return}if(am.wrapper&&y(aA,ae,al)){ay=0;return}if(au&&!aC&&am.block&&!am.wrapper&&I(aF)){aA=c.rename(aA,av);ab(aA);ap.push(aA);ay=0;return}if(am.selector){T(ah,function(aG){if("collapsed" in aG&&aG.collapsed!==ai){return}if(c.is(aA,aG.selector)&&!b(aA)){ab(aA,aG);aB=true}});if(!am.inline||aB){ay=0;return}}if(au&&!aC&&d(av,aF)&&d(aD,av)&&!(!aw&&aA.nodeType===3&&aA.nodeValue.length===1&&aA.nodeValue.charCodeAt(0)===65279)&&!b(aA)&&(!am.inline||!H(aA))){if(!ay){ay=c.clone(ar,X);aA.parentNode.insertBefore(ay,aA);ap.push(ay)}ay.appendChild(aA)}else{if(aF=="li"&&at){ay=ad(aA,at,ar,ap,az)}else{ay=0;T(a.grep(aA.childNodes),az);if(aC){au=aE}ay=0}}}T(ax,az)});if(am.wrap_links===false){T(ap,function(ax){function ay(aC){var aB,aA,az;if(aC.nodeName==="A"){aA=c.clone(ar,X);ap.push(aA);az=a.grep(aC.childNodes);for(aB=0;aB<az.length;aB++){aA.appendChild(az[aB])}aC.appendChild(aA)}T(a.grep(aC.childNodes),ay)}ay(ax)})}T(ap,function(az){var ax;function aA(aC){var aB=0;T(aC.childNodes,function(aD){if(!f(aD)&&!K(aD)){aB++}});return aB}function ay(aB){var aD,aC;T(aB.childNodes,function(aE){if(aE.nodeType==1&&!K(aE)&&!b(aE)){aD=aE;return X}});if(aD&&h(aD,am)){aC=c.clone(aD,X);ab(aC);c.replace(aC,aB,C);c.remove(aD,1)}return aC||aB}ax=aA(az);if((ap.length>1||!H(az))&&ax===0){c.remove(az,1);return}if(am.inline||am.wrapper){if(!am.exact&&ax===1){az=ay(az)}T(ah,function(aB){T(c.select(aB.inline,az),function(aD){var aC;if(aB.wrap_links===false){aC=aD.parentNode;do{if(aC.nodeName==="A"){return}}while(aC=aC.parentNode)}Z(aB,al,aD,aB.exact?aD:null)})});if(y(az.parentNode,ae,al)){c.remove(az,1);az=0;return C}if(am.merge_with_parents){c.getParent(az.parentNode,function(aB){if(y(aB,ae,al)){c.remove(az,1);az=0;return C}})}if(az&&am.merge_siblings!==false){az=u(E(az),az);az=u(az,E(az,C))}}})}if(am){if(ag){if(ag.nodeType){ac=c.createRng();ac.setStartBefore(ag);ac.setEndAfter(ag);an(p(ac,ah),null,true)}else{an(ag,null,true)}}else{if(!ai||!am.inline||c.select("td.mceSelected,th.mceSelected").length){var ao=aa.selection.getNode();if(!m&&ah[0].defaultBlock&&!c.getParent(ao,c.isBlock)){Y(ah[0].defaultBlock)}aa.selection.setRng(af());ak=r.getBookmark();an(p(r.getRng(C),ah),ak);if(am.styles&&(am.styles.color||am.styles.textDecoration)){a.walk(ao,L,"childNodes");L(ao)}r.moveToBookmark(ak);R(r.getRng(C));aa.nodeChanged()}else{U("apply",ae,al)}}}}function B(ad,am,af){var ag=V(ad),ao=ag[0],ak,aj,ac,al=true;function ae(av){var au,at,ar,aq,ax,aw;if(av.nodeType===3){return}if(av.nodeType===1&&x(av)){ax=al;al=x(av)==="true";aw=true}au=a.grep(av.childNodes);if(al&&!aw){for(at=0,ar=ag.length;at<ar;at++){if(Z(ag[at],am,av,av)){break}}}if(ao.deep){if(au.length){for(at=0,ar=au.length;at<ar;at++){ae(au[at])}if(aw){al=ax}}}}function ah(aq){var ar;T(n(aq.parentNode).reverse(),function(at){var au;if(!ar&&at.id!="_start"&&at.id!="_end"){au=y(at,ad,am);if(au&&au.split!==false){ar=at}}});return ar}function ab(au,aq,aw,az){var aA,ay,ax,at,av,ar;if(au){ar=au.parentNode;for(aA=aq.parentNode;aA&&aA!=ar;aA=aA.parentNode){ay=c.clone(aA,X);for(av=0;av<ag.length;av++){if(Z(ag[av],am,ay,ay)){ay=0;break}}if(ay){if(ax){ay.appendChild(ax)}if(!at){at=ay}ax=ay}}if(az&&(!ao.mixed||!H(au))){aq=c.split(au,aq)}if(ax){aw.parentNode.insertBefore(ax,aw);at.appendChild(aw)}}return aq}function an(aq){return ab(ah(aq),aq,aq,true)}function ai(at){var ar=c.get(at?"_start":"_end"),aq=ar[at?"firstChild":"lastChild"];if(K(aq)){aq=aq[at?"firstChild":"lastChild"]}c.remove(ar,true);return aq}function ap(aq){var at,au,ar;aq=p(aq,ag,C);if(ao.split){at=M(aq,C);au=M(aq);if(at!=au){if(/^(TR|TD)$/.test(at.nodeName)&&at.firstChild){at=(at.nodeName=="TD"?at.firstChild:at.firstChild.firstChild)||at}at=S(at,"span",{id:"_start","data-mce-type":"bookmark"});au=S(au,"span",{id:"_end","data-mce-type":"bookmark"});an(at);an(au);at=ai(C);au=ai()}else{at=au=an(at)}aq.startContainer=at.parentNode;aq.startOffset=s(at);aq.endContainer=au.parentNode;aq.endOffset=s(au)+1}N.walk(aq,function(av){T(av,function(aw){ae(aw);if(aw.nodeType===1&&aa.dom.getStyle(aw,"text-decoration")==="underline"&&aw.parentNode&&i(aw.parentNode)==="underline"){Z({deep:false,exact:true,inline:"span",styles:{textDecoration:"underline"}},null,aw)}})})}if(af){if(af.nodeType){ac=c.createRng();ac.setStartBefore(af);ac.setEndAfter(af);ap(ac)}else{ap(af)}return}if(!r.isCollapsed()||!ao.inline||c.select("td.mceSelected,th.mceSelected").length){ak=r.getBookmark();ap(r.getRng(C));r.moveToBookmark(ak);if(ao.inline&&k(ad,am,r.getStart())){R(r.getRng(true))}aa.nodeChanged()}else{U("remove",ad,am)}}function F(ac,ae,ad){var ab=V(ac);if(k(ac,ae,ad)&&(!("toggle" in ab[0])||ab[0].toggle)){B(ac,ae,ad)}else{Y(ac,ae,ad)}}function y(ac,ab,ah,af){var ad=V(ab),ai,ag,ae;function aj(an,ap,aq){var am,ao,ak=ap[aq],al;if(ap.onmatch){return ap.onmatch(an,ap,aq)}if(ak){if(ak.length===D){for(am in ak){if(ak.hasOwnProperty(am)){if(aq==="attributes"){ao=c.getAttrib(an,am)}else{ao=O(an,am)}if(af&&!ao&&!ap.exact){return}if((!af||ap.exact)&&!g(ao,q(ak[am],ah))){return}}}}else{for(al=0;al<ak.length;al++){if(aq==="attributes"?c.getAttrib(an,ak[al]):O(an,ak[al])){return ap}}}}return ap}if(ad&&ac){for(ag=0;ag<ad.length;ag++){ai=ad[ag];if(h(ac,ai)&&aj(ac,ai,"attributes")&&aj(ac,ai,"styles")){if(ae=ai.classes){for(ag=0;ag<ae.length;ag++){if(!c.hasClass(ac,ae[ag])){return}}}return ai}}}}function k(ad,af,ae){var ac;function ab(ag){ag=c.getParent(ag,function(ah){return !!y(ah,ad,af,true)});return y(ag,ad,af)}if(ae){return ab(ae)}ae=r.getNode();if(ab(ae)){return C}ac=r.getStart();if(ac!=ae){if(ab(ac)){return C}}return X}function v(ai,ah){var af,ag=[],ae={},ad,ac,ab;af=r.getStart();c.getParent(af,function(al){var ak,aj;for(ak=0;ak<ai.length;ak++){aj=ai[ak];if(!ae[aj]&&y(al,aj,ah)){ae[aj]=true;ag.push(aj)}}},c.getRoot());return ag}function z(af){var ah=V(af),ae,ad,ag,ac,ab;if(ah){ae=r.getStart();ad=n(ae);for(ac=ah.length-1;ac>=0;ac--){ab=ah[ac].selector;if(!ab){return C}for(ag=ad.length-1;ag>=0;ag--){if(c.is(ad[ag],ab)){return C}}}}return X}function J(ab,ae,ac){var ad;if(!P){P={};ad={};aa.onNodeChange.addToTop(function(ag,af,ai){var ah=n(ai),aj={};T(P,function(ak,al){T(ah,function(am){if(y(am,al,{},ak.similar)){if(!ad[al]){T(ak,function(an){an(true,{node:am,format:al,parents:ah})});ad[al]=ak}aj[al]=ak;return false}})});T(ad,function(ak,al){if(!aj[al]){delete ad[al];T(ak,function(am){am(false,{node:ai,format:al,parents:ah})})}})})}T(ab.split(","),function(af){if(!P[af]){P[af]=[];P[af].similar=ac}P[af].push(ae)});return this}a.extend(this,{get:V,register:l,apply:Y,remove:B,toggle:F,match:k,matchAll:v,matchNode:y,canApply:z,formatChanged:J});j();W();function h(ab,ac){if(g(ab,ac.inline)){return C}if(g(ab,ac.block)){return C}if(ac.selector){return c.is(ab,ac.selector)}}function g(ac,ab){ac=ac||"";ab=ab||"";ac=""+(ac.nodeName||ac);ab=""+(ab.nodeName||ab);return ac.toLowerCase()==ab.toLowerCase()}function O(ac,ab){var ad=c.getStyle(ac,ab);if(ab=="color"||ab=="backgroundColor"){ad=c.toHex(ad)}if(ab=="fontWeight"&&ad==700){ad="bold"}return""+ad}function q(ab,ac){if(typeof(ab)!="string"){ab=ab(ac)}else{if(ac){ab=ab.replace(/%(\w+)/g,function(ae,ad){return ac[ad]||ae})}}return ab}function f(ab){return ab&&ab.nodeType===3&&/^([\t \r\n]+|)$/.test(ab.nodeValue)}function S(ad,ac,ab){var ae=c.create(ac,ab);ad.parentNode.insertBefore(ae,ad);ae.appendChild(ad);return ae}function p(ab,am,ae){var ap,an,ah,al,ad=ab.startContainer,ai=ab.startOffset,ar=ab.endContainer,ak=ab.endOffset;function ao(aA){var au,ax,az,aw,av,at;au=ax=aA?ad:ar;av=aA?"previousSibling":"nextSibling";at=c.getRoot();function ay(aB){return aB.nodeName=="BR"&&aB.getAttribute("data-mce-bogus")&&!aB.nextSibling}if(au.nodeType==3&&!f(au)){if(aA?ai>0:ak<au.nodeValue.length){return au}}for(;;){if(!am[0].block_expand&&H(ax)){return ax}for(aw=ax[av];aw;aw=aw[av]){if(!K(aw)&&!f(aw)&&!ay(aw)){return ax}}if(ax.parentNode==at){au=ax;break}ax=ax.parentNode}return au}function ag(at,au){if(au===D){au=at.nodeType===3?at.length:at.childNodes.length}while(at&&at.hasChildNodes()){at=at.childNodes[au];if(at){au=at.nodeType===3?at.length:at.childNodes.length}}return{node:at,offset:au}}if(ad.nodeType==1&&ad.hasChildNodes()){an=ad.childNodes.length-1;ad=ad.childNodes[ai>an?an:ai];if(ad.nodeType==3){ai=0}}if(ar.nodeType==1&&ar.hasChildNodes()){an=ar.childNodes.length-1;ar=ar.childNodes[ak>an?an:ak-1];if(ar.nodeType==3){ak=ar.nodeValue.length}}function aq(au){var at=au;while(at){if(at.nodeType===1&&x(at)){return x(at)==="false"?at:au}at=at.parentNode}return au}function aj(au,ay,aA){var ax,av,az,at;function aw(aC,aE){var aF,aB,aD=aC.nodeValue;if(typeof(aE)=="undefined"){aE=aA?aD.length:0}if(aA){aF=aD.lastIndexOf(" ",aE);aB=aD.lastIndexOf("\u00a0",aE);aF=aF>aB?aF:aB;if(aF!==-1&&!ae){aF++}}else{aF=aD.indexOf(" ",aE);aB=aD.indexOf("\u00a0",aE);aF=aF!==-1&&(aB===-1||aF<aB)?aF:aB}return aF}if(au.nodeType===3){az=aw(au,ay);if(az!==-1){return{container:au,offset:az}}at=au}ax=new t(au,c.getParent(au,H)||aa.getBody());while(av=ax[aA?"prev":"next"]()){if(av.nodeType===3){at=av;az=aw(av);if(az!==-1){return{container:av,offset:az}}}else{if(H(av)){break}}}if(at){if(aA){ay=0}else{ay=at.length}return{container:at,offset:ay}}}function af(au,at){var av,aw,ay,ax;if(au.nodeType==3&&au.nodeValue.length===0&&au[at]){au=au[at]}av=n(au);for(aw=0;aw<av.length;aw++){for(ay=0;ay<am.length;ay++){ax=am[ay];if("collapsed" in ax&&ax.collapsed!==ab.collapsed){continue}if(c.is(av[aw],ax.selector)){return av[aw]}}}return au}function ac(au,at,aw){var av;if(!am[0].wrapper){av=c.getParent(au,am[0].block)}if(!av){av=c.getParent(au.nodeType==3?au.parentNode:au,I)}if(av&&am[0].wrapper){av=n(av,"ul,ol").reverse()[0]||av}if(!av){av=au;while(av[at]&&!H(av[at])){av=av[at];if(g(av,"br")){break}}}return av||au}ad=aq(ad);ar=aq(ar);if(K(ad.parentNode)||K(ad)){ad=K(ad)?ad:ad.parentNode;ad=ad.nextSibling||ad;if(ad.nodeType==3){ai=0}}if(K(ar.parentNode)||K(ar)){ar=K(ar)?ar:ar.parentNode;ar=ar.previousSibling||ar;if(ar.nodeType==3){ak=ar.length}}if(am[0].inline){if(ab.collapsed){al=aj(ad,ai,true);if(al){ad=al.container;ai=al.offset}al=aj(ar,ak);if(al){ar=al.container;ak=al.offset}}ah=ag(ar,ak);if(ah.node){while(ah.node&&ah.offset===0&&ah.node.previousSibling){ah=ag(ah.node.previousSibling)}if(ah.node&&ah.offset>0&&ah.node.nodeType===3&&ah.node.nodeValue.charAt(ah.offset-1)===" "){if(ah.offset>1){ar=ah.node;ar.splitText(ah.offset-1)}}}}if(am[0].inline||am[0].block_expand){if(!am[0].inline||(ad.nodeType!=3||ai===0)){ad=ao(true)}if(!am[0].inline||(ar.nodeType!=3||ak===ar.nodeValue.length)){ar=ao()}}if(am[0].selector&&am[0].expand!==X&&!am[0].inline){ad=af(ad,"previousSibling");ar=af(ar,"nextSibling")}if(am[0].block||am[0].selector){ad=ac(ad,"previousSibling");ar=ac(ar,"nextSibling");if(am[0].block){if(!H(ad)){ad=ao(true)}if(!H(ar)){ar=ao()}}}if(ad.nodeType==1){ai=s(ad);ad=ad.parentNode}if(ar.nodeType==1){ak=s(ar)+1;ar=ar.parentNode}return{startContainer:ad,startOffset:ai,endContainer:ar,endOffset:ak}}function Z(ah,ag,ae,ab){var ad,ac,af;if(!h(ae,ah)){return X}if(ah.remove!="all"){T(ah.styles,function(aj,ai){aj=q(aj,ag);if(typeof(ai)==="number"){ai=aj;ab=0}if(!ab||g(O(ab,ai),aj)){c.setStyle(ae,ai,"")}af=1});if(af&&c.getAttrib(ae,"style")==""){ae.removeAttribute("style");ae.removeAttribute("data-mce-style")}T(ah.attributes,function(ak,ai){var aj;ak=q(ak,ag);if(typeof(ai)==="number"){ai=ak;ab=0}if(!ab||g(c.getAttrib(ab,ai),ak)){if(ai=="class"){ak=c.getAttrib(ae,ai);if(ak){aj="";T(ak.split(/\s+/),function(al){if(/mce\w+/.test(al)){aj+=(aj?" ":"")+al}});if(aj){c.setAttrib(ae,ai,aj);return}}}if(ai=="class"){ae.removeAttribute("className")}if(e.test(ai)){ae.removeAttribute("data-mce-"+ai)}ae.removeAttribute(ai)}});T(ah.classes,function(ai){ai=q(ai,ag);if(!ab||c.hasClass(ab,ai)){c.removeClass(ae,ai)}});ac=c.getAttribs(ae);for(ad=0;ad<ac.length;ad++){if(ac[ad].nodeName.indexOf("_")!==0){return X}}}if(ah.remove!="none"){o(ae,ah);return C}}function o(ad,ae){var ab=ad.parentNode,ac;function af(ah,ag,ai){ah=E(ah,ag,ai);return !ah||(ah.nodeName=="BR"||H(ah))}if(ae.block){if(!m){if(H(ad)&&!H(ab)){if(!af(ad,X)&&!af(ad.firstChild,C,1)){ad.insertBefore(c.create("br"),ad.firstChild)}if(!af(ad,C)&&!af(ad.lastChild,X,1)){ad.appendChild(c.create("br"))}}}else{if(ab==c.getRoot()){if(!ae.list_block||!g(ad,ae.list_block)){T(a.grep(ad.childNodes),function(ag){if(d(m,ag.nodeName.toLowerCase())){if(!ac){ac=S(ag,m)}else{ac.appendChild(ag)}}else{ac=0}})}}}}if(ae.selector&&ae.inline&&!g(ae.inline,ad)){return}c.remove(ad,1)}function E(ac,ab,ad){if(ac){ab=ab?"nextSibling":"previousSibling";for(ac=ad?ac:ac[ab];ac;ac=ac[ab]){if(ac.nodeType==1||!f(ac)){return ac}}}}function K(ab){return ab&&ab.nodeType==1&&ab.getAttribute("data-mce-type")=="bookmark"}function u(af,ae){var ab,ad,ac;function ah(ak,aj){if(ak.nodeName!=aj.nodeName){return X}function ai(am){var an={};T(c.getAttribs(am),function(ao){var ap=ao.nodeName.toLowerCase();if(ap.indexOf("_")!==0&&ap!=="style"){an[ap]=c.getAttrib(am,ap)}});return an}function al(ap,ao){var an,am;for(am in ap){if(ap.hasOwnProperty(am)){an=ao[am];if(an===D){return X}if(ap[am]!=an){return X}delete ao[am]}}for(am in ao){if(ao.hasOwnProperty(am)){return X}}return C}if(!al(ai(ak),ai(aj))){return X}if(!al(c.parseStyle(c.getAttrib(ak,"style")),c.parseStyle(c.getAttrib(aj,"style")))){return X}return C}function ag(aj,ai){for(ad=aj;ad;ad=ad[ai]){if(ad.nodeType==3&&ad.nodeValue.length!==0){return aj}if(ad.nodeType==1&&!K(ad)){return ad}}return aj}if(af&&ae){af=ag(af,"previousSibling");ae=ag(ae,"nextSibling");if(ah(af,ae)){for(ad=af.nextSibling;ad&&ad!=ae;){ac=ad;ad=ad.nextSibling;af.appendChild(ac)}c.remove(ae);T(a.grep(ae.childNodes),function(ai){af.appendChild(ai)});return af}}return ae}function M(ac,ag){var ab,af,ad,ae;ab=ac[ag?"startContainer":"endContainer"];af=ac[ag?"startOffset":"endOffset"];if(ab.nodeType==1){ad=ab.childNodes.length-1;if(!ag&&af){af--}ab=ab.childNodes[af>ad?ad:af]}if(ab.nodeType===3&&ag&&af>=ab.nodeValue.length){ab=new t(ab,aa.getBody()).next()||ab}if(ab.nodeType===3&&!ag&&af===0){ab=new t(ab,aa.getBody()).prev()||ab}return ab}function U(ak,ab,ai){var al="_mce_caret",ac=aa.settings.caret_debug;function ad(ap){var ao=c.create("span",{id:al,"data-mce-bogus":true,style:ac?"color:red":""});if(ap){ao.appendChild(aa.getDoc().createTextNode(G))}return ao}function aj(ap,ao){while(ap){if((ap.nodeType===3&&ap.nodeValue!==G)||ap.childNodes.length>1){return false}if(ao&&ap.nodeType===1){ao.push(ap)}ap=ap.firstChild}return true}function ag(ao){while(ao){if(ao.id===al){return ao}ao=ao.parentNode}}function af(ao){var ap;if(ao){ap=new t(ao,ao);for(ao=ap.current();ao;ao=ap.next()){if(ao.nodeType===3){return ao}}}}function ae(aq,ap){var ar,ao;if(!aq){aq=ag(r.getStart());if(!aq){while(aq=c.get(al)){ae(aq,false)}}}else{ao=r.getRng(true);if(aj(aq)){if(ap!==false){ao.setStartBefore(aq);ao.setEndBefore(aq)}c.remove(aq)}else{ar=af(aq);if(ar.nodeValue.charAt(0)===G){ar=ar.deleteData(0,1)}c.remove(aq,1)}r.setRng(ao)}}function ah(){var aq,ao,av,au,ar,ap,at;aq=r.getRng(true);au=aq.startOffset;ap=aq.startContainer;at=ap.nodeValue;ao=ag(r.getStart());if(ao){av=af(ao)}if(at&&au>0&&au<at.length&&/\w/.test(at.charAt(au))&&/\w/.test(at.charAt(au-1))){ar=r.getBookmark();aq.collapse(true);aq=p(aq,V(ab));aq=N.split(aq);Y(ab,ai,aq);r.moveToBookmark(ar)}else{if(!ao||av.nodeValue!==G){ao=ad(true);av=ao.firstChild;aq.insertNode(ao);au=1;Y(ab,ai,ao)}else{Y(ab,ai,ao)}r.setCursorLocation(av,au)}}function am(){var ao=r.getRng(true),ap,at,aw,av,aq,az,ay=[],au,ax;ap=ao.startContainer;at=ao.startOffset;aq=ap;if(ap.nodeType==3){if(at!=ap.nodeValue.length||ap.nodeValue===G){av=true}aq=aq.parentNode}while(aq){if(y(aq,ab,ai)){az=aq;break}if(aq.nextSibling){av=true}ay.push(aq);aq=aq.parentNode}if(!az){return}if(av){aw=r.getBookmark();ao.collapse(true);ao=p(ao,V(ab),true);ao=N.split(ao);B(ab,ai,ao);r.moveToBookmark(aw)}else{ax=ad();aq=ax;for(au=ay.length-1;au>=0;au--){aq.appendChild(c.clone(ay[au],false));aq=aq.firstChild}aq.appendChild(c.doc.createTextNode(G));aq=aq.firstChild;var ar=c.getParent(az,I);if(ar&&c.isEmpty(ar)){az.parentNode.replaceChild(ax,az)}else{c.insertAfter(ax,az)}r.setCursorLocation(aq,1);if(c.isEmpty(az)){c.remove(az)}}}function an(){var ap,ao,aq;ao=ag(r.getStart());if(ao&&!c.isEmpty(ao)){a.walk(ao,function(ar){if(ar.nodeType==1&&ar.id!==al&&!c.isEmpty(ar)){c.setAttrib(ar,"data-mce-bogus",null)}},"childNodes")}}if(!self._hasCaretEvents){aa.onBeforeGetContent.addToTop(function(){var ao=[],ap;if(aj(ag(r.getStart()),ao)){ap=ao.length;while(ap--){c.setAttrib(ao[ap],"data-mce-bogus","1")}}});a.each("onMouseUp onKeyUp".split(" "),function(ao){aa[ao].addToTop(function(){ae();an()})});aa.onKeyDown.addToTop(function(ao,aq){var ap=aq.keyCode;if(ap==8||ap==37||ap==39){ae(ag(r.getStart()))}an()});r.onSetContent.add(an);self._hasCaretEvents=true}if(ak=="apply"){ah()}else{am()}}function R(ac){var ab=ac.startContainer,ai=ac.startOffset,ae,ah,ag,ad,af;if(ab.nodeType==3&&ai>=ab.nodeValue.length){ai=s(ab);ab=ab.parentNode;ae=true}if(ab.nodeType==1){ad=ab.childNodes;ab=ad[Math.min(ai,ad.length-1)];ah=new t(ab,c.getParent(ab,c.isBlock));if(ai>ad.length-1||ae){ah.next()}for(ag=ah.current();ag;ag=ah.next()){if(ag.nodeType==3&&!f(ag)){af=c.create("a",null,G);ag.parentNode.insertBefore(af,ag);ac.setStart(ag,0);r.setRng(ac);c.remove(af);return}}}}}})(tinymce);tinymce.onAddEditor.add(function(e,a){var d,h,g,c=a.settings;function b(j,i){e.each(i,function(l,k){if(l){g.setStyle(j,k,l)}});g.rename(j,"span")}function f(i,j){g=i.dom;if(c.convert_fonts_to_spans){e.each(g.select("font,u,strike",j.node),function(k){d[k.nodeName.toLowerCase()](a.dom,k)})}}if(c.inline_styles){h=e.explode(c.font_size_legacy_values);d={font:function(j,i){b(i,{backgroundColor:i.style.backgroundColor,color:i.color,fontFamily:i.face,fontSize:h[parseInt(i.size,10)-1]})},u:function(j,i){b(i,{textDecoration:"underline"})},strike:function(j,i){b(i,{textDecoration:"line-through"})}};a.onPreProcess.add(f);a.onSetContent.add(f);a.onInit.add(function(){a.selection.onSetContent.add(f)})}});(function(b){var a=b.dom.TreeWalker;b.EnterKey=function(f){var i=f.dom,e=f.selection,d=f.settings,h=f.undoManager,c=f.schema.getNonEmptyElements();function g(B){var v=e.getRng(true),G,j,A,u,p,M,C,o,k,n,t,J,x,D;function E(N){return N&&i.isBlock(N)&&!/^(TD|TH|CAPTION|FORM)$/.test(N.nodeName)&&!/^(fixed|absolute)/i.test(N.style.position)&&i.getContentEditable(N)!=="true"}function F(O){var N;if(b.isIE&&!b.isIE11&&i.isBlock(O)){N=e.getRng();O.appendChild(i.create("span",null,"\u00a0"));e.select(O);O.lastChild.outerHTML="";e.setRng(N)}}function z(P){var O=P,Q=[],N;while(O=O.firstChild){if(i.isBlock(O)){return}if(O.nodeType==1&&!c[O.nodeName.toLowerCase()]){Q.push(O)}}N=Q.length;while(N--){O=Q[N];if(!O.hasChildNodes()||(O.firstChild==O.lastChild&&O.firstChild.nodeValue==="")){i.remove(O)}else{if(O.nodeName=="A"&&(O.innerText||O.textContent)===" "){i.remove(O)}}}}function m(O){var T,R,N,U,S,Q=O,P;N=i.createRng();if(O.hasChildNodes()){T=new a(O,O);while(R=T.current()){if(R.nodeType==3){N.setStart(R,0);N.setEnd(R,0);break}if(c[R.nodeName.toLowerCase()]){N.setStartBefore(R);N.setEndBefore(R);break}Q=R;R=T.next()}if(!R){N.setStart(Q,0);N.setEnd(Q,0)}}else{if(O.nodeName=="BR"){if(O.nextSibling&&i.isBlock(O.nextSibling)){if(!M||M<9){P=i.create("br");O.parentNode.insertBefore(P,O)}N.setStartBefore(O);N.setEndBefore(O)}else{N.setStartAfter(O);N.setEndAfter(O)}}else{N.setStart(O,0);N.setEnd(O,0)}}e.setRng(N);i.remove(P);S=i.getViewPort(f.getWin());U=i.getPos(O).y;if(U<S.y||U+25>S.y+S.h){f.getWin().scrollTo(0,U<S.y?U:U-S.h+25)}}function r(O){var P=A,R,Q,N;R=O||t=="TABLE"?i.create(O||x):p.cloneNode(false);N=R;if(d.keep_styles!==false){do{if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(P.nodeName)){if(P.id=="_mce_caret"){continue}Q=P.cloneNode(false);i.setAttrib(Q,"id","");if(R.hasChildNodes()){Q.appendChild(R.firstChild);R.appendChild(Q)}else{N=Q;R.appendChild(Q)}}}while(P=P.parentNode)}if(!b.isIE||b.isIE11){N.innerHTML='<br data-mce-bogus="1">'}return R}function q(Q){var P,O,N;if(A.nodeType==3&&(Q?u>0:u<A.nodeValue.length)){return false}if(A.parentNode==p&&D&&!Q){return true}if(Q&&A.nodeType==1&&A==p.firstChild){return true}if(A.nodeName==="TABLE"||(A.previousSibling&&A.previousSibling.nodeName=="TABLE")){return(D&&!Q)||(!D&&Q)}P=new a(A,p);if(A.nodeType==3){if(Q&&u==0){P.prev()}else{if(!Q&&u==A.nodeValue.length){P.next()}}}while(O=P.current()){if(O.nodeType===1){if(!O.getAttribute("data-mce-bogus")){N=O.nodeName.toLowerCase();if(c[N]&&N!=="br"){return false}}}else{if(O.nodeType===3&&!/^[ \t\r\n]*$/.test(O.nodeValue)){return false}}if(Q){P.prev()}else{P.next()}}return true}function l(N,T){var U,S,P,R,Q,O=x||"P";S=i.getParent(N,i.isBlock);if(!S||!E(S)){S=S||j;if(!S.hasChildNodes()){U=i.create(O);S.appendChild(U);v.setStart(U,0);v.setEnd(U,0);return U}R=N;while(R.parentNode!=S){R=R.parentNode}while(R&&!i.isBlock(R)){P=R;R=R.previousSibling}if(P){U=i.create(O);P.parentNode.insertBefore(U,P);R=P;while(R&&!i.isBlock(R)){Q=R.nextSibling;U.appendChild(R);R=Q}v.setStart(N,T);v.setEnd(N,T)}}return N}function H(){function N(P){var O=n[P?"firstChild":"lastChild"];while(O){if(O.nodeType==1){break}O=O[P?"nextSibling":"previousSibling"]}return O===p}o=x?r(x):i.create("BR");if(N(true)&&N()){i.replace(o,n)}else{if(N(true)){n.parentNode.insertBefore(o,n)}else{if(N()){i.insertAfter(o,n);F(o)}else{G=v.cloneRange();G.setStartAfter(p);G.setEndAfter(n);k=G.extractContents();i.insertAfter(k,n);i.insertAfter(o,n)}}}i.remove(p);m(o);h.add()}function y(){var O=new a(A,p),N;while(N=O.next()){if(c[N.nodeName.toLowerCase()]||N.length>0){return true}}}function L(){var P,O,N;if(A&&A.nodeType==3&&u>=A.nodeValue.length){if((!b.isIE||b.isIE11)&&!y()){P=i.create("br");v.insertNode(P);v.setStartAfter(P);v.setEndAfter(P);O=true}}P=i.create("br");v.insertNode(P);if((b.isIE&&!b.isIE11)&&t=="PRE"&&(!M||M<8)){P.parentNode.insertBefore(i.doc.createTextNode("\r"),P)}N=i.create("span",{}," ");P.parentNode.insertBefore(N,P);e.scrollIntoView(N);i.remove(N);if(!O){v.setStartAfter(P);v.setEndAfter(P)}else{v.setStartBefore(P);v.setEndBefore(P)}e.setRng(v);h.add()}function s(N){do{if(N.nodeType===3){N.nodeValue=N.nodeValue.replace(/^[\r\n]+/,"")}N=N.firstChild}while(N)}function K(P){var N=i.getRoot(),O,Q;O=P;while(O!==N&&i.getContentEditable(O)!=="false"){if(i.getContentEditable(O)==="true"){Q=O}O=O.parentNode}return O!==N?Q:N}function I(O){var N;if(!b.isIE||b.isIE11){O.normalize();N=O.lastChild;if(!N||(/^(left|right)$/gi.test(i.getStyle(N,"float",true)))){i.add(O,"br")}}}if(!v.collapsed){f.execCommand("Delete");return}if(B.isDefaultPrevented()){return}A=v.startContainer;u=v.startOffset;x=(d.force_p_newlines?"p":"")||d.forced_root_block;x=x?x.toUpperCase():"";M=i.doc.documentMode;C=B.shiftKey;if(A.nodeType==1&&A.hasChildNodes()){D=u>A.childNodes.length-1;A=A.childNodes[Math.min(u,A.childNodes.length-1)]||A;if(D&&A.nodeType==3){u=A.nodeValue.length}else{u=0}}j=K(A);if(!j){return}h.beforeChange();if(!i.isBlock(j)&&j!=i.getRoot()){if(!x||C){L()}return}if((x&&!C)||(!x&&C)){A=l(A,u)}p=i.getParent(A,i.isBlock);n=p?i.getParent(p.parentNode,i.isBlock):null;t=p?p.nodeName.toUpperCase():"";J=n?n.nodeName.toUpperCase():"";if(J=="LI"&&!B.ctrlKey){p=n;t=J}if(t=="LI"){if(!x&&C){L();return}if(i.isEmpty(p)){if(/^(UL|OL|LI)$/.test(n.parentNode.nodeName)){return false}H();return}}if(t=="PRE"&&d.br_in_pre!==false){if(!C){L();return}}else{if((!x&&!C&&t!="LI")||(x&&C)){L();return}}x=x||"P";if(q()){if(/^(H[1-6]|PRE)$/.test(t)&&J!="HGROUP"){o=r(x)}else{o=r()}if(d.end_container_on_empty_block&&E(n)&&i.isEmpty(p)){o=i.split(n,p)}else{i.insertAfter(o,p)}m(o)}else{if(q(true)){o=p.parentNode.insertBefore(r(),p);F(o)}else{G=v.cloneRange();G.setEndAfter(p);k=G.extractContents();s(k);o=k.firstChild;i.insertAfter(k,p);z(o);I(p);m(o)}}i.setAttrib(o,"id","");h.add()}f.onKeyDown.add(function(k,j){if(j.keyCode==13){if(g(j)!==false){j.preventDefault()}}})}})(tinymce); |
| 1 | // 4.0.12 (2013-12-18) |
| 2 | |
| 3 | /** |
| 4 | * Compiled inline version. (Library mode) |
| 5 | */ |
| 6 | |
| 7 | /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ |
| 8 | /*globals $code */ |
| 9 | |
| 10 | (function(exports, undefined) { |
| 11 | "use strict"; |
| 12 | |
| 13 | var modules = {}; |
| 14 | |
| 15 | function require(ids, callback) { |
| 16 | var module, defs = []; |
| 17 | |
| 18 | for (var i = 0; i < ids.length; ++i) { |
| 19 | module = modules[ids[i]] || resolve(ids[i]); |
| 20 | if (!module) { |
| 21 | throw 'module definition dependecy not found: ' + ids[i]; |
| 22 | } |
| 23 | |
| 24 | defs.push(module); |
| 25 | } |
| 26 | |
| 27 | callback.apply(null, defs); |
| 28 | } |
| 29 | |
| 30 | function define(id, dependencies, definition) { |
| 31 | if (typeof id !== 'string') { |
| 32 | throw 'invalid module definition, module id must be defined and be a string'; |
| 33 | } |
| 34 | |
| 35 | if (dependencies === undefined) { |
| 36 | throw 'invalid module definition, dependencies must be specified'; |
| 37 | } |
| 38 | |
| 39 | if (definition === undefined) { |
| 40 | throw 'invalid module definition, definition function must be specified'; |
| 41 | } |
| 42 | |
| 43 | require(dependencies, function() { |
| 44 | modules[id] = definition.apply(null, arguments); |
| 45 | }); |
| 46 | } |
| 47 | |
| 48 | function defined(id) { |
| 49 | return !!modules[id]; |
| 50 | } |
| 51 | |
| 52 | function resolve(id) { |
| 53 | var target = exports; |
| 54 | var fragments = id.split(/[.\/]/); |
| 55 | |
| 56 | for (var fi = 0; fi < fragments.length; ++fi) { |
| 57 | if (!target[fragments[fi]]) { |
| 58 | return; |
| 59 | } |
| 60 | |
| 61 | target = target[fragments[fi]]; |
| 62 | } |
| 63 | |
| 64 | return target; |
| 65 | } |
| 66 | |
| 67 | function expose(ids) { |
| 68 | for (var i = 0; i < ids.length; i++) { |
| 69 | var target = exports; |
| 70 | var id = ids[i]; |
| 71 | var fragments = id.split(/[.\/]/); |
| 72 | |
| 73 | for (var fi = 0; fi < fragments.length - 1; ++fi) { |
| 74 | if (target[fragments[fi]] === undefined) { |
| 75 | target[fragments[fi]] = {}; |
| 76 | } |
| 77 | |
| 78 | target = target[fragments[fi]]; |
| 79 | } |
| 80 | |
| 81 | target[fragments[fragments.length - 1]] = modules[id]; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | // Included from: js/tinymce/classes/dom/EventUtils.js |
| 86 | |
| 87 | /** |
| 88 | * EventUtils.js |
| 89 | * |
| 90 | * Copyright, Moxiecode Systems AB |
| 91 | * Released under LGPL License. |
| 92 | * |
| 93 | * License: http://www.tinymce.com/license |
| 94 | * Contributing: http://www.tinymce.com/contributing |
| 95 | */ |
| 96 | |
| 97 | /*jshint loopfunc:true*/ |
| 98 | |
| 99 | define("tinymce/dom/EventUtils", [], function() { |
| 100 | "use strict"; |
| 101 | |
| 102 | var eventExpandoPrefix = "mce-data-"; |
| 103 | var mouseEventRe = /^(?:mouse|contextmenu)|click/; |
| 104 | var deprecated = {keyLocation: 1, layerX: 1, layerY: 1, returnValue: 1}; |
| 105 | |
| 106 | /** |
| 107 | * Binds a native event to a callback on the speified target. |
| 108 | */ |
| 109 | function addEvent(target, name, callback, capture) { |
| 110 | if (target.addEventListener) { |
| 111 | target.addEventListener(name, callback, capture || false); |
| 112 | } else if (target.attachEvent) { |
| 113 | target.attachEvent('on' + name, callback); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * Unbinds a native event callback on the specified target. |
| 119 | */ |
| 120 | function removeEvent(target, name, callback, capture) { |
| 121 | if (target.removeEventListener) { |
| 122 | target.removeEventListener(name, callback, capture || false); |
| 123 | } else if (target.detachEvent) { |
| 124 | target.detachEvent('on' + name, callback); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * Normalizes a native event object or just adds the event specific methods on a custom event. |
| 130 | */ |
| 131 | function fix(originalEvent, data) { |
| 132 | var name, event = data || {}, undef; |
| 133 | |
| 134 | // Dummy function that gets replaced on the delegation state functions |
| 135 | function returnFalse() { |
| 136 | return false; |
| 137 | } |
| 138 | |
| 139 | // Dummy function that gets replaced on the delegation state functions |
| 140 | function returnTrue() { |
| 141 | return true; |
| 142 | } |
| 143 | |
| 144 | // Copy all properties from the original event |
| 145 | for (name in originalEvent) { |
| 146 | // layerX/layerY is deprecated in Chrome and produces a warning |
| 147 | if (!deprecated[name]) { |
| 148 | event[name] = originalEvent[name]; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | // Normalize target IE uses srcElement |
| 153 | if (!event.target) { |
| 154 | event.target = event.srcElement || document; |
| 155 | } |
| 156 | |
| 157 | // Calculate pageX/Y if missing and clientX/Y available |
| 158 | if (originalEvent && mouseEventRe.test(originalEvent.type) && originalEvent.pageX === undef && originalEvent.clientX !== undef) { |
| 159 | var eventDoc = event.target.ownerDocument || document; |
| 160 | var doc = eventDoc.documentElement; |
| 161 | var body = eventDoc.body; |
| 162 | |
| 163 | event.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - |
| 164 | ( doc && doc.clientLeft || body && body.clientLeft || 0); |
| 165 | |
| 166 | event.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0 ) - |
| 167 | ( doc && doc.clientTop || body && body.clientTop || 0); |
| 168 | } |
| 169 | |
| 170 | // Add preventDefault method |
| 171 | event.preventDefault = function() { |
| 172 | event.isDefaultPrevented = returnTrue; |
| 173 | |
| 174 | // Execute preventDefault on the original event object |
| 175 | if (originalEvent) { |
| 176 | if (originalEvent.preventDefault) { |
| 177 | originalEvent.preventDefault(); |
| 178 | } else { |
| 179 | originalEvent.returnValue = false; // IE |
| 180 | } |
| 181 | } |
| 182 | }; |
| 183 | |
| 184 | // Add stopPropagation |
| 185 | event.stopPropagation = function() { |
| 186 | event.isPropagationStopped = returnTrue; |
| 187 | |
| 188 | // Execute stopPropagation on the original event object |
| 189 | if (originalEvent) { |
| 190 | if (originalEvent.stopPropagation) { |
| 191 | originalEvent.stopPropagation(); |
| 192 | } else { |
| 193 | originalEvent.cancelBubble = true; // IE |
| 194 | } |
| 195 | } |
| 196 | }; |
| 197 | |
| 198 | // Add stopImmediatePropagation |
| 199 | event.stopImmediatePropagation = function() { |
| 200 | event.isImmediatePropagationStopped = returnTrue; |
| 201 | event.stopPropagation(); |
| 202 | }; |
| 203 | |
| 204 | // Add event delegation states |
| 205 | if (!event.isDefaultPrevented) { |
| 206 | event.isDefaultPrevented = returnFalse; |
| 207 | event.isPropagationStopped = returnFalse; |
| 208 | event.isImmediatePropagationStopped = returnFalse; |
| 209 | } |
| 210 | |
| 211 | return event; |
| 212 | } |
| 213 | |
| 214 | /** |
| 215 | * Bind a DOMContentLoaded event across browsers and executes the callback once the page DOM is initialized. |
| 216 | * It will also set/check the domLoaded state of the event_utils instance so ready isn't called multiple times. |
| 217 | */ |
| 218 | function bindOnReady(win, callback, eventUtils) { |
| 219 | var doc = win.document, event = {type: 'ready'}; |
| 220 | |
| 221 | if (eventUtils.domLoaded) { |
| 222 | callback(event); |
| 223 | return; |
| 224 | } |
| 225 | |
| 226 | // Gets called when the DOM is ready |
| 227 | function readyHandler() { |
| 228 | if (!eventUtils.domLoaded) { |
| 229 | eventUtils.domLoaded = true; |
| 230 | callback(event); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | function waitForDomLoaded() { |
| 235 | if (doc.readyState === "complete") { |
| 236 | removeEvent(doc, "readystatechange", waitForDomLoaded); |
| 237 | readyHandler(); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | function tryScroll() { |
| 242 | try { |
| 243 | // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author. |
| 244 | // http://javascript.nwbox.com/IEContentLoaded/ |
| 245 | doc.documentElement.doScroll("left"); |
| 246 | } catch (ex) { |
| 247 | setTimeout(tryScroll, 0); |
| 248 | return; |
| 249 | } |
| 250 | |
| 251 | readyHandler(); |
| 252 | } |
| 253 | |
| 254 | // Use W3C method |
| 255 | if (doc.addEventListener) { |
| 256 | if (doc.readyState === "complete") { |
| 257 | readyHandler(); |
| 258 | } else { |
| 259 | addEvent(win, 'DOMContentLoaded', readyHandler); |
| 260 | } |
| 261 | } else { |
| 262 | // Use IE method |
| 263 | addEvent(doc, "readystatechange", waitForDomLoaded); |
| 264 | |
| 265 | // Wait until we can scroll, when we can the DOM is initialized |
| 266 | if (doc.documentElement.doScroll && win === win.top) { |
| 267 | tryScroll(); |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | // Fallback if any of the above methods should fail for some odd reason |
| 272 | addEvent(win, 'load', readyHandler); |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * This class enables you to bind/unbind native events to elements and normalize it's behavior across browsers. |
| 277 | */ |
| 278 | function EventUtils() { |
| 279 | var self = this, events = {}, count, expando, hasFocusIn, hasMouseEnterLeave, mouseEnterLeave; |
| 280 | |
| 281 | expando = eventExpandoPrefix + (+new Date()).toString(32); |
| 282 | hasMouseEnterLeave = "onmouseenter" in document.documentElement; |
| 283 | hasFocusIn = "onfocusin" in document.documentElement; |
| 284 | mouseEnterLeave = {mouseenter: 'mouseover', mouseleave: 'mouseout'}; |
| 285 | count = 1; |
| 286 | |
| 287 | // State if the DOMContentLoaded was executed or not |
| 288 | self.domLoaded = false; |
| 289 | self.events = events; |
| 290 | |
| 291 | /** |
| 292 | * Executes all event handler callbacks for a specific event. |
| 293 | * |
| 294 | * @private |
| 295 | * @param {Event} evt Event object. |
| 296 | * @param {String} id Expando id value to look for. |
| 297 | */ |
| 298 | function executeHandlers(evt, id) { |
| 299 | var callbackList, i, l, callback, container = events[id]; |
| 300 | |
| 301 | callbackList = container && container[evt.type]; |
| 302 | if (callbackList) { |
| 303 | for (i = 0, l = callbackList.length; i < l; i++) { |
| 304 | callback = callbackList[i]; |
| 305 | |
| 306 | // Check if callback exists might be removed if a unbind is called inside the callback |
| 307 | if (callback && callback.func.call(callback.scope, evt) === false) { |
| 308 | evt.preventDefault(); |
| 309 | } |
| 310 | |
| 311 | // Should we stop propagation to immediate listeners |
| 312 | if (evt.isImmediatePropagationStopped()) { |
| 313 | return; |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | /** |
| 320 | * Binds a callback to an event on the specified target. |
| 321 | * |
| 322 | * @method bind |
| 323 | * @param {Object} target Target node/window or custom object. |
| 324 | * @param {String} names Name of the event to bind. |
| 325 | * @param {function} callback Callback function to execute when the event occurs. |
| 326 | * @param {Object} scope Scope to call the callback function on, defaults to target. |
| 327 | * @return {function} Callback function that got bound. |
| 328 | */ |
| 329 | self.bind = function(target, names, callback, scope) { |
| 330 | var id, callbackList, i, name, fakeName, nativeHandler, capture, win = window; |
| 331 | |
| 332 | // Native event handler function patches the event and executes the callbacks for the expando |
| 333 | function defaultNativeHandler(evt) { |
| 334 | executeHandlers(fix(evt || win.event), id); |
| 335 | } |
| 336 | |
| 337 | // Don't bind to text nodes or comments |
| 338 | if (!target || target.nodeType === 3 || target.nodeType === 8) { |
| 339 | return; |
| 340 | } |
| 341 | |
| 342 | // Create or get events id for the target |
| 343 | if (!target[expando]) { |
| 344 | id = count++; |
| 345 | target[expando] = id; |
| 346 | events[id] = {}; |
| 347 | } else { |
| 348 | id = target[expando]; |
| 349 | } |
| 350 | |
| 351 | // Setup the specified scope or use the target as a default |
| 352 | scope = scope || target; |
| 353 | |
| 354 | // Split names and bind each event, enables you to bind multiple events with one call |
| 355 | names = names.split(' '); |
| 356 | i = names.length; |
| 357 | while (i--) { |
| 358 | name = names[i]; |
| 359 | nativeHandler = defaultNativeHandler; |
| 360 | fakeName = capture = false; |
| 361 | |
| 362 | // Use ready instead of DOMContentLoaded |
| 363 | if (name === "DOMContentLoaded") { |
| 364 | name = "ready"; |
| 365 | } |
| 366 | |
| 367 | // DOM is already ready |
| 368 | if (self.domLoaded && name === "ready" && target.readyState == 'complete') { |
| 369 | callback.call(scope, fix({type: name})); |
| 370 | continue; |
| 371 | } |
| 372 | |
| 373 | // Handle mouseenter/mouseleaver |
| 374 | if (!hasMouseEnterLeave) { |
| 375 | fakeName = mouseEnterLeave[name]; |
| 376 | |
| 377 | if (fakeName) { |
| 378 | nativeHandler = function(evt) { |
| 379 | var current, related; |
| 380 | |
| 381 | current = evt.currentTarget; |
| 382 | related = evt.relatedTarget; |
| 383 | |
| 384 | // Check if related is inside the current target if it's not then the event should |
| 385 | // be ignored since it's a mouseover/mouseout inside the element |
| 386 | if (related && current.contains) { |
| 387 | // Use contains for performance |
| 388 | related = current.contains(related); |
| 389 | } else { |
| 390 | while (related && related !== current) { |
| 391 | related = related.parentNode; |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | // Fire fake event |
| 396 | if (!related) { |
| 397 | evt = fix(evt || win.event); |
| 398 | evt.type = evt.type === 'mouseout' ? 'mouseleave' : 'mouseenter'; |
| 399 | evt.target = current; |
| 400 | executeHandlers(evt, id); |
| 401 | } |
| 402 | }; |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | // Fake bubbeling of focusin/focusout |
| 407 | if (!hasFocusIn && (name === "focusin" || name === "focusout")) { |
| 408 | capture = true; |
| 409 | fakeName = name === "focusin" ? "focus" : "blur"; |
| 410 | nativeHandler = function(evt) { |
| 411 | evt = fix(evt || win.event); |
| 412 | evt.type = evt.type === 'focus' ? 'focusin' : 'focusout'; |
| 413 | executeHandlers(evt, id); |
| 414 | }; |
| 415 | } |
| 416 | |
| 417 | // Setup callback list and bind native event |
| 418 | callbackList = events[id][name]; |
| 419 | if (!callbackList) { |
| 420 | events[id][name] = callbackList = [{func: callback, scope: scope}]; |
| 421 | callbackList.fakeName = fakeName; |
| 422 | callbackList.capture = capture; |
| 423 | |
| 424 | // Add the nativeHandler to the callback list so that we can later unbind it |
| 425 | callbackList.nativeHandler = nativeHandler; |
| 426 | |
| 427 | // Check if the target has native events support |
| 428 | |
| 429 | if (name === "ready") { |
| 430 | bindOnReady(target, nativeHandler, self); |
| 431 | } else { |
| 432 | addEvent(target, fakeName || name, nativeHandler, capture); |
| 433 | } |
| 434 | } else { |
| 435 | if (name === "ready" && self.domLoaded) { |
| 436 | callback({type: name}); |
| 437 | } else { |
| 438 | // If it already has an native handler then just push the callback |
| 439 | callbackList.push({func: callback, scope: scope}); |
| 440 | } |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | target = callbackList = 0; // Clean memory for IE |
| 445 | |
| 446 | return callback; |
| 447 | }; |
| 448 | |
| 449 | /** |
| 450 | * Unbinds the specified event by name, name and callback or all events on the target. |
| 451 | * |
| 452 | * @method unbind |
| 453 | * @param {Object} target Target node/window or custom object. |
| 454 | * @param {String} names Optional event name to unbind. |
| 455 | * @param {function} callback Optional callback function to unbind. |
| 456 | * @return {EventUtils} Event utils instance. |
| 457 | */ |
| 458 | self.unbind = function(target, names, callback) { |
| 459 | var id, callbackList, i, ci, name, eventMap; |
| 460 | |
| 461 | // Don't bind to text nodes or comments |
| 462 | if (!target || target.nodeType === 3 || target.nodeType === 8) { |
| 463 | return self; |
| 464 | } |
| 465 | |
| 466 | // Unbind event or events if the target has the expando |
| 467 | id = target[expando]; |
| 468 | if (id) { |
| 469 | eventMap = events[id]; |
| 470 | |
| 471 | // Specific callback |
| 472 | if (names) { |
| 473 | names = names.split(' '); |
| 474 | i = names.length; |
| 475 | while (i--) { |
| 476 | name = names[i]; |
| 477 | callbackList = eventMap[name]; |
| 478 | |
| 479 | // Unbind the event if it exists in the map |
| 480 | if (callbackList) { |
| 481 | // Remove specified callback |
| 482 | if (callback) { |
| 483 | ci = callbackList.length; |
| 484 | while (ci--) { |
| 485 | if (callbackList[ci].func === callback) { |
| 486 | var nativeHandler = callbackList.nativeHandler; |
| 487 | |
| 488 | // Clone callbackList since unbind inside a callback would otherwise break the handlers loop |
| 489 | callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1)); |
| 490 | callbackList.nativeHandler = nativeHandler; |
| 491 | |
| 492 | eventMap[name] = callbackList; |
| 493 | } |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | // Remove all callbacks if there isn't a specified callback or there is no callbacks left |
| 498 | if (!callback || callbackList.length === 0) { |
| 499 | delete eventMap[name]; |
| 500 | removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture); |
| 501 | } |
| 502 | } |
| 503 | } |
| 504 | } else { |
| 505 | // All events for a specific element |
| 506 | for (name in eventMap) { |
| 507 | callbackList = eventMap[name]; |
| 508 | removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture); |
| 509 | } |
| 510 | |
| 511 | eventMap = {}; |
| 512 | } |
| 513 | |
| 514 | // Check if object is empty, if it isn't then we won't remove the expando map |
| 515 | for (name in eventMap) { |
| 516 | return self; |
| 517 | } |
| 518 | |
| 519 | // Delete event object |
| 520 | delete events[id]; |
| 521 | |
| 522 | // Remove expando from target |
| 523 | try { |
| 524 | // IE will fail here since it can't delete properties from window |
| 525 | delete target[expando]; |
| 526 | } catch (ex) { |
| 527 | // IE will set it to null |
| 528 | target[expando] = null; |
| 529 | } |
| 530 | } |
| 531 | |
| 532 | return self; |
| 533 | }; |
| 534 | |
| 535 | /** |
| 536 | * Fires the specified event on the specified target. |
| 537 | * |
| 538 | * @method fire |
| 539 | * @param {Object} target Target node/window or custom object. |
| 540 | * @param {String} name Event name to fire. |
| 541 | * @param {Object} args Optional arguments to send to the observers. |
| 542 | * @return {EventUtils} Event utils instance. |
| 543 | */ |
| 544 | self.fire = function(target, name, args) { |
| 545 | var id; |
| 546 | |
| 547 | // Don't bind to text nodes or comments |
| 548 | if (!target || target.nodeType === 3 || target.nodeType === 8) { |
| 549 | return self; |
| 550 | } |
| 551 | |
| 552 | // Build event object by patching the args |
| 553 | args = fix(null, args); |
| 554 | args.type = name; |
| 555 | args.target = target; |
| 556 | |
| 557 | do { |
| 558 | // Found an expando that means there is listeners to execute |
| 559 | id = target[expando]; |
| 560 | if (id) { |
| 561 | executeHandlers(args, id); |
| 562 | } |
| 563 | |
| 564 | // Walk up the DOM |
| 565 | target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow; |
| 566 | } while (target && !args.isPropagationStopped()); |
| 567 | |
| 568 | return self; |
| 569 | }; |
| 570 | |
| 571 | /** |
| 572 | * Removes all bound event listeners for the specified target. This will also remove any bound |
| 573 | * listeners to child nodes within that target. |
| 574 | * |
| 575 | * @method clean |
| 576 | * @param {Object} target Target node/window object. |
| 577 | * @return {EventUtils} Event utils instance. |
| 578 | */ |
| 579 | self.clean = function(target) { |
| 580 | var i, children, unbind = self.unbind; |
| 581 | |
| 582 | // Don't bind to text nodes or comments |
| 583 | if (!target || target.nodeType === 3 || target.nodeType === 8) { |
| 584 | return self; |
| 585 | } |
| 586 | |
| 587 | // Unbind any element on the specificed target |
| 588 | if (target[expando]) { |
| 589 | unbind(target); |
| 590 | } |
| 591 | |
| 592 | // Target doesn't have getElementsByTagName it's probably a window object then use it's document to find the children |
| 593 | if (!target.getElementsByTagName) { |
| 594 | target = target.document; |
| 595 | } |
| 596 | |
| 597 | // Remove events from each child element |
| 598 | if (target && target.getElementsByTagName) { |
| 599 | unbind(target); |
| 600 | |
| 601 | children = target.getElementsByTagName('*'); |
| 602 | i = children.length; |
| 603 | while (i--) { |
| 604 | target = children[i]; |
| 605 | |
| 606 | if (target[expando]) { |
| 607 | unbind(target); |
| 608 | } |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | return self; |
| 613 | }; |
| 614 | |
| 615 | /** |
| 616 | * Destroys the event object. Call this on IE to remove memory leaks. |
| 617 | */ |
| 618 | self.destroy = function() { |
| 619 | events = {}; |
| 620 | }; |
| 621 | |
| 622 | // Legacy function for canceling events |
| 623 | self.cancel = function(e) { |
| 624 | if (e) { |
| 625 | e.preventDefault(); |
| 626 | e.stopImmediatePropagation(); |
| 627 | } |
| 628 | |
| 629 | return false; |
| 630 | }; |
| 631 | } |
| 632 | |
| 633 | EventUtils.Event = new EventUtils(); |
| 634 | EventUtils.Event.bind(window, 'ready', function() {}); |
| 635 | |
| 636 | return EventUtils; |
| 637 | }); |
| 638 | |
| 639 | // Included from: js/tinymce/classes/dom/Sizzle.js |
| 640 | |
| 641 | /** |
| 642 | * Sizzle.js |
| 643 | * |
| 644 | * Copyright, Moxiecode Systems AB |
| 645 | * Released under LGPL License. |
| 646 | * |
| 647 | * License: http://www.tinymce.com/license |
| 648 | * Contributing: http://www.tinymce.com/contributing |
| 649 | * |
| 650 | * @ignore-file |
| 651 | */ |
| 652 | |
| 653 | /*jshint bitwise:false, expr:true, noempty:false, sub:true, eqnull:true, latedef:false, maxlen:255 */ |
| 654 | |
| 655 | /* |
| 656 | * Sizzle CSS Selector Engine |
| 657 | * Copyright, The Dojo Foundation |
| 658 | * Released under the MIT, BSD, and GPL Licenses. |
| 659 | * More information: http://sizzlejs.com/ |
| 660 | */ |
| 661 | define("tinymce/dom/Sizzle", [], function() { |
| 662 | var i, |
| 663 | cachedruns, |
| 664 | Expr, |
| 665 | getText, |
| 666 | isXML, |
| 667 | compile, |
| 668 | outermostContext, |
| 669 | recompare, |
| 670 | sortInput, |
| 671 | |
| 672 | // Local document vars |
| 673 | setDocument, |
| 674 | document, |
| 675 | docElem, |
| 676 | documentIsHTML, |
| 677 | rbuggyQSA, |
| 678 | rbuggyMatches, |
| 679 | matches, |
| 680 | contains, |
| 681 | |
| 682 | // Instance-specific data |
| 683 | expando = "sizzle" + -(new Date()), |
| 684 | preferredDoc = window.document, |
| 685 | support = {}, |
| 686 | dirruns = 0, |
| 687 | done = 0, |
| 688 | classCache = createCache(), |
| 689 | tokenCache = createCache(), |
| 690 | compilerCache = createCache(), |
| 691 | hasDuplicate = false, |
| 692 | sortOrder = function() { return 0; }, |
| 693 | |
| 694 | // General-purpose constants |
| 695 | strundefined = typeof undefined, |
| 696 | MAX_NEGATIVE = 1 << 31, |
| 697 | |
| 698 | // Array methods |
| 699 | arr = [], |
| 700 | pop = arr.pop, |
| 701 | push_native = arr.push, |
| 702 | push = arr.push, |
| 703 | slice = arr.slice, |
| 704 | // Use a stripped-down indexOf if we can't use a native one |
| 705 | indexOf = arr.indexOf || function( elem ) { |
| 706 | var i = 0, |
| 707 | len = this.length; |
| 708 | for ( ; i < len; i++ ) { |
| 709 | if ( this[i] === elem ) { |
| 710 | return i; |
| 711 | } |
| 712 | } |
| 713 | return -1; |
| 714 | }, |
| 715 | |
| 716 | |
| 717 | // Regular expressions |
| 718 | |
| 719 | // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace |
| 720 | whitespace = "[\\x20\\t\\r\\n\\f]", |
| 721 | // http://www.w3.org/TR/css3-syntax/#characters |
| 722 | characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", |
| 723 | |
| 724 | // Loosely modeled on CSS identifier characters |
| 725 | // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors |
| 726 | // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier |
| 727 | identifier = characterEncoding.replace( "w", "w#" ), |
| 728 | |
| 729 | // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors |
| 730 | operators = "([*^$|!~]?=)", |
| 731 | attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + |
| 732 | "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", |
| 733 | |
| 734 | // Prefer arguments quoted, |
| 735 | // then not containing pseudos/brackets, |
| 736 | // then attribute selectors/non-parenthetical expressions, |
| 737 | // then anything else |
| 738 | // These preferences are here to reduce the number of selectors |
| 739 | // needing tokenize in the PSEUDO preFilter |
| 740 | pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", |
| 741 | |
| 742 | // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter |
| 743 | rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), |
| 744 | |
| 745 | rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), |
| 746 | rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), |
| 747 | rpseudo = new RegExp( pseudos ), |
| 748 | ridentifier = new RegExp( "^" + identifier + "$" ), |
| 749 | |
| 750 | matchExpr = { |
| 751 | "ID": new RegExp( "^#(" + characterEncoding + ")" ), |
| 752 | "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), |
| 753 | "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), |
| 754 | "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), |
| 755 | "ATTR": new RegExp( "^" + attributes ), |
| 756 | "PSEUDO": new RegExp( "^" + pseudos ), |
| 757 | "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + |
| 758 | "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + |
| 759 | "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), |
| 760 | // For use in libraries implementing .is() |
| 761 | // We use this for POS matching in `select` |
| 762 | "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + |
| 763 | whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) |
| 764 | }, |
| 765 | |
| 766 | rsibling = /[\x20\t\r\n\f]*[+~]/, |
| 767 | |
| 768 | rnative = /^[^{]+\{\s*\[native code/, |
| 769 | |
| 770 | // Easily-parseable/retrievable ID or TAG or CLASS selectors |
| 771 | rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, |
| 772 | |
| 773 | rinputs = /^(?:input|select|textarea|button)$/i, |
| 774 | rheader = /^h\d$/i, |
| 775 | |
| 776 | rescape = /'|\\/g, |
| 777 | rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, |
| 778 | |
| 779 | // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters |
| 780 | runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, |
| 781 | funescape = function( _, escaped ) { |
| 782 | var high = "0x" + escaped - 0x10000; |
| 783 | // NaN means non-codepoint |
| 784 | return high !== high ? |
| 785 | escaped : |
| 786 | // BMP codepoint |
| 787 | high < 0 ? |
| 788 | String.fromCharCode( high + 0x10000 ) : |
| 789 | // Supplemental Plane codepoint (surrogate pair) |
| 790 | String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); |
| 791 | }; |
| 792 | |
| 793 | // Optimize for push.apply( _, NodeList ) |
| 794 | try { |
| 795 | push.apply( |
| 796 | (arr = slice.call( preferredDoc.childNodes )), |
| 797 | preferredDoc.childNodes |
| 798 | ); |
| 799 | // Support: Android<4.0 |
| 800 | // Detect silently failing push.apply |
| 801 | arr[ preferredDoc.childNodes.length ].nodeType; |
| 802 | } catch ( e ) { |
| 803 | push = { apply: arr.length ? |
| 804 | |
| 805 | // Leverage slice if possible |
| 806 | function( target, els ) { |
| 807 | push_native.apply( target, slice.call(els) ); |
| 808 | } : |
| 809 | |
| 810 | // Support: IE<9 |
| 811 | // Otherwise append directly |
| 812 | function( target, els ) { |
| 813 | var j = target.length, |
| 814 | i = 0; |
| 815 | // Can't trust NodeList.length |
| 816 | while ( (target[j++] = els[i++]) ) {} |
| 817 | target.length = j - 1; |
| 818 | } |
| 819 | }; |
| 820 | } |
| 821 | |
| 822 | /** |
| 823 | * For feature detection |
| 824 | * @param {Function} fn The function to test for native support |
| 825 | */ |
| 826 | function isNative( fn ) { |
| 827 | return rnative.test( fn + "" ); |
| 828 | } |
| 829 | |
| 830 | /** |
| 831 | * Create key-value caches of limited size |
| 832 | * @returns {Function(string, Object)} Returns the Object data after storing it on itself with |
| 833 | * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) |
| 834 | * deleting the oldest entry |
| 835 | */ |
| 836 | function createCache() { |
| 837 | var cache, |
| 838 | keys = []; |
| 839 | |
| 840 | cache = function( key, value ) { |
| 841 | // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) |
| 842 | if ( keys.push( key += " " ) > Expr.cacheLength ) { |
| 843 | // Only keep the most recent entries |
| 844 | delete cache[ keys.shift() ]; |
| 845 | } |
| 846 | cache[ key ] = value; |
| 847 | return value; |
| 848 | }; |
| 849 | |
| 850 | return cache; |
| 851 | } |
| 852 | |
| 853 | /** |
| 854 | * Mark a function for special use by Sizzle |
| 855 | * @param {Function} fn The function to mark |
| 856 | */ |
| 857 | function markFunction( fn ) { |
| 858 | fn[ expando ] = true; |
| 859 | return fn; |
| 860 | } |
| 861 | |
| 862 | /** |
| 863 | * Support testing using an element |
| 864 | * @param {Function} fn Passed the created div and expects a boolean result |
| 865 | */ |
| 866 | function assert( fn ) { |
| 867 | var div = document.createElement("div"); |
| 868 | |
| 869 | try { |
| 870 | return !!fn( div ); |
| 871 | } catch (e) { |
| 872 | return false; |
| 873 | } finally { |
| 874 | // release memory in IE |
| 875 | div = null; |
| 876 | } |
| 877 | } |
| 878 | |
| 879 | function Sizzle( selector, context, results, seed ) { |
| 880 | var match, elem, m, nodeType, |
| 881 | // QSA vars |
| 882 | i, groups, old, nid, newContext, newSelector; |
| 883 | |
| 884 | if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { |
| 885 | setDocument( context ); |
| 886 | } |
| 887 | |
| 888 | context = context || document; |
| 889 | results = results || []; |
| 890 | |
| 891 | if ( !selector || typeof selector !== "string" ) { |
| 892 | return results; |
| 893 | } |
| 894 | |
| 895 | if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { |
| 896 | return []; |
| 897 | } |
| 898 | |
| 899 | if ( documentIsHTML && !seed ) { |
| 900 | |
| 901 | // Shortcuts |
| 902 | if ( (match = rquickExpr.exec( selector )) ) { |
| 903 | // Speed-up: Sizzle("#ID") |
| 904 | if ( (m = match[1]) ) { |
| 905 | if ( nodeType === 9 ) { |
| 906 | elem = context.getElementById( m ); |
| 907 | // Check parentNode to catch when Blackberry 4.6 returns |
| 908 | // nodes that are no longer in the document #6963 |
| 909 | if ( elem && elem.parentNode ) { |
| 910 | // Handle the case where IE, Opera, and Webkit return items |
| 911 | // by name instead of ID |
| 912 | if ( elem.id === m ) { |
| 913 | results.push( elem ); |
| 914 | return results; |
| 915 | } |
| 916 | } else { |
| 917 | return results; |
| 918 | } |
| 919 | } else { |
| 920 | // Context is not a document |
| 921 | if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && |
| 922 | contains( context, elem ) && elem.id === m ) { |
| 923 | results.push( elem ); |
| 924 | return results; |
| 925 | } |
| 926 | } |
| 927 | |
| 928 | // Speed-up: Sizzle("TAG") |
| 929 | } else if ( match[2] ) { |
| 930 | push.apply( results, context.getElementsByTagName( selector ) ); |
| 931 | return results; |
| 932 | |
| 933 | // Speed-up: Sizzle(".CLASS") |
| 934 | } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { |
| 935 | push.apply( results, context.getElementsByClassName( m ) ); |
| 936 | return results; |
| 937 | } |
| 938 | } |
| 939 | |
| 940 | // QSA path |
| 941 | if ( support.qsa && !rbuggyQSA.test(selector) ) { |
| 942 | old = true; |
| 943 | nid = expando; |
| 944 | newContext = context; |
| 945 | newSelector = nodeType === 9 && selector; |
| 946 | |
| 947 | // qSA works strangely on Element-rooted queries |
| 948 | // We can work around this by specifying an extra ID on the root |
| 949 | // and working up from there (Thanks to Andrew Dupont for the technique) |
| 950 | // IE 8 doesn't work on object elements |
| 951 | if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { |
| 952 | groups = tokenize( selector ); |
| 953 | |
| 954 | if ( (old = context.getAttribute("id")) ) { |
| 955 | nid = old.replace( rescape, "\\$&" ); |
| 956 | } else { |
| 957 | context.setAttribute( "id", nid ); |
| 958 | } |
| 959 | nid = "[id='" + nid + "'] "; |
| 960 | |
| 961 | i = groups.length; |
| 962 | while ( i-- ) { |
| 963 | groups[i] = nid + toSelector( groups[i] ); |
| 964 | } |
| 965 | newContext = rsibling.test( selector ) && context.parentNode || context; |
| 966 | newSelector = groups.join(","); |
| 967 | } |
| 968 | |
| 969 | if ( newSelector ) { |
| 970 | try { |
| 971 | push.apply( results, |
| 972 | newContext.querySelectorAll( newSelector ) |
| 973 | ); |
| 974 | return results; |
| 975 | } catch(qsaError) { |
| 976 | } finally { |
| 977 | if ( !old ) { |
| 978 | context.removeAttribute("id"); |
| 979 | } |
| 980 | } |
| 981 | } |
| 982 | } |
| 983 | } |
| 984 | |
| 985 | // All others |
| 986 | return select( selector.replace( rtrim, "$1" ), context, results, seed ); |
| 987 | } |
| 988 | |
| 989 | /** |
| 990 | * Detect xml |
| 991 | * @param {Element|Object} elem An element or a document |
| 992 | */ |
| 993 | isXML = Sizzle.isXML = function( elem ) { |
| 994 | // documentElement is verified for cases where it doesn't yet exist |
| 995 | // (such as loading iframes in IE - #4833) |
| 996 | var documentElement = elem && (elem.ownerDocument || elem).documentElement; |
| 997 | return documentElement ? documentElement.nodeName !== "HTML" : false; |
| 998 | }; |
| 999 | |
| 1000 | /** |
| 1001 | * Sets document-related variables once based on the current document |
| 1002 | * @param {Element|Object} [doc] An element or document object to use to set the document |
| 1003 | * @returns {Object} Returns the current document |
| 1004 | */ |
| 1005 | setDocument = Sizzle.setDocument = function( node ) { |
| 1006 | var doc = node ? node.ownerDocument || node : preferredDoc; |
| 1007 | |
| 1008 | // If no document and documentElement is available, return |
| 1009 | if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { |
| 1010 | return document; |
| 1011 | } |
| 1012 | |
| 1013 | // Set our document |
| 1014 | document = doc; |
| 1015 | docElem = doc.documentElement; |
| 1016 | |
| 1017 | // Support tests |
| 1018 | documentIsHTML = !isXML( doc ); |
| 1019 | |
| 1020 | // Check if getElementsByTagName("*") returns only elements |
| 1021 | support.getElementsByTagName = assert(function( div ) { |
| 1022 | div.appendChild( doc.createComment("") ); |
| 1023 | return !div.getElementsByTagName("*").length; |
| 1024 | }); |
| 1025 | |
| 1026 | // Check if attributes should be retrieved by attribute nodes |
| 1027 | support.attributes = assert(function( div ) { |
| 1028 | div.innerHTML = "<select></select>"; |
| 1029 | var type = typeof div.lastChild.getAttribute("multiple"); |
| 1030 | // IE8 returns a string for some attributes even when not present |
| 1031 | return type !== "boolean" && type !== "string"; |
| 1032 | }); |
| 1033 | |
| 1034 | // Check if getElementsByClassName can be trusted |
| 1035 | support.getElementsByClassName = assert(function( div ) { |
| 1036 | // Opera can't find a second classname (in 9.6) |
| 1037 | div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>"; |
| 1038 | if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { |
| 1039 | return false; |
| 1040 | } |
| 1041 | |
| 1042 | // Safari 3.2 caches class attributes and doesn't catch changes |
| 1043 | div.lastChild.className = "e"; |
| 1044 | return div.getElementsByClassName("e").length === 2; |
| 1045 | }); |
| 1046 | |
| 1047 | // Check if getElementsByName privileges form controls or returns elements by ID |
| 1048 | // If so, assume (for broader support) that getElementById returns elements by name |
| 1049 | support.getByName = assert(function( div ) { |
| 1050 | // Inject content |
| 1051 | div.id = expando + 0; |
| 1052 | // Support: Windows 8 Native Apps |
| 1053 | // Assigning innerHTML with "name" attributes throws uncatchable exceptions |
| 1054 | // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx |
| 1055 | div.appendChild( document.createElement("a") ).setAttribute( "name", expando ); |
| 1056 | div.appendChild( document.createElement("i") ).setAttribute( "name", expando ); |
| 1057 | docElem.appendChild( div ); |
| 1058 | |
| 1059 | // Test |
| 1060 | var pass = doc.getElementsByName && |
| 1061 | // buggy browsers will return fewer than the correct 2 |
| 1062 | doc.getElementsByName( expando ).length === 2 + |
| 1063 | // buggy browsers will return more than the correct 0 |
| 1064 | doc.getElementsByName( expando + 0 ).length; |
| 1065 | |
| 1066 | // Cleanup |
| 1067 | docElem.removeChild( div ); |
| 1068 | |
| 1069 | return pass; |
| 1070 | }); |
| 1071 | |
| 1072 | // Support: Webkit<537.32 |
| 1073 | // Detached nodes confoundingly follow *each other* |
| 1074 | support.sortDetached = assert(function( div1 ) { |
| 1075 | return div1.compareDocumentPosition && |
| 1076 | // Should return 1, but Webkit returns 4 (following) |
| 1077 | (div1.compareDocumentPosition( document.createElement("div") ) & 1); |
| 1078 | }); |
| 1079 | |
| 1080 | // IE6/7 return modified attributes |
| 1081 | Expr.attrHandle = assert(function( div ) { |
| 1082 | div.innerHTML = "<a href='#'></a>"; |
| 1083 | return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && |
| 1084 | div.firstChild.getAttribute("href") === "#"; |
| 1085 | }) ? |
| 1086 | {} : |
| 1087 | { |
| 1088 | "href": function( elem ) { |
| 1089 | return elem.getAttribute( "href", 2 ); |
| 1090 | }, |
| 1091 | "type": function( elem ) { |
| 1092 | return elem.getAttribute("type"); |
| 1093 | } |
| 1094 | }; |
| 1095 | |
| 1096 | // ID find and filter |
| 1097 | if ( support.getByName ) { |
| 1098 | Expr.find["ID"] = function( id, context ) { |
| 1099 | if ( typeof context.getElementById !== strundefined && documentIsHTML ) { |
| 1100 | var m = context.getElementById( id ); |
| 1101 | // Check parentNode to catch when Blackberry 4.6 returns |
| 1102 | // nodes that are no longer in the document #6963 |
| 1103 | return m && m.parentNode ? [m] : []; |
| 1104 | } |
| 1105 | }; |
| 1106 | Expr.filter["ID"] = function( id ) { |
| 1107 | var attrId = id.replace( runescape, funescape ); |
| 1108 | return function( elem ) { |
| 1109 | return elem.getAttribute("id") === attrId; |
| 1110 | }; |
| 1111 | }; |
| 1112 | } else { |
| 1113 | Expr.find["ID"] = function( id, context ) { |
| 1114 | if ( typeof context.getElementById !== strundefined && documentIsHTML ) { |
| 1115 | var m = context.getElementById( id ); |
| 1116 | |
| 1117 | return m ? |
| 1118 | m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? |
| 1119 | [m] : |
| 1120 | undefined : |
| 1121 | []; |
| 1122 | } |
| 1123 | }; |
| 1124 | Expr.filter["ID"] = function( id ) { |
| 1125 | var attrId = id.replace( runescape, funescape ); |
| 1126 | return function( elem ) { |
| 1127 | var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); |
| 1128 | return node && node.value === attrId; |
| 1129 | }; |
| 1130 | }; |
| 1131 | } |
| 1132 | |
| 1133 | // Tag |
| 1134 | Expr.find["TAG"] = support.getElementsByTagName ? |
| 1135 | function( tag, context ) { |
| 1136 | if ( typeof context.getElementsByTagName !== strundefined ) { |
| 1137 | return context.getElementsByTagName( tag ); |
| 1138 | } |
| 1139 | } : |
| 1140 | function( tag, context ) { |
| 1141 | var elem, |
| 1142 | tmp = [], |
| 1143 | i = 0, |
| 1144 | results = context.getElementsByTagName( tag ); |
| 1145 | |
| 1146 | // Filter out possible comments |
| 1147 | if ( tag === "*" ) { |
| 1148 | while ( (elem = results[i++]) ) { |
| 1149 | if ( elem.nodeType === 1 ) { |
| 1150 | tmp.push( elem ); |
| 1151 | } |
| 1152 | } |
| 1153 | |
| 1154 | return tmp; |
| 1155 | } |
| 1156 | return results; |
| 1157 | }; |
| 1158 | |
| 1159 | // Name |
| 1160 | Expr.find["NAME"] = support.getByName && function( tag, context ) { |
| 1161 | if ( typeof context.getElementsByName !== strundefined ) { |
| 1162 | return context.getElementsByName( name ); |
| 1163 | } |
| 1164 | }; |
| 1165 | |
| 1166 | // Class |
| 1167 | Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { |
| 1168 | if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { |
| 1169 | return context.getElementsByClassName( className ); |
| 1170 | } |
| 1171 | }; |
| 1172 | |
| 1173 | // QSA and matchesSelector support |
| 1174 | |
| 1175 | // matchesSelector(:active) reports false when true (IE9/Opera 11.5) |
| 1176 | rbuggyMatches = []; |
| 1177 | |
| 1178 | // qSa(:focus) reports false when true (Chrome 21), |
| 1179 | // no need to also add to buggyMatches since matches checks buggyQSA |
| 1180 | // A support test would require too much code (would include document ready) |
| 1181 | rbuggyQSA = [ ":focus" ]; |
| 1182 | |
| 1183 | if ( (support.qsa = isNative(doc.querySelectorAll)) ) { |
| 1184 | // Build QSA regex |
| 1185 | // Regex strategy adopted from Diego Perini |
| 1186 | assert(function( div ) { |
| 1187 | // Select is set to empty string on purpose |
| 1188 | // This is to test IE's treatment of not explicitly |
| 1189 | // setting a boolean content attribute, |
| 1190 | // since its presence should be enough |
| 1191 | // http://bugs.jquery.com/ticket/12359 |
| 1192 | div.innerHTML = "<select><option selected=''></option></select>"; |
| 1193 | |
| 1194 | // IE8 - Some boolean attributes are not treated correctly |
| 1195 | if ( !div.querySelectorAll("[selected]").length ) { |
| 1196 | rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); |
| 1197 | } |
| 1198 | |
| 1199 | // Webkit/Opera - :checked should return selected option elements |
| 1200 | // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked |
| 1201 | // IE8 throws error here and will not see later tests |
| 1202 | if ( !div.querySelectorAll(":checked").length ) { |
| 1203 | rbuggyQSA.push(":checked"); |
| 1204 | } |
| 1205 | }); |
| 1206 | |
| 1207 | assert(function( div ) { |
| 1208 | |
| 1209 | // Opera 10-12/IE8 - ^= $= *= and empty values |
| 1210 | // Should not select anything |
| 1211 | div.innerHTML = "<input type='hidden' i=''/>"; |
| 1212 | if ( div.querySelectorAll("[i^='']").length ) { |
| 1213 | rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); |
| 1214 | } |
| 1215 | |
| 1216 | // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) |
| 1217 | // IE8 throws error here and will not see later tests |
| 1218 | if ( !div.querySelectorAll(":enabled").length ) { |
| 1219 | rbuggyQSA.push( ":enabled", ":disabled" ); |
| 1220 | } |
| 1221 | |
| 1222 | // Opera 10-11 does not throw on post-comma invalid pseudos |
| 1223 | div.querySelectorAll("*,:x"); |
| 1224 | rbuggyQSA.push(",.*:"); |
| 1225 | }); |
| 1226 | } |
| 1227 | |
| 1228 | if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || |
| 1229 | docElem.mozMatchesSelector || |
| 1230 | docElem.webkitMatchesSelector || |
| 1231 | docElem.oMatchesSelector || |
| 1232 | docElem.msMatchesSelector) )) ) { |
| 1233 | |
| 1234 | assert(function( div ) { |
| 1235 | // Check to see if it's possible to do matchesSelector |
| 1236 | // on a disconnected node (IE 9) |
| 1237 | support.disconnectedMatch = matches.call( div, "div" ); |
| 1238 | |
| 1239 | // This should fail with an exception |
| 1240 | // Gecko does not error, returns false instead |
| 1241 | matches.call( div, "[s!='']:x" ); |
| 1242 | rbuggyMatches.push( "!=", pseudos ); |
| 1243 | }); |
| 1244 | } |
| 1245 | |
| 1246 | rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); |
| 1247 | rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); |
| 1248 | |
| 1249 | // Element contains another |
| 1250 | // Purposefully does not implement inclusive descendant |
| 1251 | // As in, an element does not contain itself |
| 1252 | contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? |
| 1253 | function( a, b ) { |
| 1254 | var adown = a.nodeType === 9 ? a.documentElement : a, |
| 1255 | bup = b && b.parentNode; |
| 1256 | return a === bup || !!( bup && bup.nodeType === 1 && ( |
| 1257 | adown.contains ? |
| 1258 | adown.contains( bup ) : |
| 1259 | a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 |
| 1260 | )); |
| 1261 | } : |
| 1262 | function( a, b ) { |
| 1263 | if ( b ) { |
| 1264 | while ( (b = b.parentNode) ) { |
| 1265 | if ( b === a ) { |
| 1266 | return true; |
| 1267 | } |
| 1268 | } |
| 1269 | } |
| 1270 | return false; |
| 1271 | }; |
| 1272 | |
| 1273 | // Document order sorting |
| 1274 | sortOrder = docElem.compareDocumentPosition ? |
| 1275 | function( a, b ) { |
| 1276 | |
| 1277 | // Flag for duplicate removal |
| 1278 | if ( a === b ) { |
| 1279 | hasDuplicate = true; |
| 1280 | return 0; |
| 1281 | } |
| 1282 | |
| 1283 | var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b ); |
| 1284 | |
| 1285 | if ( compare ) { |
| 1286 | // Disconnected nodes |
| 1287 | if ( compare & 1 || |
| 1288 | (recompare && b.compareDocumentPosition( a ) === compare) ) { |
| 1289 | |
| 1290 | // Choose the first element that is related to our preferred document |
| 1291 | if ( a === doc || contains(preferredDoc, a) ) { |
| 1292 | return -1; |
| 1293 | } |
| 1294 | if ( b === doc || contains(preferredDoc, b) ) { |
| 1295 | return 1; |
| 1296 | } |
| 1297 | |
| 1298 | // Maintain original order |
| 1299 | return sortInput ? |
| 1300 | ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : |
| 1301 | 0; |
| 1302 | } |
| 1303 | |
| 1304 | return compare & 4 ? -1 : 1; |
| 1305 | } |
| 1306 | |
| 1307 | // Not directly comparable, sort on existence of method |
| 1308 | return a.compareDocumentPosition ? -1 : 1; |
| 1309 | } : |
| 1310 | function( a, b ) { |
| 1311 | var cur, |
| 1312 | i = 0, |
| 1313 | aup = a.parentNode, |
| 1314 | bup = b.parentNode, |
| 1315 | ap = [ a ], |
| 1316 | bp = [ b ]; |
| 1317 | |
| 1318 | // Exit early if the nodes are identical |
| 1319 | if ( a === b ) { |
| 1320 | hasDuplicate = true; |
| 1321 | return 0; |
| 1322 | |
| 1323 | // Parentless nodes are either documents or disconnected |
| 1324 | } else if ( !aup || !bup ) { |
| 1325 | return a === doc ? -1 : |
| 1326 | b === doc ? 1 : |
| 1327 | aup ? -1 : |
| 1328 | bup ? 1 : |
| 1329 | 0; |
| 1330 | |
| 1331 | // If the nodes are siblings, we can do a quick check |
| 1332 | } else if ( aup === bup ) { |
| 1333 | return siblingCheck( a, b ); |
| 1334 | } |
| 1335 | |
| 1336 | // Otherwise we need full lists of their ancestors for comparison |
| 1337 | cur = a; |
| 1338 | while ( (cur = cur.parentNode) ) { |
| 1339 | ap.unshift( cur ); |
| 1340 | } |
| 1341 | cur = b; |
| 1342 | while ( (cur = cur.parentNode) ) { |
| 1343 | bp.unshift( cur ); |
| 1344 | } |
| 1345 | |
| 1346 | // Walk down the tree looking for a discrepancy |
| 1347 | while ( ap[i] === bp[i] ) { |
| 1348 | i++; |
| 1349 | } |
| 1350 | |
| 1351 | return i ? |
| 1352 | // Do a sibling check if the nodes have a common ancestor |
| 1353 | siblingCheck( ap[i], bp[i] ) : |
| 1354 | |
| 1355 | // Otherwise nodes in our document sort first |
| 1356 | ap[i] === preferredDoc ? -1 : |
| 1357 | bp[i] === preferredDoc ? 1 : |
| 1358 | 0; |
| 1359 | }; |
| 1360 | |
| 1361 | return document; |
| 1362 | }; |
| 1363 | |
| 1364 | Sizzle.matches = function( expr, elements ) { |
| 1365 | return Sizzle( expr, null, null, elements ); |
| 1366 | }; |
| 1367 | |
| 1368 | Sizzle.matchesSelector = function( elem, expr ) { |
| 1369 | // Set document vars if needed |
| 1370 | if ( ( elem.ownerDocument || elem ) !== document ) { |
| 1371 | setDocument( elem ); |
| 1372 | } |
| 1373 | |
| 1374 | // Make sure that attribute selectors are quoted |
| 1375 | expr = expr.replace( rattributeQuotes, "='$1']" ); |
| 1376 | |
| 1377 | // rbuggyQSA always contains :focus, so no need for an existence check |
| 1378 | if ( support.matchesSelector && documentIsHTML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { |
| 1379 | try { |
| 1380 | var ret = matches.call( elem, expr ); |
| 1381 | |
| 1382 | // IE 9's matchesSelector returns false on disconnected nodes |
| 1383 | if ( ret || support.disconnectedMatch || |
| 1384 | // As well, disconnected nodes are said to be in a document |
| 1385 | // fragment in IE 9 |
| 1386 | elem.document && elem.document.nodeType !== 11 ) { |
| 1387 | return ret; |
| 1388 | } |
| 1389 | } catch(e) {} |
| 1390 | } |
| 1391 | |
| 1392 | return Sizzle( expr, document, null, [elem] ).length > 0; |
| 1393 | }; |
| 1394 | |
| 1395 | Sizzle.contains = function( context, elem ) { |
| 1396 | // Set document vars if needed |
| 1397 | if ( ( context.ownerDocument || context ) !== document ) { |
| 1398 | setDocument( context ); |
| 1399 | } |
| 1400 | return contains( context, elem ); |
| 1401 | }; |
| 1402 | |
| 1403 | Sizzle.attr = function( elem, name ) { |
| 1404 | var val; |
| 1405 | |
| 1406 | // Set document vars if needed |
| 1407 | if ( ( elem.ownerDocument || elem ) !== document ) { |
| 1408 | setDocument( elem ); |
| 1409 | } |
| 1410 | |
| 1411 | if ( documentIsHTML ) { |
| 1412 | name = name.toLowerCase(); |
| 1413 | } |
| 1414 | if ( (val = Expr.attrHandle[ name ]) ) { |
| 1415 | return val( elem ); |
| 1416 | } |
| 1417 | if ( !documentIsHTML || support.attributes ) { |
| 1418 | return elem.getAttribute( name ); |
| 1419 | } |
| 1420 | return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? |
| 1421 | name : |
| 1422 | val && val.specified ? val.value : null; |
| 1423 | }; |
| 1424 | |
| 1425 | Sizzle.error = function( msg ) { |
| 1426 | throw new Error( "Syntax error, unrecognized expression: " + msg ); |
| 1427 | }; |
| 1428 | |
| 1429 | // Document sorting and removing duplicates |
| 1430 | Sizzle.uniqueSort = function( results ) { |
| 1431 | var elem, |
| 1432 | duplicates = [], |
| 1433 | j = 0, |
| 1434 | i = 0; |
| 1435 | |
| 1436 | // Unless we *know* we can detect duplicates, assume their presence |
| 1437 | hasDuplicate = !support.detectDuplicates; |
| 1438 | // Compensate for sort limitations |
| 1439 | recompare = !support.sortDetached; |
| 1440 | sortInput = !support.sortStable && results.slice( 0 ); |
| 1441 | results.sort( sortOrder ); |
| 1442 | |
| 1443 | if ( hasDuplicate ) { |
| 1444 | while ( (elem = results[i++]) ) { |
| 1445 | if ( elem === results[ i ] ) { |
| 1446 | j = duplicates.push( i ); |
| 1447 | } |
| 1448 | } |
| 1449 | while ( j-- ) { |
| 1450 | results.splice( duplicates[ j ], 1 ); |
| 1451 | } |
| 1452 | } |
| 1453 | |
| 1454 | return results; |
| 1455 | }; |
| 1456 | |
| 1457 | /** |
| 1458 | * Checks document order of two siblings |
| 1459 | * @param {Element} a |
| 1460 | * @param {Element} b |
| 1461 | * @returns Returns -1 if a precedes b, 1 if a follows b |
| 1462 | */ |
| 1463 | function siblingCheck( a, b ) { |
| 1464 | var cur = b && a, |
| 1465 | diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); |
| 1466 | |
| 1467 | // Use IE sourceIndex if available on both nodes |
| 1468 | if ( diff ) { |
| 1469 | return diff; |
| 1470 | } |
| 1471 | |
| 1472 | // Check if b follows a |
| 1473 | if ( cur ) { |
| 1474 | while ( (cur = cur.nextSibling) ) { |
| 1475 | if ( cur === b ) { |
| 1476 | return -1; |
| 1477 | } |
| 1478 | } |
| 1479 | } |
| 1480 | |
| 1481 | return a ? 1 : -1; |
| 1482 | } |
| 1483 | |
| 1484 | // Returns a function to use in pseudos for input types |
| 1485 | function createInputPseudo( type ) { |
| 1486 | return function( elem ) { |
| 1487 | var name = elem.nodeName.toLowerCase(); |
| 1488 | return name === "input" && elem.type === type; |
| 1489 | }; |
| 1490 | } |
| 1491 | |
| 1492 | // Returns a function to use in pseudos for buttons |
| 1493 | function createButtonPseudo( type ) { |
| 1494 | return function( elem ) { |
| 1495 | var name = elem.nodeName.toLowerCase(); |
| 1496 | return (name === "input" || name === "button") && elem.type === type; |
| 1497 | }; |
| 1498 | } |
| 1499 | |
| 1500 | // Returns a function to use in pseudos for positionals |
| 1501 | function createPositionalPseudo( fn ) { |
| 1502 | return markFunction(function( argument ) { |
| 1503 | argument = +argument; |
| 1504 | return markFunction(function( seed, matches ) { |
| 1505 | var j, |
| 1506 | matchIndexes = fn( [], seed.length, argument ), |
| 1507 | i = matchIndexes.length; |
| 1508 | |
| 1509 | // Match elements found at the specified indexes |
| 1510 | while ( i-- ) { |
| 1511 | if ( seed[ (j = matchIndexes[i]) ] ) { |
| 1512 | seed[j] = !(matches[j] = seed[j]); |
| 1513 | } |
| 1514 | } |
| 1515 | }); |
| 1516 | }); |
| 1517 | } |
| 1518 | |
| 1519 | /** |
| 1520 | * Utility function for retrieving the text value of an array of DOM nodes |
| 1521 | * @param {Array|Element} elem |
| 1522 | */ |
| 1523 | getText = Sizzle.getText = function( elem ) { |
| 1524 | var node, |
| 1525 | ret = "", |
| 1526 | i = 0, |
| 1527 | nodeType = elem.nodeType; |
| 1528 | |
| 1529 | if ( !nodeType ) { |
| 1530 | // If no nodeType, this is expected to be an array |
| 1531 | for ( ; (node = elem[i]); i++ ) { |
| 1532 | // Do not traverse comment nodes |
| 1533 | ret += getText( node ); |
| 1534 | } |
| 1535 | } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { |
| 1536 | // Use textContent for elements |
| 1537 | // innerText usage removed for consistency of new lines (see #11153) |
| 1538 | if ( typeof elem.textContent === "string" ) { |
| 1539 | return elem.textContent; |
| 1540 | } else { |
| 1541 | // Traverse its children |
| 1542 | for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { |
| 1543 | ret += getText( elem ); |
| 1544 | } |
| 1545 | } |
| 1546 | } else if ( nodeType === 3 || nodeType === 4 ) { |
| 1547 | return elem.nodeValue; |
| 1548 | } |
| 1549 | // Do not include comment or processing instruction nodes |
| 1550 | |
| 1551 | return ret; |
| 1552 | }; |
| 1553 | |
| 1554 | Expr = Sizzle.selectors = { |
| 1555 | |
| 1556 | // Can be adjusted by the user |
| 1557 | cacheLength: 50, |
| 1558 | |
| 1559 | createPseudo: markFunction, |
| 1560 | |
| 1561 | match: matchExpr, |
| 1562 | |
| 1563 | find: {}, |
| 1564 | |
| 1565 | relative: { |
| 1566 | ">": { dir: "parentNode", first: true }, |
| 1567 | " ": { dir: "parentNode" }, |
| 1568 | "+": { dir: "previousSibling", first: true }, |
| 1569 | "~": { dir: "previousSibling" } |
| 1570 | }, |
| 1571 | |
| 1572 | preFilter: { |
| 1573 | "ATTR": function( match ) { |
| 1574 | match[1] = match[1].replace( runescape, funescape ); |
| 1575 | |
| 1576 | // Move the given value to match[3] whether quoted or unquoted |
| 1577 | match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); |
| 1578 | |
| 1579 | if ( match[2] === "~=" ) { |
| 1580 | match[3] = " " + match[3] + " "; |
| 1581 | } |
| 1582 | |
| 1583 | return match.slice( 0, 4 ); |
| 1584 | }, |
| 1585 | |
| 1586 | "CHILD": function( match ) { |
| 1587 | /* matches from matchExpr["CHILD"] |
| 1588 | 1 type (only|nth|...) |
| 1589 | 2 what (child|of-type) |
| 1590 | 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) |
| 1591 | 4 xn-component of xn+y argument ([+-]?\d*n|) |
| 1592 | 5 sign of xn-component |
| 1593 | 6 x of xn-component |
| 1594 | 7 sign of y-component |
| 1595 | 8 y of y-component |
| 1596 | */ |
| 1597 | match[1] = match[1].toLowerCase(); |
| 1598 | |
| 1599 | if ( match[1].slice( 0, 3 ) === "nth" ) { |
| 1600 | // nth-* requires argument |
| 1601 | if ( !match[3] ) { |
| 1602 | Sizzle.error( match[0] ); |
| 1603 | } |
| 1604 | |
| 1605 | // numeric x and y parameters for Expr.filter.CHILD |
| 1606 | // remember that false/true cast respectively to 0/1 |
| 1607 | match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); |
| 1608 | match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); |
| 1609 | |
| 1610 | // other types prohibit arguments |
| 1611 | } else if ( match[3] ) { |
| 1612 | Sizzle.error( match[0] ); |
| 1613 | } |
| 1614 | |
| 1615 | return match; |
| 1616 | }, |
| 1617 | |
| 1618 | "PSEUDO": function( match ) { |
| 1619 | var excess, |
| 1620 | unquoted = !match[5] && match[2]; |
| 1621 | |
| 1622 | if ( matchExpr["CHILD"].test( match[0] ) ) { |
| 1623 | return null; |
| 1624 | } |
| 1625 | |
| 1626 | // Accept quoted arguments as-is |
| 1627 | if ( match[4] ) { |
| 1628 | match[2] = match[4]; |
| 1629 | |
| 1630 | // Strip excess characters from unquoted arguments |
| 1631 | } else if ( unquoted && rpseudo.test( unquoted ) && |
| 1632 | // Get excess from tokenize (recursively) |
| 1633 | (excess = tokenize( unquoted, true )) && |
| 1634 | // advance to the next closing parenthesis |
| 1635 | (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { |
| 1636 | |
| 1637 | // excess is a negative index |
| 1638 | match[0] = match[0].slice( 0, excess ); |
| 1639 | match[2] = unquoted.slice( 0, excess ); |
| 1640 | } |
| 1641 | |
| 1642 | // Return only captures needed by the pseudo filter method (type and argument) |
| 1643 | return match.slice( 0, 3 ); |
| 1644 | } |
| 1645 | }, |
| 1646 | |
| 1647 | filter: { |
| 1648 | |
| 1649 | "TAG": function( nodeName ) { |
| 1650 | if ( nodeName === "*" ) { |
| 1651 | return function() { return true; }; |
| 1652 | } |
| 1653 | |
| 1654 | nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); |
| 1655 | return function( elem ) { |
| 1656 | return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; |
| 1657 | }; |
| 1658 | }, |
| 1659 | |
| 1660 | "CLASS": function( className ) { |
| 1661 | var pattern = classCache[ className + " " ]; |
| 1662 | |
| 1663 | return pattern || |
| 1664 | (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && |
| 1665 | classCache( className, function( elem ) { |
| 1666 | return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); |
| 1667 | }); |
| 1668 | }, |
| 1669 | |
| 1670 | "ATTR": function( name, operator, check ) { |
| 1671 | return function( elem ) { |
| 1672 | var result = Sizzle.attr( elem, name ); |
| 1673 | |
| 1674 | if ( result == null ) { |
| 1675 | return operator === "!="; |
| 1676 | } |
| 1677 | if ( !operator ) { |
| 1678 | return true; |
| 1679 | } |
| 1680 | |
| 1681 | result += ""; |
| 1682 | |
| 1683 | return operator === "=" ? result === check : |
| 1684 | operator === "!=" ? result !== check : |
| 1685 | operator === "^=" ? check && result.indexOf( check ) === 0 : |
| 1686 | operator === "*=" ? check && result.indexOf( check ) > -1 : |
| 1687 | operator === "$=" ? check && result.slice( -check.length ) === check : |
| 1688 | operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : |
| 1689 | operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : |
| 1690 | false; |
| 1691 | }; |
| 1692 | }, |
| 1693 | |
| 1694 | "CHILD": function( type, what, argument, first, last ) { |
| 1695 | var simple = type.slice( 0, 3 ) !== "nth", |
| 1696 | forward = type.slice( -4 ) !== "last", |
| 1697 | ofType = what === "of-type"; |
| 1698 | |
| 1699 | return first === 1 && last === 0 ? |
| 1700 | |
| 1701 | // Shortcut for :nth-*(n) |
| 1702 | function( elem ) { |
| 1703 | return !!elem.parentNode; |
| 1704 | } : |
| 1705 | |
| 1706 | function( elem, context, xml ) { |
| 1707 | var cache, outerCache, node, diff, nodeIndex, start, |
| 1708 | dir = simple !== forward ? "nextSibling" : "previousSibling", |
| 1709 | parent = elem.parentNode, |
| 1710 | name = ofType && elem.nodeName.toLowerCase(), |
| 1711 | useCache = !xml && !ofType; |
| 1712 | |
| 1713 | if ( parent ) { |
| 1714 | |
| 1715 | // :(first|last|only)-(child|of-type) |
| 1716 | if ( simple ) { |
| 1717 | while ( dir ) { |
| 1718 | node = elem; |
| 1719 | while ( (node = node[ dir ]) ) { |
| 1720 | if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { |
| 1721 | return false; |
| 1722 | } |
| 1723 | } |
| 1724 | // Reverse direction for :only-* (if we haven't yet done so) |
| 1725 | start = dir = type === "only" && !start && "nextSibling"; |
| 1726 | } |
| 1727 | return true; |
| 1728 | } |
| 1729 | |
| 1730 | start = [ forward ? parent.firstChild : parent.lastChild ]; |
| 1731 | |
| 1732 | // non-xml :nth-child(...) stores cache data on `parent` |
| 1733 | if ( forward && useCache ) { |
| 1734 | // Seek `elem` from a previously-cached index |
| 1735 | outerCache = parent[ expando ] || (parent[ expando ] = {}); |
| 1736 | cache = outerCache[ type ] || []; |
| 1737 | nodeIndex = cache[0] === dirruns && cache[1]; |
| 1738 | diff = cache[0] === dirruns && cache[2]; |
| 1739 | node = nodeIndex && parent.childNodes[ nodeIndex ]; |
| 1740 | |
| 1741 | while ( (node = ++nodeIndex && node && node[ dir ] || |
| 1742 | |
| 1743 | // Fallback to seeking `elem` from the start |
| 1744 | (diff = nodeIndex = 0) || start.pop()) ) { |
| 1745 | |
| 1746 | // When found, cache indexes on `parent` and break |
| 1747 | if ( node.nodeType === 1 && ++diff && node === elem ) { |
| 1748 | outerCache[ type ] = [ dirruns, nodeIndex, diff ]; |
| 1749 | break; |
| 1750 | } |
| 1751 | } |
| 1752 | |
| 1753 | // Use previously-cached element index if available |
| 1754 | } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { |
| 1755 | diff = cache[1]; |
| 1756 | |
| 1757 | // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) |
| 1758 | } else { |
| 1759 | // Use the same loop as above to seek `elem` from the start |
| 1760 | while ( (node = ++nodeIndex && node && node[ dir ] || |
| 1761 | (diff = nodeIndex = 0) || start.pop()) ) { |
| 1762 | |
| 1763 | if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { |
| 1764 | // Cache the index of each encountered element |
| 1765 | if ( useCache ) { |
| 1766 | (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; |
| 1767 | } |
| 1768 | |
| 1769 | if ( node === elem ) { |
| 1770 | break; |
| 1771 | } |
| 1772 | } |
| 1773 | } |
| 1774 | } |
| 1775 | |
| 1776 | // Incorporate the offset, then check against cycle size |
| 1777 | diff -= last; |
| 1778 | return diff === first || ( diff % first === 0 && diff / first >= 0 ); |
| 1779 | } |
| 1780 | }; |
| 1781 | }, |
| 1782 | |
| 1783 | "PSEUDO": function( pseudo, argument ) { |
| 1784 | // pseudo-class names are case-insensitive |
| 1785 | // http://www.w3.org/TR/selectors/#pseudo-classes |
| 1786 | // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters |
| 1787 | // Remember that setFilters inherits from pseudos |
| 1788 | var args, |
| 1789 | fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || |
| 1790 | Sizzle.error( "unsupported pseudo: " + pseudo ); |
| 1791 | |
| 1792 | // The user may use createPseudo to indicate that |
| 1793 | // arguments are needed to create the filter function |
| 1794 | // just as Sizzle does |
| 1795 | if ( fn[ expando ] ) { |
| 1796 | return fn( argument ); |
| 1797 | } |
| 1798 | |
| 1799 | // But maintain support for old signatures |
| 1800 | if ( fn.length > 1 ) { |
| 1801 | args = [ pseudo, pseudo, "", argument ]; |
| 1802 | return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? |
| 1803 | markFunction(function( seed, matches ) { |
| 1804 | var idx, |
| 1805 | matched = fn( seed, argument ), |
| 1806 | i = matched.length; |
| 1807 | while ( i-- ) { |
| 1808 | idx = indexOf.call( seed, matched[i] ); |
| 1809 | seed[ idx ] = !( matches[ idx ] = matched[i] ); |
| 1810 | } |
| 1811 | }) : |
| 1812 | function( elem ) { |
| 1813 | return fn( elem, 0, args ); |
| 1814 | }; |
| 1815 | } |
| 1816 | |
| 1817 | return fn; |
| 1818 | } |
| 1819 | }, |
| 1820 | |
| 1821 | pseudos: { |
| 1822 | // Potentially complex pseudos |
| 1823 | "not": markFunction(function( selector ) { |
| 1824 | // Trim the selector passed to compile |
| 1825 | // to avoid treating leading and trailing |
| 1826 | // spaces as combinators |
| 1827 | var input = [], |
| 1828 | results = [], |
| 1829 | matcher = compile( selector.replace( rtrim, "$1" ) ); |
| 1830 | |
| 1831 | return matcher[ expando ] ? |
| 1832 | markFunction(function( seed, matches, context, xml ) { |
| 1833 | var elem, |
| 1834 | unmatched = matcher( seed, null, xml, [] ), |
| 1835 | i = seed.length; |
| 1836 | |
| 1837 | // Match elements unmatched by `matcher` |
| 1838 | while ( i-- ) { |
| 1839 | if ( (elem = unmatched[i]) ) { |
| 1840 | seed[i] = !(matches[i] = elem); |
| 1841 | } |
| 1842 | } |
| 1843 | }) : |
| 1844 | function( elem, context, xml ) { |
| 1845 | input[0] = elem; |
| 1846 | matcher( input, null, xml, results ); |
| 1847 | return !results.pop(); |
| 1848 | }; |
| 1849 | }), |
| 1850 | |
| 1851 | "has": markFunction(function( selector ) { |
| 1852 | return function( elem ) { |
| 1853 | return Sizzle( selector, elem ).length > 0; |
| 1854 | }; |
| 1855 | }), |
| 1856 | |
| 1857 | "contains": markFunction(function( text ) { |
| 1858 | return function( elem ) { |
| 1859 | return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; |
| 1860 | }; |
| 1861 | }), |
| 1862 | |
| 1863 | // "Whether an element is represented by a :lang() selector |
| 1864 | // is based solely on the element's language value |
| 1865 | // being equal to the identifier C, |
| 1866 | // or beginning with the identifier C immediately followed by "-". |
| 1867 | // The matching of C against the element's language value is performed case-insensitively. |
| 1868 | // The identifier C does not have to be a valid language name." |
| 1869 | // http://www.w3.org/TR/selectors/#lang-pseudo |
| 1870 | "lang": markFunction( function( lang ) { |
| 1871 | // lang value must be a valid identifier |
| 1872 | if ( !ridentifier.test(lang || "") ) { |
| 1873 | Sizzle.error( "unsupported lang: " + lang ); |
| 1874 | } |
| 1875 | lang = lang.replace( runescape, funescape ).toLowerCase(); |
| 1876 | return function( elem ) { |
| 1877 | var elemLang; |
| 1878 | do { |
| 1879 | if ( (elemLang = documentIsHTML ? |
| 1880 | elem.lang : |
| 1881 | elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { |
| 1882 | |
| 1883 | elemLang = elemLang.toLowerCase(); |
| 1884 | return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; |
| 1885 | } |
| 1886 | } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); |
| 1887 | return false; |
| 1888 | }; |
| 1889 | }), |
| 1890 | |
| 1891 | // Miscellaneous |
| 1892 | "target": function( elem ) { |
| 1893 | var hash = window.location && window.location.hash; |
| 1894 | return hash && hash.slice( 1 ) === elem.id; |
| 1895 | }, |
| 1896 | |
| 1897 | "root": function( elem ) { |
| 1898 | return elem === docElem; |
| 1899 | }, |
| 1900 | |
| 1901 | "focus": function( elem ) { |
| 1902 | return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); |
| 1903 | }, |
| 1904 | |
| 1905 | // Boolean properties |
| 1906 | "enabled": function( elem ) { |
| 1907 | return elem.disabled === false; |
| 1908 | }, |
| 1909 | |
| 1910 | "disabled": function( elem ) { |
| 1911 | return elem.disabled === true; |
| 1912 | }, |
| 1913 | |
| 1914 | "checked": function( elem ) { |
| 1915 | // In CSS3, :checked should return both checked and selected elements |
| 1916 | // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked |
| 1917 | var nodeName = elem.nodeName.toLowerCase(); |
| 1918 | return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); |
| 1919 | }, |
| 1920 | |
| 1921 | "selected": function( elem ) { |
| 1922 | // Accessing this property makes selected-by-default |
| 1923 | // options in Safari work properly |
| 1924 | if ( elem.parentNode ) { |
| 1925 | elem.parentNode.selectedIndex; |
| 1926 | } |
| 1927 | |
| 1928 | return elem.selected === true; |
| 1929 | }, |
| 1930 | |
| 1931 | // Contents |
| 1932 | "empty": function( elem ) { |
| 1933 | // http://www.w3.org/TR/selectors/#empty-pseudo |
| 1934 | // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), |
| 1935 | // not comment, processing instructions, or others |
| 1936 | // Thanks to Diego Perini for the nodeName shortcut |
| 1937 | // Greater than "@" means alpha characters (specifically not starting with "#" or "?") |
| 1938 | for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { |
| 1939 | if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { |
| 1940 | return false; |
| 1941 | } |
| 1942 | } |
| 1943 | return true; |
| 1944 | }, |
| 1945 | |
| 1946 | "parent": function( elem ) { |
| 1947 | return !Expr.pseudos["empty"]( elem ); |
| 1948 | }, |
| 1949 | |
| 1950 | // Element/input types |
| 1951 | "header": function( elem ) { |
| 1952 | return rheader.test( elem.nodeName ); |
| 1953 | }, |
| 1954 | |
| 1955 | "input": function( elem ) { |
| 1956 | return rinputs.test( elem.nodeName ); |
| 1957 | }, |
| 1958 | |
| 1959 | "button": function( elem ) { |
| 1960 | var name = elem.nodeName.toLowerCase(); |
| 1961 | return name === "input" && elem.type === "button" || name === "button"; |
| 1962 | }, |
| 1963 | |
| 1964 | "text": function( elem ) { |
| 1965 | var attr; |
| 1966 | // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) |
| 1967 | // use getAttribute instead to test this case |
| 1968 | return elem.nodeName.toLowerCase() === "input" && |
| 1969 | elem.type === "text" && |
| 1970 | ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); |
| 1971 | }, |
| 1972 | |
| 1973 | // Position-in-collection |
| 1974 | "first": createPositionalPseudo(function() { |
| 1975 | return [ 0 ]; |
| 1976 | }), |
| 1977 | |
| 1978 | "last": createPositionalPseudo(function( matchIndexes, length ) { |
| 1979 | return [ length - 1 ]; |
| 1980 | }), |
| 1981 | |
| 1982 | "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { |
| 1983 | return [ argument < 0 ? argument + length : argument ]; |
| 1984 | }), |
| 1985 | |
| 1986 | "even": createPositionalPseudo(function( matchIndexes, length ) { |
| 1987 | var i = 0; |
| 1988 | for ( ; i < length; i += 2 ) { |
| 1989 | matchIndexes.push( i ); |
| 1990 | } |
| 1991 | return matchIndexes; |
| 1992 | }), |
| 1993 | |
| 1994 | "odd": createPositionalPseudo(function( matchIndexes, length ) { |
| 1995 | var i = 1; |
| 1996 | for ( ; i < length; i += 2 ) { |
| 1997 | matchIndexes.push( i ); |
| 1998 | } |
| 1999 | return matchIndexes; |
| 2000 | }), |
| 2001 | |
| 2002 | "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { |
| 2003 | var i = argument < 0 ? argument + length : argument; |
| 2004 | for ( ; --i >= 0; ) { |
| 2005 | matchIndexes.push( i ); |
| 2006 | } |
| 2007 | return matchIndexes; |
| 2008 | }), |
| 2009 | |
| 2010 | "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { |
| 2011 | var i = argument < 0 ? argument + length : argument; |
| 2012 | for ( ; ++i < length; ) { |
| 2013 | matchIndexes.push( i ); |
| 2014 | } |
| 2015 | return matchIndexes; |
| 2016 | }) |
| 2017 | } |
| 2018 | }; |
| 2019 | |
| 2020 | // Add button/input type pseudos |
| 2021 | for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { |
| 2022 | Expr.pseudos[ i ] = createInputPseudo( i ); |
| 2023 | } |
| 2024 | for ( i in { submit: true, reset: true } ) { |
| 2025 | Expr.pseudos[ i ] = createButtonPseudo( i ); |
| 2026 | } |
| 2027 | |
| 2028 | function tokenize( selector, parseOnly ) { |
| 2029 | var matched, match, tokens, type, |
| 2030 | soFar, groups, preFilters, |
| 2031 | cached = tokenCache[ selector + " " ]; |
| 2032 | |
| 2033 | if ( cached ) { |
| 2034 | return parseOnly ? 0 : cached.slice( 0 ); |
| 2035 | } |
| 2036 | |
| 2037 | soFar = selector; |
| 2038 | groups = []; |
| 2039 | preFilters = Expr.preFilter; |
| 2040 | |
| 2041 | while ( soFar ) { |
| 2042 | |
| 2043 | // Comma and first run |
| 2044 | if ( !matched || (match = rcomma.exec( soFar )) ) { |
| 2045 | if ( match ) { |
| 2046 | // Don't consume trailing commas as valid |
| 2047 | soFar = soFar.slice( match[0].length ) || soFar; |
| 2048 | } |
| 2049 | groups.push( tokens = [] ); |
| 2050 | } |
| 2051 | |
| 2052 | matched = false; |
| 2053 | |
| 2054 | // Combinators |
| 2055 | if ( (match = rcombinators.exec( soFar )) ) { |
| 2056 | matched = match.shift(); |
| 2057 | tokens.push( { |
| 2058 | value: matched, |
| 2059 | // Cast descendant combinators to space |
| 2060 | type: match[0].replace( rtrim, " " ) |
| 2061 | } ); |
| 2062 | soFar = soFar.slice( matched.length ); |
| 2063 | } |
| 2064 | |
| 2065 | // Filters |
| 2066 | for ( type in Expr.filter ) { |
| 2067 | if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || |
| 2068 | (match = preFilters[ type ]( match ))) ) { |
| 2069 | matched = match.shift(); |
| 2070 | tokens.push( { |
| 2071 | value: matched, |
| 2072 | type: type, |
| 2073 | matches: match |
| 2074 | } ); |
| 2075 | soFar = soFar.slice( matched.length ); |
| 2076 | } |
| 2077 | } |
| 2078 | |
| 2079 | if ( !matched ) { |
| 2080 | break; |
| 2081 | } |
| 2082 | } |
| 2083 | |
| 2084 | // Return the length of the invalid excess |
| 2085 | // if we're just parsing |
| 2086 | // Otherwise, throw an error or return tokens |
| 2087 | return parseOnly ? |
| 2088 | soFar.length : |
| 2089 | soFar ? |
| 2090 | Sizzle.error( selector ) : |
| 2091 | // Cache the tokens |
| 2092 | tokenCache( selector, groups ).slice( 0 ); |
| 2093 | } |
| 2094 | |
| 2095 | function toSelector( tokens ) { |
| 2096 | var i = 0, |
| 2097 | len = tokens.length, |
| 2098 | selector = ""; |
| 2099 | for ( ; i < len; i++ ) { |
| 2100 | selector += tokens[i].value; |
| 2101 | } |
| 2102 | return selector; |
| 2103 | } |
| 2104 | |
| 2105 | function addCombinator( matcher, combinator, base ) { |
| 2106 | var dir = combinator.dir, |
| 2107 | checkNonElements = base && dir === "parentNode", |
| 2108 | doneName = done++; |
| 2109 | |
| 2110 | return combinator.first ? |
| 2111 | // Check against closest ancestor/preceding element |
| 2112 | function( elem, context, xml ) { |
| 2113 | while ( (elem = elem[ dir ]) ) { |
| 2114 | if ( elem.nodeType === 1 || checkNonElements ) { |
| 2115 | return matcher( elem, context, xml ); |
| 2116 | } |
| 2117 | } |
| 2118 | } : |
| 2119 | |
| 2120 | // Check against all ancestor/preceding elements |
| 2121 | function( elem, context, xml ) { |
| 2122 | var data, cache, outerCache, |
| 2123 | dirkey = dirruns + " " + doneName; |
| 2124 | |
| 2125 | // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching |
| 2126 | if ( xml ) { |
| 2127 | while ( (elem = elem[ dir ]) ) { |
| 2128 | if ( elem.nodeType === 1 || checkNonElements ) { |
| 2129 | if ( matcher( elem, context, xml ) ) { |
| 2130 | return true; |
| 2131 | } |
| 2132 | } |
| 2133 | } |
| 2134 | } else { |
| 2135 | while ( (elem = elem[ dir ]) ) { |
| 2136 | if ( elem.nodeType === 1 || checkNonElements ) { |
| 2137 | outerCache = elem[ expando ] || (elem[ expando ] = {}); |
| 2138 | if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { |
| 2139 | if ( (data = cache[1]) === true || data === cachedruns ) { |
| 2140 | return data === true; |
| 2141 | } |
| 2142 | } else { |
| 2143 | cache = outerCache[ dir ] = [ dirkey ]; |
| 2144 | cache[1] = matcher( elem, context, xml ) || cachedruns; |
| 2145 | if ( cache[1] === true ) { |
| 2146 | return true; |
| 2147 | } |
| 2148 | } |
| 2149 | } |
| 2150 | } |
| 2151 | } |
| 2152 | }; |
| 2153 | } |
| 2154 | |
| 2155 | function elementMatcher( matchers ) { |
| 2156 | return matchers.length > 1 ? |
| 2157 | function( elem, context, xml ) { |
| 2158 | var i = matchers.length; |
| 2159 | while ( i-- ) { |
| 2160 | if ( !matchers[i]( elem, context, xml ) ) { |
| 2161 | return false; |
| 2162 | } |
| 2163 | } |
| 2164 | return true; |
| 2165 | } : |
| 2166 | matchers[0]; |
| 2167 | } |
| 2168 | |
| 2169 | function condense( unmatched, map, filter, context, xml ) { |
| 2170 | var elem, |
| 2171 | newUnmatched = [], |
| 2172 | i = 0, |
| 2173 | len = unmatched.length, |
| 2174 | mapped = map != null; |
| 2175 | |
| 2176 | for ( ; i < len; i++ ) { |
| 2177 | if ( (elem = unmatched[i]) ) { |
| 2178 | if ( !filter || filter( elem, context, xml ) ) { |
| 2179 | newUnmatched.push( elem ); |
| 2180 | if ( mapped ) { |
| 2181 | map.push( i ); |
| 2182 | } |
| 2183 | } |
| 2184 | } |
| 2185 | } |
| 2186 | |
| 2187 | return newUnmatched; |
| 2188 | } |
| 2189 | |
| 2190 | function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { |
| 2191 | if ( postFilter && !postFilter[ expando ] ) { |
| 2192 | postFilter = setMatcher( postFilter ); |
| 2193 | } |
| 2194 | if ( postFinder && !postFinder[ expando ] ) { |
| 2195 | postFinder = setMatcher( postFinder, postSelector ); |
| 2196 | } |
| 2197 | return markFunction(function( seed, results, context, xml ) { |
| 2198 | var temp, i, elem, |
| 2199 | preMap = [], |
| 2200 | postMap = [], |
| 2201 | preexisting = results.length, |
| 2202 | |
| 2203 | // Get initial elements from seed or context |
| 2204 | elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), |
| 2205 | |
| 2206 | // Prefilter to get matcher input, preserving a map for seed-results synchronization |
| 2207 | matcherIn = preFilter && ( seed || !selector ) ? |
| 2208 | condense( elems, preMap, preFilter, context, xml ) : |
| 2209 | elems, |
| 2210 | |
| 2211 | matcherOut = matcher ? |
| 2212 | // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, |
| 2213 | postFinder || ( seed ? preFilter : preexisting || postFilter ) ? |
| 2214 | |
| 2215 | // ...intermediate processing is necessary |
| 2216 | [] : |
| 2217 | |
| 2218 | // ...otherwise use results directly |
| 2219 | results : |
| 2220 | matcherIn; |
| 2221 | |
| 2222 | // Find primary matches |
| 2223 | if ( matcher ) { |
| 2224 | matcher( matcherIn, matcherOut, context, xml ); |
| 2225 | } |
| 2226 | |
| 2227 | // Apply postFilter |
| 2228 | if ( postFilter ) { |
| 2229 | temp = condense( matcherOut, postMap ); |
| 2230 | postFilter( temp, [], context, xml ); |
| 2231 | |
| 2232 | // Un-match failing elements by moving them back to matcherIn |
| 2233 | i = temp.length; |
| 2234 | while ( i-- ) { |
| 2235 | if ( (elem = temp[i]) ) { |
| 2236 | matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); |
| 2237 | } |
| 2238 | } |
| 2239 | } |
| 2240 | |
| 2241 | if ( seed ) { |
| 2242 | if ( postFinder || preFilter ) { |
| 2243 | if ( postFinder ) { |
| 2244 | // Get the final matcherOut by condensing this intermediate into postFinder contexts |
| 2245 | temp = []; |
| 2246 | i = matcherOut.length; |
| 2247 | while ( i-- ) { |
| 2248 | if ( (elem = matcherOut[i]) ) { |
| 2249 | // Restore matcherIn since elem is not yet a final match |
| 2250 | temp.push( (matcherIn[i] = elem) ); |
| 2251 | } |
| 2252 | } |
| 2253 | postFinder( null, (matcherOut = []), temp, xml ); |
| 2254 | } |
| 2255 | |
| 2256 | // Move matched elements from seed to results to keep them synchronized |
| 2257 | i = matcherOut.length; |
| 2258 | while ( i-- ) { |
| 2259 | if ( (elem = matcherOut[i]) && |
| 2260 | (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { |
| 2261 | |
| 2262 | seed[temp] = !(results[temp] = elem); |
| 2263 | } |
| 2264 | } |
| 2265 | } |
| 2266 | |
| 2267 | // Add elements to results, through postFinder if defined |
| 2268 | } else { |
| 2269 | matcherOut = condense( |
| 2270 | matcherOut === results ? |
| 2271 | matcherOut.splice( preexisting, matcherOut.length ) : |
| 2272 | matcherOut |
| 2273 | ); |
| 2274 | if ( postFinder ) { |
| 2275 | postFinder( null, results, matcherOut, xml ); |
| 2276 | } else { |
| 2277 | push.apply( results, matcherOut ); |
| 2278 | } |
| 2279 | } |
| 2280 | }); |
| 2281 | } |
| 2282 | |
| 2283 | function matcherFromTokens( tokens ) { |
| 2284 | var checkContext, matcher, j, |
| 2285 | len = tokens.length, |
| 2286 | leadingRelative = Expr.relative[ tokens[0].type ], |
| 2287 | implicitRelative = leadingRelative || Expr.relative[" "], |
| 2288 | i = leadingRelative ? 1 : 0, |
| 2289 | |
| 2290 | // The foundational matcher ensures that elements are reachable from top-level context(s) |
| 2291 | matchContext = addCombinator( function( elem ) { |
| 2292 | return elem === checkContext; |
| 2293 | }, implicitRelative, true ), |
| 2294 | matchAnyContext = addCombinator( function( elem ) { |
| 2295 | return indexOf.call( checkContext, elem ) > -1; |
| 2296 | }, implicitRelative, true ), |
| 2297 | matchers = [ function( elem, context, xml ) { |
| 2298 | return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( |
| 2299 | (checkContext = context).nodeType ? |
| 2300 | matchContext( elem, context, xml ) : |
| 2301 | matchAnyContext( elem, context, xml ) ); |
| 2302 | } ]; |
| 2303 | |
| 2304 | for ( ; i < len; i++ ) { |
| 2305 | if ( (matcher = Expr.relative[ tokens[i].type ]) ) { |
| 2306 | matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; |
| 2307 | } else { |
| 2308 | matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); |
| 2309 | |
| 2310 | // Return special upon seeing a positional matcher |
| 2311 | if ( matcher[ expando ] ) { |
| 2312 | // Find the next relative operator (if any) for proper handling |
| 2313 | j = ++i; |
| 2314 | for ( ; j < len; j++ ) { |
| 2315 | if ( Expr.relative[ tokens[j].type ] ) { |
| 2316 | break; |
| 2317 | } |
| 2318 | } |
| 2319 | return setMatcher( |
| 2320 | i > 1 && elementMatcher( matchers ), |
| 2321 | i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), |
| 2322 | matcher, |
| 2323 | i < j && matcherFromTokens( tokens.slice( i, j ) ), |
| 2324 | j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), |
| 2325 | j < len && toSelector( tokens ) |
| 2326 | ); |
| 2327 | } |
| 2328 | matchers.push( matcher ); |
| 2329 | } |
| 2330 | } |
| 2331 | |
| 2332 | return elementMatcher( matchers ); |
| 2333 | } |
| 2334 | |
| 2335 | function matcherFromGroupMatchers( elementMatchers, setMatchers ) { |
| 2336 | // A counter to specify which element is currently being matched |
| 2337 | var matcherCachedRuns = 0, |
| 2338 | bySet = setMatchers.length > 0, |
| 2339 | byElement = elementMatchers.length > 0, |
| 2340 | superMatcher = function( seed, context, xml, results, expandContext ) { |
| 2341 | var elem, j, matcher, |
| 2342 | setMatched = [], |
| 2343 | matchedCount = 0, |
| 2344 | i = "0", |
| 2345 | unmatched = seed && [], |
| 2346 | outermost = expandContext != null, |
| 2347 | contextBackup = outermostContext, |
| 2348 | // We must always have either seed elements or context |
| 2349 | elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), |
| 2350 | // Use integer dirruns iff this is the outermost matcher |
| 2351 | dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); |
| 2352 | |
| 2353 | if ( outermost ) { |
| 2354 | outermostContext = context !== document && context; |
| 2355 | cachedruns = matcherCachedRuns; |
| 2356 | } |
| 2357 | |
| 2358 | // Add elements passing elementMatchers directly to results |
| 2359 | // Keep `i` a string if there are no elements so `matchedCount` will be "00" below |
| 2360 | for ( ; (elem = elems[i]) != null; i++ ) { |
| 2361 | if ( byElement && elem ) { |
| 2362 | j = 0; |
| 2363 | while ( (matcher = elementMatchers[j++]) ) { |
| 2364 | if ( matcher( elem, context, xml ) ) { |
| 2365 | results.push( elem ); |
| 2366 | break; |
| 2367 | } |
| 2368 | } |
| 2369 | if ( outermost ) { |
| 2370 | dirruns = dirrunsUnique; |
| 2371 | cachedruns = ++matcherCachedRuns; |
| 2372 | } |
| 2373 | } |
| 2374 | |
| 2375 | // Track unmatched elements for set filters |
| 2376 | if ( bySet ) { |
| 2377 | // They will have gone through all possible matchers |
| 2378 | if ( (elem = !matcher && elem) ) { |
| 2379 | matchedCount--; |
| 2380 | } |
| 2381 | |
| 2382 | // Lengthen the array for every element, matched or not |
| 2383 | if ( seed ) { |
| 2384 | unmatched.push( elem ); |
| 2385 | } |
| 2386 | } |
| 2387 | } |
| 2388 | |
| 2389 | // Apply set filters to unmatched elements |
| 2390 | matchedCount += i; |
| 2391 | if ( bySet && i !== matchedCount ) { |
| 2392 | j = 0; |
| 2393 | while ( (matcher = setMatchers[j++]) ) { |
| 2394 | matcher( unmatched, setMatched, context, xml ); |
| 2395 | } |
| 2396 | |
| 2397 | if ( seed ) { |
| 2398 | // Reintegrate element matches to eliminate the need for sorting |
| 2399 | if ( matchedCount > 0 ) { |
| 2400 | while ( i-- ) { |
| 2401 | if ( !(unmatched[i] || setMatched[i]) ) { |
| 2402 | setMatched[i] = pop.call( results ); |
| 2403 | } |
| 2404 | } |
| 2405 | } |
| 2406 | |
| 2407 | // Discard index placeholder values to get only actual matches |
| 2408 | setMatched = condense( setMatched ); |
| 2409 | } |
| 2410 | |
| 2411 | // Add matches to results |
| 2412 | push.apply( results, setMatched ); |
| 2413 | |
| 2414 | // Seedless set matches succeeding multiple successful matchers stipulate sorting |
| 2415 | if ( outermost && !seed && setMatched.length > 0 && |
| 2416 | ( matchedCount + setMatchers.length ) > 1 ) { |
| 2417 | |
| 2418 | Sizzle.uniqueSort( results ); |
| 2419 | } |
| 2420 | } |
| 2421 | |
| 2422 | // Override manipulation of globals by nested matchers |
| 2423 | if ( outermost ) { |
| 2424 | dirruns = dirrunsUnique; |
| 2425 | outermostContext = contextBackup; |
| 2426 | } |
| 2427 | |
| 2428 | return unmatched; |
| 2429 | }; |
| 2430 | |
| 2431 | return bySet ? |
| 2432 | markFunction( superMatcher ) : |
| 2433 | superMatcher; |
| 2434 | } |
| 2435 | |
| 2436 | compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { |
| 2437 | var i, |
| 2438 | setMatchers = [], |
| 2439 | elementMatchers = [], |
| 2440 | cached = compilerCache[ selector + " " ]; |
| 2441 | |
| 2442 | if ( !cached ) { |
| 2443 | // Generate a function of recursive functions that can be used to check each element |
| 2444 | if ( !group ) { |
| 2445 | group = tokenize( selector ); |
| 2446 | } |
| 2447 | i = group.length; |
| 2448 | while ( i-- ) { |
| 2449 | cached = matcherFromTokens( group[i] ); |
| 2450 | if ( cached[ expando ] ) { |
| 2451 | setMatchers.push( cached ); |
| 2452 | } else { |
| 2453 | elementMatchers.push( cached ); |
| 2454 | } |
| 2455 | } |
| 2456 | |
| 2457 | // Cache the compiled function |
| 2458 | cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); |
| 2459 | } |
| 2460 | return cached; |
| 2461 | }; |
| 2462 | |
| 2463 | function multipleContexts( selector, contexts, results ) { |
| 2464 | var i = 0, |
| 2465 | len = contexts.length; |
| 2466 | for ( ; i < len; i++ ) { |
| 2467 | Sizzle( selector, contexts[i], results ); |
| 2468 | } |
| 2469 | return results; |
| 2470 | } |
| 2471 | |
| 2472 | function select( selector, context, results, seed ) { |
| 2473 | var i, tokens, token, type, find, |
| 2474 | match = tokenize( selector ); |
| 2475 | |
| 2476 | if ( !seed ) { |
| 2477 | // Try to minimize operations if there is only one group |
| 2478 | if ( match.length === 1 ) { |
| 2479 | |
| 2480 | // Take a shortcut and set the context if the root selector is an ID |
| 2481 | tokens = match[0] = match[0].slice( 0 ); |
| 2482 | if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && |
| 2483 | context.nodeType === 9 && documentIsHTML && |
| 2484 | Expr.relative[ tokens[1].type ] ) { |
| 2485 | |
| 2486 | context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; |
| 2487 | if ( !context ) { |
| 2488 | return results; |
| 2489 | } |
| 2490 | |
| 2491 | selector = selector.slice( tokens.shift().value.length ); |
| 2492 | } |
| 2493 | |
| 2494 | // Fetch a seed set for right-to-left matching |
| 2495 | i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; |
| 2496 | while ( i-- ) { |
| 2497 | token = tokens[i]; |
| 2498 | |
| 2499 | // Abort if we hit a combinator |
| 2500 | if ( Expr.relative[ (type = token.type) ] ) { |
| 2501 | break; |
| 2502 | } |
| 2503 | if ( (find = Expr.find[ type ]) ) { |
| 2504 | // Search, expanding context for leading sibling combinators |
| 2505 | if ( (seed = find( |
| 2506 | token.matches[0].replace( runescape, funescape ), |
| 2507 | rsibling.test( tokens[0].type ) && context.parentNode || context |
| 2508 | )) ) { |
| 2509 | |
| 2510 | // If seed is empty or no tokens remain, we can return early |
| 2511 | tokens.splice( i, 1 ); |
| 2512 | selector = seed.length && toSelector( tokens ); |
| 2513 | if ( !selector ) { |
| 2514 | push.apply( results, seed ); |
| 2515 | return results; |
| 2516 | } |
| 2517 | |
| 2518 | break; |
| 2519 | } |
| 2520 | } |
| 2521 | } |
| 2522 | } |
| 2523 | } |
| 2524 | |
| 2525 | // Compile and execute a filtering function |
| 2526 | // Provide `match` to avoid retokenization if we modified the selector above |
| 2527 | compile( selector, match )( |
| 2528 | seed, |
| 2529 | context, |
| 2530 | !documentIsHTML, |
| 2531 | results, |
| 2532 | rsibling.test( selector ) |
| 2533 | ); |
| 2534 | return results; |
| 2535 | } |
| 2536 | |
| 2537 | // Deprecated |
| 2538 | Expr.pseudos["nth"] = Expr.pseudos["eq"]; |
| 2539 | |
| 2540 | // Easy API for creating new setFilters |
| 2541 | function setFilters() {} |
| 2542 | setFilters.prototype = Expr.filters = Expr.pseudos; |
| 2543 | Expr.setFilters = new setFilters(); |
| 2544 | |
| 2545 | // Check sort stability |
| 2546 | support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; |
| 2547 | |
| 2548 | // Initialize with the default document |
| 2549 | setDocument(); |
| 2550 | |
| 2551 | // Always assume the presence of duplicates if sort doesn't |
| 2552 | // pass them to our comparison function (as in Google Chrome). |
| 2553 | [0, 0].sort( sortOrder ); |
| 2554 | support.detectDuplicates = hasDuplicate; |
| 2555 | |
| 2556 | /* |
| 2557 | // EXPOSE |
| 2558 | if ( typeof define === "function" && define.amd ) { |
| 2559 | define(function() { return Sizzle; }); |
| 2560 | } else { |
| 2561 | window.Sizzle = Sizzle; |
| 2562 | } |
| 2563 | */ |
| 2564 | |
| 2565 | // EXPOSE |
| 2566 | return Sizzle; |
| 2567 | }); |
| 2568 | |
| 2569 | // Included from: js/tinymce/classes/dom/DomQuery.js |
| 2570 | |
| 2571 | /** |
| 2572 | * DomQuery.js |
| 2573 | * |
| 2574 | * Copyright, Moxiecode Systems AB |
| 2575 | * Released under LGPL License. |
| 2576 | * |
| 2577 | * License: http://www.tinymce.com/license |
| 2578 | * Contributing: http://www.tinymce.com/contributing |
| 2579 | * |
| 2580 | * Some of this logic is based on jQuery code that is released under |
| 2581 | * MIT license that grants us to sublicense it under LGPL. |
| 2582 | * |
| 2583 | * @ignore-file |
| 2584 | */ |
| 2585 | |
| 2586 | /** |
| 2587 | * @class tinymce.dom.DomQuery |
| 2588 | */ |
| 2589 | define("tinymce/dom/DomQuery", [ |
| 2590 | "tinymce/dom/EventUtils", |
| 2591 | "tinymce/dom/Sizzle" |
| 2592 | ], function(EventUtils, Sizzle) { |
| 2593 | var doc = document, push = Array.prototype.push, slice = Array.prototype.slice; |
| 2594 | var rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/; |
| 2595 | var Event = EventUtils.Event; |
| 2596 | |
| 2597 | function isDefined(obj) { |
| 2598 | return typeof obj !== "undefined"; |
| 2599 | } |
| 2600 | |
| 2601 | function isString(obj) { |
| 2602 | return typeof obj === "string"; |
| 2603 | } |
| 2604 | |
| 2605 | function createFragment(html) { |
| 2606 | var frag, node, container; |
| 2607 | |
| 2608 | container = doc.createElement("div"); |
| 2609 | frag = doc.createDocumentFragment(); |
| 2610 | container.innerHTML = html; |
| 2611 | |
| 2612 | while ((node = container.firstChild)) { |
| 2613 | frag.appendChild(node); |
| 2614 | } |
| 2615 | |
| 2616 | return frag; |
| 2617 | } |
| 2618 | |
| 2619 | function domManipulate(targetNodes, sourceItem, callback) { |
| 2620 | var i; |
| 2621 | |
| 2622 | if (typeof sourceItem === "string") { |
| 2623 | sourceItem = createFragment(sourceItem); |
| 2624 | } else if (sourceItem.length) { |
| 2625 | for (i = 0; i < sourceItem.length; i++) { |
| 2626 | domManipulate(targetNodes, sourceItem[i], callback); |
| 2627 | } |
| 2628 | |
| 2629 | return targetNodes; |
| 2630 | } |
| 2631 | |
| 2632 | i = targetNodes.length; |
| 2633 | while (i--) { |
| 2634 | callback.call(targetNodes[i], sourceItem.parentNode ? sourceItem : sourceItem); |
| 2635 | } |
| 2636 | |
| 2637 | return targetNodes; |
| 2638 | } |
| 2639 | |
| 2640 | function hasClass(node, className) { |
| 2641 | return node && className && (' ' + node.className + ' ').indexOf(' ' + className + ' ') !== -1; |
| 2642 | } |
| 2643 | |
| 2644 | /** |
| 2645 | * Makes a map object out of a string that gets separated by a delimiter. |
| 2646 | * |
| 2647 | * @method makeMap |
| 2648 | * @param {String} items Item string to split. |
| 2649 | * @param {Object} map Optional object to add items to. |
| 2650 | * @return {Object} name/value object with items as keys. |
| 2651 | */ |
| 2652 | function makeMap(items, map) { |
| 2653 | var i; |
| 2654 | |
| 2655 | items = items || []; |
| 2656 | |
| 2657 | if (typeof(items) == "string") { |
| 2658 | items = items.split(' '); |
| 2659 | } |
| 2660 | |
| 2661 | map = map || {}; |
| 2662 | |
| 2663 | i = items.length; |
| 2664 | while (i--) { |
| 2665 | map[items[i]] = {}; |
| 2666 | } |
| 2667 | |
| 2668 | return map; |
| 2669 | } |
| 2670 | |
| 2671 | var numericCssMap = makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom'); |
| 2672 | |
| 2673 | function DomQuery(selector, context) { |
| 2674 | return new DomQuery.fn.init(selector, context); |
| 2675 | } |
| 2676 | |
| 2677 | /** |
| 2678 | * Extends the specified object with another object. |
| 2679 | * |
| 2680 | * @method extend |
| 2681 | * @param {Object} target Object to extend. |
| 2682 | * @param {Object..} obj Multiple objects to extend with. |
| 2683 | * @return {Object} Same as target, the extended object. |
| 2684 | */ |
| 2685 | function extend(target) { |
| 2686 | var args = arguments, arg, i, key; |
| 2687 | |
| 2688 | for (i = 1; i < args.length; i++) { |
| 2689 | arg = args[i]; |
| 2690 | |
| 2691 | for (key in arg) { |
| 2692 | target[key] = arg[key]; |
| 2693 | } |
| 2694 | } |
| 2695 | |
| 2696 | return target; |
| 2697 | } |
| 2698 | |
| 2699 | /** |
| 2700 | * Converts the specified object into a real JavaScript array. |
| 2701 | * |
| 2702 | * @method toArray |
| 2703 | * @param {Object} obj Object to convert into array. |
| 2704 | * @return {Array} Array object based in input. |
| 2705 | */ |
| 2706 | function toArray(obj) { |
| 2707 | var array = [], i, l; |
| 2708 | |
| 2709 | for (i = 0, l = obj.length; i < l; i++) { |
| 2710 | array[i] = obj[i]; |
| 2711 | } |
| 2712 | |
| 2713 | return array; |
| 2714 | } |
| 2715 | |
| 2716 | /** |
| 2717 | * Returns the index of the specified item inside the array. |
| 2718 | * |
| 2719 | * @method inArray |
| 2720 | * @param {Object} item Item to look for. |
| 2721 | * @param {Array} array Array to look for item in. |
| 2722 | * @return {Number} Index of the item or -1. |
| 2723 | */ |
| 2724 | function inArray(item, array) { |
| 2725 | var i; |
| 2726 | |
| 2727 | if (array.indexOf) { |
| 2728 | return array.indexOf(item); |
| 2729 | } |
| 2730 | |
| 2731 | i = array.length; |
| 2732 | while (i--) { |
| 2733 | if (array[i] === item) { |
| 2734 | return i; |
| 2735 | } |
| 2736 | } |
| 2737 | |
| 2738 | return -1; |
| 2739 | } |
| 2740 | |
| 2741 | /** |
| 2742 | * Returns true/false if the specified object is an array. |
| 2743 | * |
| 2744 | * @method isArray |
| 2745 | * @param {Object} obj Object to check if it's an array. |
| 2746 | * @return {Boolean} true/false if the input object is array or not. |
| 2747 | */ |
| 2748 | var isArray = Array.isArray || function(obj) { |
| 2749 | return Object.prototype.toString.call(obj) === "[object Array]"; |
| 2750 | }; |
| 2751 | |
| 2752 | var whiteSpaceRegExp = /^\s*|\s*$/g; |
| 2753 | var trim = function(str) { |
| 2754 | return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, ''); |
| 2755 | }; |
| 2756 | |
| 2757 | /** |
| 2758 | * Executes the callback function for each item in array/object. If you return false in the |
| 2759 | * callback it will break the loop. |
| 2760 | * |
| 2761 | * @method each |
| 2762 | * @param {Object} obj Object to iterate. |
| 2763 | * @param {function} callback Callback function to execute for each item. |
| 2764 | */ |
| 2765 | function each(obj, callback) { |
| 2766 | var length, key, i, undef, value; |
| 2767 | |
| 2768 | if (obj) { |
| 2769 | length = obj.length; |
| 2770 | |
| 2771 | if (length === undef) { |
| 2772 | // Loop object items |
| 2773 | for (key in obj) { |
| 2774 | if (obj.hasOwnProperty(key)) { |
| 2775 | value = obj[key]; |
| 2776 | if (callback.call(value, value, key) === false) { |
| 2777 | break; |
| 2778 | } |
| 2779 | } |
| 2780 | } |
| 2781 | } else { |
| 2782 | // Loop array items |
| 2783 | for (i = 0; i < length; i++) { |
| 2784 | value = obj[i]; |
| 2785 | if (callback.call(value, value, key) === false) { |
| 2786 | break; |
| 2787 | } |
| 2788 | } |
| 2789 | } |
| 2790 | } |
| 2791 | |
| 2792 | return obj; |
| 2793 | } |
| 2794 | |
| 2795 | DomQuery.fn = DomQuery.prototype = { |
| 2796 | constructor: DomQuery, |
| 2797 | selector: "", |
| 2798 | length: 0, |
| 2799 | |
| 2800 | init: function(selector, context) { |
| 2801 | var self = this, match, node; |
| 2802 | |
| 2803 | if (!selector) { |
| 2804 | return self; |
| 2805 | } |
| 2806 | |
| 2807 | if (selector.nodeType) { |
| 2808 | self.context = self[0] = selector; |
| 2809 | self.length = 1; |
| 2810 | |
| 2811 | return self; |
| 2812 | } |
| 2813 | |
| 2814 | if (isString(selector)) { |
| 2815 | if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) { |
| 2816 | match = [null, selector, null]; |
| 2817 | } else { |
| 2818 | match = rquickExpr.exec(selector); |
| 2819 | } |
| 2820 | |
| 2821 | if (match) { |
| 2822 | if (match[1]) { |
| 2823 | node = createFragment(selector).firstChild; |
| 2824 | while (node) { |
| 2825 | this.add(node); |
| 2826 | node = node.nextSibling; |
| 2827 | } |
| 2828 | } else { |
| 2829 | node = doc.getElementById(match[2]); |
| 2830 | |
| 2831 | if (node.id !== match[2]) { |
| 2832 | return self.find(selector); |
| 2833 | } |
| 2834 | |
| 2835 | self.length = 1; |
| 2836 | self[0] = node; |
| 2837 | } |
| 2838 | } else { |
| 2839 | return DomQuery(context || document).find(selector); |
| 2840 | } |
| 2841 | } else { |
| 2842 | this.add(selector); |
| 2843 | } |
| 2844 | |
| 2845 | return self; |
| 2846 | }, |
| 2847 | |
| 2848 | toArray: function() { |
| 2849 | return toArray(this); |
| 2850 | }, |
| 2851 | |
| 2852 | add: function(items) { |
| 2853 | var self = this; |
| 2854 | |
| 2855 | // Force single item into array |
| 2856 | if (!isArray(items)) { |
| 2857 | if (items instanceof DomQuery) { |
| 2858 | self.add(items.toArray()); |
| 2859 | } else { |
| 2860 | push.call(self, items); |
| 2861 | } |
| 2862 | } else { |
| 2863 | push.apply(self, items); |
| 2864 | } |
| 2865 | |
| 2866 | return self; |
| 2867 | }, |
| 2868 | |
| 2869 | attr: function(name, value) { |
| 2870 | var self = this; |
| 2871 | |
| 2872 | if (typeof name === "object") { |
| 2873 | each(name, function(value, name) { |
| 2874 | self.attr(name, value); |
| 2875 | }); |
| 2876 | } else if (isDefined(value)) { |
| 2877 | this.each(function() { |
| 2878 | if (this.nodeType === 1) { |
| 2879 | this.setAttribute(name, value); |
| 2880 | } |
| 2881 | }); |
| 2882 | } else { |
| 2883 | return self[0] && self[0].nodeType === 1 ? self[0].getAttribute(name) : undefined; |
| 2884 | } |
| 2885 | |
| 2886 | return self; |
| 2887 | }, |
| 2888 | |
| 2889 | css: function(name, value) { |
| 2890 | var self = this; |
| 2891 | |
| 2892 | if (typeof name === "object") { |
| 2893 | each(name, function(value, name) { |
| 2894 | self.css(name, value); |
| 2895 | }); |
| 2896 | } else { |
| 2897 | // Camelcase it, if needed |
| 2898 | name = name.replace(/-(\D)/g, function(a, b) { |
| 2899 | return b.toUpperCase(); |
| 2900 | }); |
| 2901 | |
| 2902 | if (isDefined(value)) { |
| 2903 | // Default px suffix on these |
| 2904 | if (typeof(value) === 'number' && !numericCssMap[name]) { |
| 2905 | value += 'px'; |
| 2906 | } |
| 2907 | |
| 2908 | self.each(function() { |
| 2909 | var style = this.style; |
| 2910 | |
| 2911 | // IE specific opacity |
| 2912 | if (name === "opacity" && this.runtimeStyle && typeof(this.runtimeStyle.opacity) === "undefined") { |
| 2913 | style.filter = value === '' ? '' : "alpha(opacity=" + (value * 100) + ")"; |
| 2914 | } |
| 2915 | |
| 2916 | try { |
| 2917 | style[name] = value; |
| 2918 | } catch (ex) { |
| 2919 | // Ignore |
| 2920 | } |
| 2921 | }); |
| 2922 | } else { |
| 2923 | return self[0] ? self[0].style[name] : undefined; |
| 2924 | } |
| 2925 | } |
| 2926 | |
| 2927 | return self; |
| 2928 | }, |
| 2929 | |
| 2930 | remove: function() { |
| 2931 | var self = this, node, i = this.length; |
| 2932 | |
| 2933 | while (i--) { |
| 2934 | node = self[i]; |
| 2935 | Event.clean(node); |
| 2936 | |
| 2937 | if (node.parentNode) { |
| 2938 | node.parentNode.removeChild(node); |
| 2939 | } |
| 2940 | } |
| 2941 | |
| 2942 | return this; |
| 2943 | }, |
| 2944 | |
| 2945 | empty: function() { |
| 2946 | var self = this, node, i = this.length; |
| 2947 | |
| 2948 | while (i--) { |
| 2949 | node = self[i]; |
| 2950 | while (node.firstChild) { |
| 2951 | node.removeChild(node.firstChild); |
| 2952 | } |
| 2953 | } |
| 2954 | |
| 2955 | return this; |
| 2956 | }, |
| 2957 | |
| 2958 | html: function(value) { |
| 2959 | var self = this, i; |
| 2960 | |
| 2961 | if (isDefined(value)) { |
| 2962 | i = self.length; |
| 2963 | while (i--) { |
| 2964 | self[i].innerHTML = value; |
| 2965 | } |
| 2966 | |
| 2967 | return self; |
| 2968 | } |
| 2969 | |
| 2970 | return self[0] ? self[0].innerHTML : ''; |
| 2971 | }, |
| 2972 | |
| 2973 | text: function(value) { |
| 2974 | var self = this, i; |
| 2975 | |
| 2976 | if (isDefined(value)) { |
| 2977 | i = self.length; |
| 2978 | while (i--) { |
| 2979 | self[i].innerText = self[0].textContent = value; |
| 2980 | } |
| 2981 | |
| 2982 | return self; |
| 2983 | } |
| 2984 | |
| 2985 | return self[0] ? self[0].innerText || self[0].textContent : ''; |
| 2986 | }, |
| 2987 | |
| 2988 | append: function() { |
| 2989 | return domManipulate(this, arguments, function(node) { |
| 2990 | if (this.nodeType === 1) { |
| 2991 | this.appendChild(node); |
| 2992 | } |
| 2993 | }); |
| 2994 | }, |
| 2995 | |
| 2996 | prepend: function() { |
| 2997 | return domManipulate(this, arguments, function(node) { |
| 2998 | if (this.nodeType === 1) { |
| 2999 | this.insertBefore(node, this.firstChild); |
| 3000 | } |
| 3001 | }); |
| 3002 | }, |
| 3003 | |
| 3004 | before: function() { |
| 3005 | var self = this; |
| 3006 | |
| 3007 | if (self[0] && self[0].parentNode) { |
| 3008 | return domManipulate(self, arguments, function(node) { |
| 3009 | this.parentNode.insertBefore(node, this.nextSibling); |
| 3010 | }); |
| 3011 | } |
| 3012 | |
| 3013 | return self; |
| 3014 | }, |
| 3015 | |
| 3016 | after: function() { |
| 3017 | var self = this; |
| 3018 | |
| 3019 | if (self[0] && self[0].parentNode) { |
| 3020 | return domManipulate(self, arguments, function(node) { |
| 3021 | this.parentNode.insertBefore(node, this); |
| 3022 | }); |
| 3023 | } |
| 3024 | |
| 3025 | return self; |
| 3026 | }, |
| 3027 | |
| 3028 | appendTo: function(val) { |
| 3029 | DomQuery(val).append(this); |
| 3030 | |
| 3031 | return this; |
| 3032 | }, |
| 3033 | |
| 3034 | addClass: function(className) { |
| 3035 | return this.toggleClass(className, true); |
| 3036 | }, |
| 3037 | |
| 3038 | removeClass: function(className) { |
| 3039 | return this.toggleClass(className, false); |
| 3040 | }, |
| 3041 | |
| 3042 | toggleClass: function(className, state) { |
| 3043 | var self = this; |
| 3044 | |
| 3045 | if (className.indexOf(' ') !== -1) { |
| 3046 | each(className.split(' '), function() { |
| 3047 | self.toggleClass(this, state); |
| 3048 | }); |
| 3049 | } else { |
| 3050 | self.each(function() { |
| 3051 | var node = this, existingClassName; |
| 3052 | |
| 3053 | if (hasClass(node, className) !== state) { |
| 3054 | existingClassName = node.className; |
| 3055 | |
| 3056 | if (state) { |
| 3057 | node.className += existingClassName ? ' ' + className : className; |
| 3058 | } else { |
| 3059 | node.className = trim((" " + existingClassName + " ").replace(' ' + className + ' ', ' ')); |
| 3060 | } |
| 3061 | } |
| 3062 | }); |
| 3063 | } |
| 3064 | |
| 3065 | return self; |
| 3066 | }, |
| 3067 | |
| 3068 | hasClass: function(className) { |
| 3069 | return hasClass(this[0], className); |
| 3070 | }, |
| 3071 | |
| 3072 | each: function(callback) { |
| 3073 | return each(this, callback); |
| 3074 | }, |
| 3075 | |
| 3076 | on: function(name, callback) { |
| 3077 | return this.each(function() { |
| 3078 | Event.bind(this, name, callback); |
| 3079 | }); |
| 3080 | }, |
| 3081 | |
| 3082 | off: function(name, callback) { |
| 3083 | return this.each(function() { |
| 3084 | Event.unbind(this, name, callback); |
| 3085 | }); |
| 3086 | }, |
| 3087 | |
| 3088 | show: function() { |
| 3089 | return this.css('display', ''); |
| 3090 | }, |
| 3091 | |
| 3092 | hide: function() { |
| 3093 | return this.css('display', 'none'); |
| 3094 | }, |
| 3095 | |
| 3096 | slice: function() { |
| 3097 | return new DomQuery(slice.apply(this, arguments)); |
| 3098 | }, |
| 3099 | |
| 3100 | eq: function(index) { |
| 3101 | return index === -1 ? this.slice(index) : this.slice(index, +index + 1); |
| 3102 | }, |
| 3103 | |
| 3104 | first: function() { |
| 3105 | return this.eq(0); |
| 3106 | }, |
| 3107 | |
| 3108 | last: function() { |
| 3109 | return this.eq(-1); |
| 3110 | }, |
| 3111 | |
| 3112 | replaceWith: function(content) { |
| 3113 | var self = this; |
| 3114 | |
| 3115 | if (self[0]) { |
| 3116 | self[0].parentNode.replaceChild(DomQuery(content)[0], self[0]); |
| 3117 | } |
| 3118 | |
| 3119 | return self; |
| 3120 | }, |
| 3121 | |
| 3122 | wrap: function(wrapper) { |
| 3123 | wrapper = DomQuery(wrapper)[0]; |
| 3124 | |
| 3125 | return this.each(function() { |
| 3126 | var self = this, newWrapper = wrapper.cloneNode(false); |
| 3127 | self.parentNode.insertBefore(newWrapper, self); |
| 3128 | newWrapper.appendChild(self); |
| 3129 | }); |
| 3130 | }, |
| 3131 | |
| 3132 | unwrap: function() { |
| 3133 | return this.each(function() { |
| 3134 | var self = this, node = self.firstChild, currentNode; |
| 3135 | |
| 3136 | while (node) { |
| 3137 | currentNode = node; |
| 3138 | node = node.nextSibling; |
| 3139 | self.parentNode.insertBefore(currentNode, self); |
| 3140 | } |
| 3141 | }); |
| 3142 | }, |
| 3143 | |
| 3144 | clone: function() { |
| 3145 | var result = []; |
| 3146 | |
| 3147 | this.each(function() { |
| 3148 | result.push(this.cloneNode(true)); |
| 3149 | }); |
| 3150 | |
| 3151 | return DomQuery(result); |
| 3152 | }, |
| 3153 | |
| 3154 | find: function(selector) { |
| 3155 | var i, l, ret = []; |
| 3156 | |
| 3157 | for (i = 0, l = this.length; i < l; i++) { |
| 3158 | DomQuery.find(selector, this[i], ret); |
| 3159 | } |
| 3160 | |
| 3161 | return DomQuery(ret); |
| 3162 | }, |
| 3163 | |
| 3164 | push: push, |
| 3165 | sort: [].sort, |
| 3166 | splice: [].splice |
| 3167 | }; |
| 3168 | |
| 3169 | // Static members |
| 3170 | extend(DomQuery, { |
| 3171 | extend: extend, |
| 3172 | toArray: toArray, |
| 3173 | inArray: inArray, |
| 3174 | isArray: isArray, |
| 3175 | each: each, |
| 3176 | trim: trim, |
| 3177 | makeMap: makeMap, |
| 3178 | |
| 3179 | // Sizzle |
| 3180 | find: Sizzle, |
| 3181 | expr: Sizzle.selectors, |
| 3182 | unique: Sizzle.uniqueSort, |
| 3183 | text: Sizzle.getText, |
| 3184 | isXMLDoc: Sizzle.isXML, |
| 3185 | contains: Sizzle.contains, |
| 3186 | filter: function(expr, elems, not) { |
| 3187 | if (not) { |
| 3188 | expr = ":not(" + expr + ")"; |
| 3189 | } |
| 3190 | |
| 3191 | return elems.length === 1 ? |
| 3192 | DomQuery.find.matchesSelector(elems[0], expr) ? [elems[0]] : [] : |
| 3193 | DomQuery.find.matches(expr, elems); |
| 3194 | } |
| 3195 | }); |
| 3196 | |
| 3197 | function dir(el, prop, until) { |
| 3198 | var matched = [], cur = el[prop]; |
| 3199 | |
| 3200 | while (cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !DomQuery(cur).is(until))) { |
| 3201 | if (cur.nodeType === 1) { |
| 3202 | matched.push(cur); |
| 3203 | } |
| 3204 | |
| 3205 | cur = cur[prop]; |
| 3206 | } |
| 3207 | |
| 3208 | return matched; |
| 3209 | } |
| 3210 | |
| 3211 | function sibling(n, el, siblingName, nodeType) { |
| 3212 | var r = []; |
| 3213 | |
| 3214 | for(; n; n = n[siblingName]) { |
| 3215 | if ((!nodeType || n.nodeType === nodeType) && n !== el) { |
| 3216 | r.push(n); |
| 3217 | } |
| 3218 | } |
| 3219 | |
| 3220 | return r; |
| 3221 | } |
| 3222 | |
| 3223 | each({ |
| 3224 | parent: function(node) { |
| 3225 | var parent = node.parentNode; |
| 3226 | |
| 3227 | return parent && parent.nodeType !== 11 ? parent : null; |
| 3228 | }, |
| 3229 | |
| 3230 | parents: function(node) { |
| 3231 | return dir(node, "parentNode"); |
| 3232 | }, |
| 3233 | |
| 3234 | parentsUntil: function(node, until) { |
| 3235 | return dir(node, "parentNode", until); |
| 3236 | }, |
| 3237 | |
| 3238 | next: function(node) { |
| 3239 | return sibling(node, 'nextSibling', 1); |
| 3240 | }, |
| 3241 | |
| 3242 | prev: function(node) { |
| 3243 | return sibling(node, 'previousSibling', 1); |
| 3244 | }, |
| 3245 | |
| 3246 | nextNodes: function(node) { |
| 3247 | return sibling(node, 'nextSibling'); |
| 3248 | }, |
| 3249 | |
| 3250 | prevNodes: function(node) { |
| 3251 | return sibling(node, 'previousSibling'); |
| 3252 | }, |
| 3253 | |
| 3254 | children: function(node) { |
| 3255 | return sibling(node.firstChild, 'nextSibling', 1); |
| 3256 | }, |
| 3257 | |
| 3258 | contents: function(node) { |
| 3259 | return toArray((node.nodeName === "iframe" ? node.contentDocument || node.contentWindow.document : node).childNodes); |
| 3260 | } |
| 3261 | }, function(name, fn){ |
| 3262 | DomQuery.fn[name] = function(selector) { |
| 3263 | var self = this, result; |
| 3264 | |
| 3265 | if (self.length > 1) { |
| 3266 | throw new Error("DomQuery only supports traverse functions on a single node."); |
| 3267 | } |
| 3268 | |
| 3269 | if (self[0]) { |
| 3270 | result = fn(self[0], selector); |
| 3271 | } |
| 3272 | |
| 3273 | result = DomQuery(result); |
| 3274 | |
| 3275 | if (selector && name !== "parentsUntil") { |
| 3276 | return result.filter(selector); |
| 3277 | } |
| 3278 | |
| 3279 | return result; |
| 3280 | }; |
| 3281 | }); |
| 3282 | |
| 3283 | DomQuery.fn.filter = function(selector) { |
| 3284 | return DomQuery.filter(selector); |
| 3285 | }; |
| 3286 | |
| 3287 | DomQuery.fn.is = function(selector) { |
| 3288 | return !!selector && this.filter(selector).length > 0; |
| 3289 | }; |
| 3290 | |
| 3291 | DomQuery.fn.init.prototype = DomQuery.fn; |
| 3292 | |
| 3293 | return DomQuery; |
| 3294 | }); |
| 3295 | |
| 3296 | // Included from: js/tinymce/classes/html/Styles.js |
| 3297 | |
| 3298 | /** |
| 3299 | * Styles.js |
| 3300 | * |
| 3301 | * Copyright, Moxiecode Systems AB |
| 3302 | * Released under LGPL License. |
| 3303 | * |
| 3304 | * License: http://www.tinymce.com/license |
| 3305 | * Contributing: http://www.tinymce.com/contributing |
| 3306 | */ |
| 3307 | |
| 3308 | /** |
| 3309 | * This class is used to parse CSS styles it also compresses styles to reduce the output size. |
| 3310 | * |
| 3311 | * @example |
| 3312 | * var Styles = new tinymce.html.Styles({ |
| 3313 | * url_converter: function(url) { |
| 3314 | * return url; |
| 3315 | * } |
| 3316 | * }); |
| 3317 | * |
| 3318 | * styles = Styles.parse('border: 1px solid red'); |
| 3319 | * styles.color = 'red'; |
| 3320 | * |
| 3321 | * console.log(new tinymce.html.StyleSerializer().serialize(styles)); |
| 3322 | * |
| 3323 | * @class tinymce.html.Styles |
| 3324 | * @version 3.4 |
| 3325 | */ |
| 3326 | define("tinymce/html/Styles", [], function() { |
| 3327 | return function(settings, schema) { |
| 3328 | /*jshint maxlen:255 */ |
| 3329 | var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi, |
| 3330 | urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi, |
| 3331 | styleRegExp = /\s*([^:]+):\s*([^;]+);?/g, |
| 3332 | trimRightRegExp = /\s+$/, |
| 3333 | undef, i, encodingLookup = {}, encodingItems, invisibleChar = '\uFEFF'; |
| 3334 | |
| 3335 | settings = settings || {}; |
| 3336 | |
| 3337 | encodingItems = ('\\" \\\' \\; \\: ; : ' + invisibleChar).split(' '); |
| 3338 | for (i = 0; i < encodingItems.length; i++) { |
| 3339 | encodingLookup[encodingItems[i]] = invisibleChar + i; |
| 3340 | encodingLookup[invisibleChar + i] = encodingItems[i]; |
| 3341 | } |
| 3342 | |
| 3343 | function toHex(match, r, g, b) { |
| 3344 | function hex(val) { |
| 3345 | val = parseInt(val, 10).toString(16); |
| 3346 | |
| 3347 | return val.length > 1 ? val : '0' + val; // 0 -> 00 |
| 3348 | } |
| 3349 | |
| 3350 | return '#' + hex(r) + hex(g) + hex(b); |
| 3351 | } |
| 3352 | |
| 3353 | return { |
| 3354 | /** |
| 3355 | * Parses the specified RGB color value and returns a hex version of that color. |
| 3356 | * |
| 3357 | * @method toHex |
| 3358 | * @param {String} color RGB string value like rgb(1,2,3) |
| 3359 | * @return {String} Hex version of that RGB value like #FF00FF. |
| 3360 | */ |
| 3361 | toHex: function(color) { |
| 3362 | return color.replace(rgbRegExp, toHex); |
| 3363 | }, |
| 3364 | |
| 3365 | /** |
| 3366 | * Parses the specified style value into an object collection. This parser will also |
| 3367 | * merge and remove any redundant items that browsers might have added. It will also convert non hex |
| 3368 | * colors to hex values. Urls inside the styles will also be converted to absolute/relative based on settings. |
| 3369 | * |
| 3370 | * @method parse |
| 3371 | * @param {String} css Style value to parse for example: border:1px solid red;. |
| 3372 | * @return {Object} Object representation of that style like {border: '1px solid red'} |
| 3373 | */ |
| 3374 | parse: function(css) { |
| 3375 | var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter; |
| 3376 | var urlConverterScope = settings.url_converter_scope || this; |
| 3377 | |
| 3378 | function compress(prefix, suffix, noJoin) { |
| 3379 | var top, right, bottom, left; |
| 3380 | |
| 3381 | top = styles[prefix + '-top' + suffix]; |
| 3382 | if (!top) { |
| 3383 | return; |
| 3384 | } |
| 3385 | |
| 3386 | right = styles[prefix + '-right' + suffix]; |
| 3387 | if (!right) { |
| 3388 | return; |
| 3389 | } |
| 3390 | |
| 3391 | bottom = styles[prefix + '-bottom' + suffix]; |
| 3392 | if (!bottom) { |
| 3393 | return; |
| 3394 | } |
| 3395 | |
| 3396 | left = styles[prefix + '-left' + suffix]; |
| 3397 | if (!left) { |
| 3398 | return; |
| 3399 | } |
| 3400 | |
| 3401 | var box = [top, right, bottom, left]; |
| 3402 | i = box.length - 1; |
| 3403 | while (i--) { |
| 3404 | if (box[i] !== box[i + 1]) { |
| 3405 | break; |
| 3406 | } |
| 3407 | } |
| 3408 | |
| 3409 | if (i > -1 && noJoin) { |
| 3410 | return; |
| 3411 | } |
| 3412 | |
| 3413 | styles[prefix + suffix] = i == -1 ? box[0] : box.join(' '); |
| 3414 | delete styles[prefix + '-top' + suffix]; |
| 3415 | delete styles[prefix + '-right' + suffix]; |
| 3416 | delete styles[prefix + '-bottom' + suffix]; |
| 3417 | delete styles[prefix + '-left' + suffix]; |
| 3418 | } |
| 3419 | |
| 3420 | /** |
| 3421 | * Checks if the specific style can be compressed in other words if all border-width are equal. |
| 3422 | */ |
| 3423 | function canCompress(key) { |
| 3424 | var value = styles[key], i; |
| 3425 | |
| 3426 | if (!value) { |
| 3427 | return; |
| 3428 | } |
| 3429 | |
| 3430 | value = value.split(' '); |
| 3431 | i = value.length; |
| 3432 | while (i--) { |
| 3433 | if (value[i] !== value[0]) { |
| 3434 | return false; |
| 3435 | } |
| 3436 | } |
| 3437 | |
| 3438 | styles[key] = value[0]; |
| 3439 | |
| 3440 | return true; |
| 3441 | } |
| 3442 | |
| 3443 | /** |
| 3444 | * Compresses multiple styles into one style. |
| 3445 | */ |
| 3446 | function compress2(target, a, b, c) { |
| 3447 | if (!canCompress(a)) { |
| 3448 | return; |
| 3449 | } |
| 3450 | |
| 3451 | if (!canCompress(b)) { |
| 3452 | return; |
| 3453 | } |
| 3454 | |
| 3455 | if (!canCompress(c)) { |
| 3456 | return; |
| 3457 | } |
| 3458 | |
| 3459 | // Compress |
| 3460 | styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c]; |
| 3461 | delete styles[a]; |
| 3462 | delete styles[b]; |
| 3463 | delete styles[c]; |
| 3464 | } |
| 3465 | |
| 3466 | // Encodes the specified string by replacing all \" \' ; : with _<num> |
| 3467 | function encode(str) { |
| 3468 | isEncoded = true; |
| 3469 | |
| 3470 | return encodingLookup[str]; |
| 3471 | } |
| 3472 | |
| 3473 | // Decodes the specified string by replacing all _<num> with it's original value \" \' etc |
| 3474 | // It will also decode the \" \' if keep_slashes is set to fale or omitted |
| 3475 | function decode(str, keep_slashes) { |
| 3476 | if (isEncoded) { |
| 3477 | str = str.replace(/\uFEFF[0-9]/g, function(str) { |
| 3478 | return encodingLookup[str]; |
| 3479 | }); |
| 3480 | } |
| 3481 | |
| 3482 | if (!keep_slashes) { |
| 3483 | str = str.replace(/\\([\'\";:])/g, "$1"); |
| 3484 | } |
| 3485 | |
| 3486 | return str; |
| 3487 | } |
| 3488 | |
| 3489 | function processUrl(match, url, url2, url3, str, str2) { |
| 3490 | str = str || str2; |
| 3491 | |
| 3492 | if (str) { |
| 3493 | str = decode(str); |
| 3494 | |
| 3495 | // Force strings into single quote format |
| 3496 | return "'" + str.replace(/\'/g, "\\'") + "'"; |
| 3497 | } |
| 3498 | |
| 3499 | url = decode(url || url2 || url3); |
| 3500 | |
| 3501 | if (!settings.allow_script_urls && /(java|vb)script:/i.test(url.replace(/[\s\r\n]+/, ''))) { |
| 3502 | return ""; |
| 3503 | } |
| 3504 | |
| 3505 | // Convert the URL to relative/absolute depending on config |
| 3506 | if (urlConverter) { |
| 3507 | url = urlConverter.call(urlConverterScope, url, 'style'); |
| 3508 | } |
| 3509 | |
| 3510 | // Output new URL format |
| 3511 | return "url('" + url.replace(/\'/g, "\\'") + "')"; |
| 3512 | } |
| 3513 | |
| 3514 | if (css) { |
| 3515 | css = css.replace(/[\u0000-\u001F]/g, ''); |
| 3516 | |
| 3517 | // Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing |
| 3518 | css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function(str) { |
| 3519 | return str.replace(/[;:]/g, encode); |
| 3520 | }); |
| 3521 | |
| 3522 | // Parse styles |
| 3523 | while ((matches = styleRegExp.exec(css))) { |
| 3524 | name = matches[1].replace(trimRightRegExp, '').toLowerCase(); |
| 3525 | value = matches[2].replace(trimRightRegExp, ''); |
| 3526 | |
| 3527 | if (name && value.length > 0) { |
| 3528 | if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(/.test(value))) { |
| 3529 | continue; |
| 3530 | } |
| 3531 | |
| 3532 | // Opera will produce 700 instead of bold in their style values |
| 3533 | if (name === 'font-weight' && value === '700') { |
| 3534 | value = 'bold'; |
| 3535 | } else if (name === 'color' || name === 'background-color') { // Lowercase colors like RED |
| 3536 | value = value.toLowerCase(); |
| 3537 | } |
| 3538 | |
| 3539 | // Convert RGB colors to HEX |
| 3540 | value = value.replace(rgbRegExp, toHex); |
| 3541 | |
| 3542 | // Convert URLs and force them into url('value') format |
| 3543 | value = value.replace(urlOrStrRegExp, processUrl); |
| 3544 | styles[name] = isEncoded ? decode(value, true) : value; |
| 3545 | } |
| 3546 | |
| 3547 | styleRegExp.lastIndex = matches.index + matches[0].length; |
| 3548 | } |
| 3549 | // Compress the styles to reduce it's size for example IE will expand styles |
| 3550 | compress("border", "", true); |
| 3551 | compress("border", "-width"); |
| 3552 | compress("border", "-color"); |
| 3553 | compress("border", "-style"); |
| 3554 | compress("padding", ""); |
| 3555 | compress("margin", ""); |
| 3556 | compress2('border', 'border-width', 'border-style', 'border-color'); |
| 3557 | |
| 3558 | // Remove pointless border, IE produces these |
| 3559 | if (styles.border === 'medium none') { |
| 3560 | delete styles.border; |
| 3561 | } |
| 3562 | |
| 3563 | // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p> |
| 3564 | // So lets asume it shouldn't be there |
| 3565 | if (styles['border-image'] === 'none') { |
| 3566 | delete styles['border-image']; |
| 3567 | } |
| 3568 | } |
| 3569 | |
| 3570 | return styles; |
| 3571 | }, |
| 3572 | |
| 3573 | /** |
| 3574 | * Serializes the specified style object into a string. |
| 3575 | * |
| 3576 | * @method serialize |
| 3577 | * @param {Object} styles Object to serialize as string for example: {border: '1px solid red'} |
| 3578 | * @param {String} element_name Optional element name, if specified only the styles that matches the schema will be serialized. |
| 3579 | * @return {String} String representation of the style object for example: border: 1px solid red. |
| 3580 | */ |
| 3581 | serialize: function(styles, element_name) { |
| 3582 | var css = '', name, value; |
| 3583 | |
| 3584 | function serializeStyles(name) { |
| 3585 | var styleList, i, l, value; |
| 3586 | |
| 3587 | styleList = schema.styles[name]; |
| 3588 | if (styleList) { |
| 3589 | for (i = 0, l = styleList.length; i < l; i++) { |
| 3590 | name = styleList[i]; |
| 3591 | value = styles[name]; |
| 3592 | |
| 3593 | if (value !== undef && value.length > 0) { |
| 3594 | css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';'; |
| 3595 | } |
| 3596 | } |
| 3597 | } |
| 3598 | } |
| 3599 | |
| 3600 | // Serialize styles according to schema |
| 3601 | if (element_name && schema && schema.styles) { |
| 3602 | // Serialize global styles and element specific styles |
| 3603 | serializeStyles('*'); |
| 3604 | serializeStyles(element_name); |
| 3605 | } else { |
| 3606 | // Output the styles in the order they are inside the object |
| 3607 | for (name in styles) { |
| 3608 | value = styles[name]; |
| 3609 | |
| 3610 | if (value !== undef && value.length > 0) { |
| 3611 | css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';'; |
| 3612 | } |
| 3613 | } |
| 3614 | } |
| 3615 | |
| 3616 | return css; |
| 3617 | } |
| 3618 | }; |
| 3619 | }; |
| 3620 | }); |
| 3621 | |
| 3622 | // Included from: js/tinymce/classes/dom/TreeWalker.js |
| 3623 | |
| 3624 | /** |
| 3625 | * TreeWalker.js |
| 3626 | * |
| 3627 | * Copyright, Moxiecode Systems AB |
| 3628 | * Released under LGPL License. |
| 3629 | * |
| 3630 | * License: http://www.tinymce.com/license |
| 3631 | * Contributing: http://www.tinymce.com/contributing |
| 3632 | */ |
| 3633 | |
| 3634 | /** |
| 3635 | * TreeWalker class enables you to walk the DOM in a linear manner. |
| 3636 | * |
| 3637 | * @class tinymce.dom.TreeWalker |
| 3638 | */ |
| 3639 | define("tinymce/dom/TreeWalker", [], function() { |
| 3640 | return function(start_node, root_node) { |
| 3641 | var node = start_node; |
| 3642 | |
| 3643 | function findSibling(node, start_name, sibling_name, shallow) { |
| 3644 | var sibling, parent; |
| 3645 | |
| 3646 | if (node) { |
| 3647 | // Walk into nodes if it has a start |
| 3648 | if (!shallow && node[start_name]) { |
| 3649 | return node[start_name]; |
| 3650 | } |
| 3651 | |
| 3652 | // Return the sibling if it has one |
| 3653 | if (node != root_node) { |
| 3654 | sibling = node[sibling_name]; |
| 3655 | if (sibling) { |
| 3656 | return sibling; |
| 3657 | } |
| 3658 | |
| 3659 | // Walk up the parents to look for siblings |
| 3660 | for (parent = node.parentNode; parent && parent != root_node; parent = parent.parentNode) { |
| 3661 | sibling = parent[sibling_name]; |
| 3662 | if (sibling) { |
| 3663 | return sibling; |
| 3664 | } |
| 3665 | } |
| 3666 | } |
| 3667 | } |
| 3668 | } |
| 3669 | |
| 3670 | /** |
| 3671 | * Returns the current node. |
| 3672 | * |
| 3673 | * @method current |
| 3674 | * @return {Node} Current node where the walker is. |
| 3675 | */ |
| 3676 | this.current = function() { |
| 3677 | return node; |
| 3678 | }; |
| 3679 | |
| 3680 | /** |
| 3681 | * Walks to the next node in tree. |
| 3682 | * |
| 3683 | * @method next |
| 3684 | * @return {Node} Current node where the walker is after moving to the next node. |
| 3685 | */ |
| 3686 | this.next = function(shallow) { |
| 3687 | node = findSibling(node, 'firstChild', 'nextSibling', shallow); |
| 3688 | return node; |
| 3689 | }; |
| 3690 | |
| 3691 | /** |
| 3692 | * Walks to the previous node in tree. |
| 3693 | * |
| 3694 | * @method prev |
| 3695 | * @return {Node} Current node where the walker is after moving to the previous node. |
| 3696 | */ |
| 3697 | this.prev = function(shallow) { |
| 3698 | node = findSibling(node, 'lastChild', 'previousSibling', shallow); |
| 3699 | return node; |
| 3700 | }; |
| 3701 | }; |
| 3702 | }); |
| 3703 | |
| 3704 | // Included from: js/tinymce/classes/util/Tools.js |
| 3705 | |
| 3706 | /** |
| 3707 | * Tools.js |
| 3708 | * |
| 3709 | * Copyright, Moxiecode Systems AB |
| 3710 | * Released under LGPL License. |
| 3711 | * |
| 3712 | * License: http://www.tinymce.com/license |
| 3713 | * Contributing: http://www.tinymce.com/contributing |
| 3714 | */ |
| 3715 | |
| 3716 | /** |
| 3717 | * This class contains various utlity functions. These are also exposed |
| 3718 | * directly on the tinymce namespace. |
| 3719 | * |
| 3720 | * @class tinymce.util.Tools |
| 3721 | */ |
| 3722 | define("tinymce/util/Tools", [], function() { |
| 3723 | /** |
| 3724 | * Removes whitespace from the beginning and end of a string. |
| 3725 | * |
| 3726 | * @method trim |
| 3727 | * @param {String} s String to remove whitespace from. |
| 3728 | * @return {String} New string with removed whitespace. |
| 3729 | */ |
| 3730 | var whiteSpaceRegExp = /^\s*|\s*$/g; |
| 3731 | var trim = function(str) { |
| 3732 | return (str === null || str === undefined) ? '' : ("" + str).replace(whiteSpaceRegExp, ''); |
| 3733 | }; |
| 3734 | |
| 3735 | /** |
| 3736 | * Returns true/false if the object is an array or not. |
| 3737 | * |
| 3738 | * @method isArray |
| 3739 | * @param {Object} obj Object to check. |
| 3740 | * @return {boolean} true/false state if the object is an array or not. |
| 3741 | */ |
| 3742 | var isArray = Array.isArray || function(obj) { |
| 3743 | return Object.prototype.toString.call(obj) === "[object Array]"; |
| 3744 | }; |
| 3745 | |
| 3746 | /** |
| 3747 | * Checks if a object is of a specific type for example an array. |
| 3748 | * |
| 3749 | * @method is |
| 3750 | * @param {Object} o Object to check type of. |
| 3751 | * @param {string} t Optional type to check for. |
| 3752 | * @return {Boolean} true/false if the object is of the specified type. |
| 3753 | */ |
| 3754 | function is(o, t) { |
| 3755 | if (!t) { |
| 3756 | return o !== undefined; |
| 3757 | } |
| 3758 | |
| 3759 | if (t == 'array' && isArray(o)) { |
| 3760 | return true; |
| 3761 | } |
| 3762 | |
| 3763 | return typeof(o) == t; |
| 3764 | } |
| 3765 | |
| 3766 | /** |
| 3767 | * Converts the specified object into a real JavaScript array. |
| 3768 | * |
| 3769 | * @method toArray |
| 3770 | * @param {Object} obj Object to convert into array. |
| 3771 | * @return {Array} Array object based in input. |
| 3772 | */ |
| 3773 | function toArray(obj) { |
| 3774 | var array = [], i, l; |
| 3775 | |
| 3776 | for (i = 0, l = obj.length; i < l; i++) { |
| 3777 | array[i] = obj[i]; |
| 3778 | } |
| 3779 | |
| 3780 | return array; |
| 3781 | } |
| 3782 | |
| 3783 | /** |
| 3784 | * Makes a name/object map out of an array with names. |
| 3785 | * |
| 3786 | * @method makeMap |
| 3787 | * @param {Array/String} items Items to make map out of. |
| 3788 | * @param {String} delim Optional delimiter to split string by. |
| 3789 | * @param {Object} map Optional map to add items to. |
| 3790 | * @return {Object} Name/value map of items. |
| 3791 | */ |
| 3792 | function makeMap(items, delim, map) { |
| 3793 | var i; |
| 3794 | |
| 3795 | items = items || []; |
| 3796 | delim = delim || ','; |
| 3797 | |
| 3798 | if (typeof(items) == "string") { |
| 3799 | items = items.split(delim); |
| 3800 | } |
| 3801 | |
| 3802 | map = map || {}; |
| 3803 | |
| 3804 | i = items.length; |
| 3805 | while (i--) { |
| 3806 | map[items[i]] = {}; |
| 3807 | } |
| 3808 | |
| 3809 | return map; |
| 3810 | } |
| 3811 | |
| 3812 | /** |
| 3813 | * Performs an iteration of all items in a collection such as an object or array. This method will execure the |
| 3814 | * callback function for each item in the collection, if the callback returns false the iteration will terminate. |
| 3815 | * The callback has the following format: cb(value, key_or_index). |
| 3816 | * |
| 3817 | * @method each |
| 3818 | * @param {Object} o Collection to iterate. |
| 3819 | * @param {function} cb Callback function to execute for each item. |
| 3820 | * @param {Object} s Optional scope to execute the callback in. |
| 3821 | * @example |
| 3822 | * // Iterate an array |
| 3823 | * tinymce.each([1,2,3], function(v, i) { |
| 3824 | * console.debug("Value: " + v + ", Index: " + i); |
| 3825 | * }); |
| 3826 | * |
| 3827 | * // Iterate an object |
| 3828 | * tinymce.each({a: 1, b: 2, c: 3], function(v, k) { |
| 3829 | * console.debug("Value: " + v + ", Key: " + k); |
| 3830 | * }); |
| 3831 | */ |
| 3832 | function each(o, cb, s) { |
| 3833 | var n, l; |
| 3834 | |
| 3835 | if (!o) { |
| 3836 | return 0; |
| 3837 | } |
| 3838 | |
| 3839 | s = s || o; |
| 3840 | |
| 3841 | if (o.length !== undefined) { |
| 3842 | // Indexed arrays, needed for Safari |
| 3843 | for (n=0, l = o.length; n < l; n++) { |
| 3844 | if (cb.call(s, o[n], n, o) === false) { |
| 3845 | return 0; |
| 3846 | } |
| 3847 | } |
| 3848 | } else { |
| 3849 | // Hashtables |
| 3850 | for (n in o) { |
| 3851 | if (o.hasOwnProperty(n)) { |
| 3852 | if (cb.call(s, o[n], n, o) === false) { |
| 3853 | return 0; |
| 3854 | } |
| 3855 | } |
| 3856 | } |
| 3857 | } |
| 3858 | |
| 3859 | return 1; |
| 3860 | } |
| 3861 | |
| 3862 | /** |
| 3863 | * Creates a new array by the return value of each iteration function call. This enables you to convert |
| 3864 | * one array list into another. |
| 3865 | * |
| 3866 | * @method map |
| 3867 | * @param {Array} a Array of items to iterate. |
| 3868 | * @param {function} f Function to call for each item. It's return value will be the new value. |
| 3869 | * @return {Array} Array with new values based on function return values. |
| 3870 | */ |
| 3871 | function map(a, f) { |
| 3872 | var o = []; |
| 3873 | |
| 3874 | each(a, function(v) { |
| 3875 | o.push(f(v)); |
| 3876 | }); |
| 3877 | |
| 3878 | return o; |
| 3879 | } |
| 3880 | |
| 3881 | /** |
| 3882 | * Filters out items from the input array by calling the specified function for each item. |
| 3883 | * If the function returns false the item will be excluded if it returns true it will be included. |
| 3884 | * |
| 3885 | * @method grep |
| 3886 | * @param {Array} a Array of items to loop though. |
| 3887 | * @param {function} f Function to call for each item. Include/exclude depends on it's return value. |
| 3888 | * @return {Array} New array with values imported and filtered based in input. |
| 3889 | * @example |
| 3890 | * // Filter out some items, this will return an array with 4 and 5 |
| 3891 | * var items = tinymce.grep([1,2,3,4,5], function(v) {return v > 3;}); |
| 3892 | */ |
| 3893 | function grep(a, f) { |
| 3894 | var o = []; |
| 3895 | |
| 3896 | each(a, function(v) { |
| 3897 | if (!f || f(v)) { |
| 3898 | o.push(v); |
| 3899 | } |
| 3900 | }); |
| 3901 | |
| 3902 | return o; |
| 3903 | } |
| 3904 | |
| 3905 | /** |
| 3906 | * Creates a class, subclass or static singleton. |
| 3907 | * More details on this method can be found in the Wiki. |
| 3908 | * |
| 3909 | * @method create |
| 3910 | * @param {String} s Class name, inheritage and prefix. |
| 3911 | * @param {Object} p Collection of methods to add to the class. |
| 3912 | * @param {Object} root Optional root object defaults to the global window object. |
| 3913 | * @example |
| 3914 | * // Creates a basic class |
| 3915 | * tinymce.create('tinymce.somepackage.SomeClass', { |
| 3916 | * SomeClass: function() { |
| 3917 | * // Class constructor |
| 3918 | * }, |
| 3919 | * |
| 3920 | * method: function() { |
| 3921 | * // Some method |
| 3922 | * } |
| 3923 | * }); |
| 3924 | * |
| 3925 | * // Creates a basic subclass class |
| 3926 | * tinymce.create('tinymce.somepackage.SomeSubClass:tinymce.somepackage.SomeClass', { |
| 3927 | * SomeSubClass: function() { |
| 3928 | * // Class constructor |
| 3929 | * this.parent(); // Call parent constructor |
| 3930 | * }, |
| 3931 | * |
| 3932 | * method: function() { |
| 3933 | * // Some method |
| 3934 | * this.parent(); // Call parent method |
| 3935 | * }, |
| 3936 | * |
| 3937 | * 'static': { |
| 3938 | * staticMethod: function() { |
| 3939 | * // Static method |
| 3940 | * } |
| 3941 | * } |
| 3942 | * }); |
| 3943 | * |
| 3944 | * // Creates a singleton/static class |
| 3945 | * tinymce.create('static tinymce.somepackage.SomeSingletonClass', { |
| 3946 | * method: function() { |
| 3947 | * // Some method |
| 3948 | * } |
| 3949 | * }); |
| 3950 | */ |
| 3951 | function create(s, p, root) { |
| 3952 | var t = this, sp, ns, cn, scn, c, de = 0; |
| 3953 | |
| 3954 | // Parse : <prefix> <class>:<super class> |
| 3955 | s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s); |
| 3956 | cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name |
| 3957 | |
| 3958 | // Create namespace for new class |
| 3959 | ns = t.createNS(s[3].replace(/\.\w+$/, ''), root); |
| 3960 | |
| 3961 | // Class already exists |
| 3962 | if (ns[cn]) { |
| 3963 | return; |
| 3964 | } |
| 3965 | |
| 3966 | // Make pure static class |
| 3967 | if (s[2] == 'static') { |
| 3968 | ns[cn] = p; |
| 3969 | |
| 3970 | if (this.onCreate) { |
| 3971 | this.onCreate(s[2], s[3], ns[cn]); |
| 3972 | } |
| 3973 | |
| 3974 | return; |
| 3975 | } |
| 3976 | |
| 3977 | // Create default constructor |
| 3978 | if (!p[cn]) { |
| 3979 | p[cn] = function() {}; |
| 3980 | de = 1; |
| 3981 | } |
| 3982 | |
| 3983 | // Add constructor and methods |
| 3984 | ns[cn] = p[cn]; |
| 3985 | t.extend(ns[cn].prototype, p); |
| 3986 | |
| 3987 | // Extend |
| 3988 | if (s[5]) { |
| 3989 | sp = t.resolve(s[5]).prototype; |
| 3990 | scn = s[5].match(/\.(\w+)$/i)[1]; // Class name |
| 3991 | |
| 3992 | // Extend constructor |
| 3993 | c = ns[cn]; |
| 3994 | if (de) { |
| 3995 | // Add passthrough constructor |
| 3996 | ns[cn] = function() { |
| 3997 | return sp[scn].apply(this, arguments); |
| 3998 | }; |
| 3999 | } else { |
| 4000 | // Add inherit constructor |
| 4001 | ns[cn] = function() { |
| 4002 | this.parent = sp[scn]; |
| 4003 | return c.apply(this, arguments); |
| 4004 | }; |
| 4005 | } |
| 4006 | ns[cn].prototype[cn] = ns[cn]; |
| 4007 | |
| 4008 | // Add super methods |
| 4009 | t.each(sp, function(f, n) { |
| 4010 | ns[cn].prototype[n] = sp[n]; |
| 4011 | }); |
| 4012 | |
| 4013 | // Add overridden methods |
| 4014 | t.each(p, function(f, n) { |
| 4015 | // Extend methods if needed |
| 4016 | if (sp[n]) { |
| 4017 | ns[cn].prototype[n] = function() { |
| 4018 | this.parent = sp[n]; |
| 4019 | return f.apply(this, arguments); |
| 4020 | }; |
| 4021 | } else { |
| 4022 | if (n != cn) { |
| 4023 | ns[cn].prototype[n] = f; |
| 4024 | } |
| 4025 | } |
| 4026 | }); |
| 4027 | } |
| 4028 | |
| 4029 | // Add static methods |
| 4030 | /*jshint sub:true*/ |
| 4031 | t.each(p['static'], function(f, n) { |
| 4032 | ns[cn][n] = f; |
| 4033 | }); |
| 4034 | } |
| 4035 | |
| 4036 | /** |
| 4037 | * Returns the index of a value in an array, this method will return -1 if the item wasn't found. |
| 4038 | * |
| 4039 | * @method inArray |
| 4040 | * @param {Array} a Array/Object to search for value in. |
| 4041 | * @param {Object} v Value to check for inside the array. |
| 4042 | * @return {Number/String} Index of item inside the array inside an object. Or -1 if it wasn't found. |
| 4043 | * @example |
| 4044 | * // Get index of value in array this will alert 1 since 2 is at that index |
| 4045 | * alert(tinymce.inArray([1,2,3], 2)); |
| 4046 | */ |
| 4047 | function inArray(a, v) { |
| 4048 | var i, l; |
| 4049 | |
| 4050 | if (a) { |
| 4051 | for (i = 0, l = a.length; i < l; i++) { |
| 4052 | if (a[i] === v) { |
| 4053 | return i; |
| 4054 | } |
| 4055 | } |
| 4056 | } |
| 4057 | |
| 4058 | return -1; |
| 4059 | } |
| 4060 | |
| 4061 | function extend(obj, ext) { |
| 4062 | var i, l, name, args = arguments, value; |
| 4063 | |
| 4064 | for (i = 1, l = args.length; i < l; i++) { |
| 4065 | ext = args[i]; |
| 4066 | for (name in ext) { |
| 4067 | if (ext.hasOwnProperty(name)) { |
| 4068 | value = ext[name]; |
| 4069 | |
| 4070 | if (value !== undefined) { |
| 4071 | obj[name] = value; |
| 4072 | } |
| 4073 | } |
| 4074 | } |
| 4075 | } |
| 4076 | |
| 4077 | return obj; |
| 4078 | } |
| 4079 | |
| 4080 | /** |
| 4081 | * Executed the specified function for each item in a object tree. |
| 4082 | * |
| 4083 | * @method walk |
| 4084 | * @param {Object} o Object tree to walk though. |
| 4085 | * @param {function} f Function to call for each item. |
| 4086 | * @param {String} n Optional name of collection inside the objects to walk for example childNodes. |
| 4087 | * @param {String} s Optional scope to execute the function in. |
| 4088 | */ |
| 4089 | function walk(o, f, n, s) { |
| 4090 | s = s || this; |
| 4091 | |
| 4092 | if (o) { |
| 4093 | if (n) { |
| 4094 | o = o[n]; |
| 4095 | } |
| 4096 | |
| 4097 | each(o, function(o, i) { |
| 4098 | if (f.call(s, o, i, n) === false) { |
| 4099 | return false; |
| 4100 | } |
| 4101 | |
| 4102 | walk(o, f, n, s); |
| 4103 | }); |
| 4104 | } |
| 4105 | } |
| 4106 | |
| 4107 | /** |
| 4108 | * Creates a namespace on a specific object. |
| 4109 | * |
| 4110 | * @method createNS |
| 4111 | * @param {String} n Namespace to create for example a.b.c.d. |
| 4112 | * @param {Object} o Optional object to add namespace to, defaults to window. |
| 4113 | * @return {Object} New namespace object the last item in path. |
| 4114 | * @example |
| 4115 | * // Create some namespace |
| 4116 | * tinymce.createNS('tinymce.somepackage.subpackage'); |
| 4117 | * |
| 4118 | * // Add a singleton |
| 4119 | * var tinymce.somepackage.subpackage.SomeSingleton = { |
| 4120 | * method: function() { |
| 4121 | * // Some method |
| 4122 | * } |
| 4123 | * }; |
| 4124 | */ |
| 4125 | function createNS(n, o) { |
| 4126 | var i, v; |
| 4127 | |
| 4128 | o = o || window; |
| 4129 | |
| 4130 | n = n.split('.'); |
| 4131 | for (i=0; i<n.length; i++) { |
| 4132 | v = n[i]; |
| 4133 | |
| 4134 | if (!o[v]) { |
| 4135 | o[v] = {}; |
| 4136 | } |
| 4137 | |
| 4138 | o = o[v]; |
| 4139 | } |
| 4140 | |
| 4141 | return o; |
| 4142 | } |
| 4143 | |
| 4144 | /** |
| 4145 | * Resolves a string and returns the object from a specific structure. |
| 4146 | * |
| 4147 | * @method resolve |
| 4148 | * @param {String} n Path to resolve for example a.b.c.d. |
| 4149 | * @param {Object} o Optional object to search though, defaults to window. |
| 4150 | * @return {Object} Last object in path or null if it couldn't be resolved. |
| 4151 | * @example |
| 4152 | * // Resolve a path into an object reference |
| 4153 | * var obj = tinymce.resolve('a.b.c.d'); |
| 4154 | */ |
| 4155 | function resolve(n, o) { |
| 4156 | var i, l; |
| 4157 | |
| 4158 | o = o || window; |
| 4159 | |
| 4160 | n = n.split('.'); |
| 4161 | for (i = 0, l = n.length; i < l; i++) { |
| 4162 | o = o[n[i]]; |
| 4163 | |
| 4164 | if (!o) { |
| 4165 | break; |
| 4166 | } |
| 4167 | } |
| 4168 | |
| 4169 | return o; |
| 4170 | } |
| 4171 | |
| 4172 | /** |
| 4173 | * Splits a string but removes the whitespace before and after each value. |
| 4174 | * |
| 4175 | * @method explode |
| 4176 | * @param {string} s String to split. |
| 4177 | * @param {string} d Delimiter to split by. |
| 4178 | * @example |
| 4179 | * // Split a string into an array with a,b,c |
| 4180 | * var arr = tinymce.explode('a, b, c'); |
| 4181 | */ |
| 4182 | function explode(s, d) { |
| 4183 | if (!s || is(s, 'array')) { |
| 4184 | return s; |
| 4185 | } |
| 4186 | |
| 4187 | return map(s.split(d || ','), trim); |
| 4188 | } |
| 4189 | |
| 4190 | return { |
| 4191 | trim: trim, |
| 4192 | isArray: isArray, |
| 4193 | is: is, |
| 4194 | toArray: toArray, |
| 4195 | makeMap: makeMap, |
| 4196 | each: each, |
| 4197 | map: map, |
| 4198 | grep: grep, |
| 4199 | inArray: inArray, |
| 4200 | extend: extend, |
| 4201 | create: create, |
| 4202 | walk: walk, |
| 4203 | createNS: createNS, |
| 4204 | resolve: resolve, |
| 4205 | explode: explode |
| 4206 | }; |
| 4207 | }); |
| 4208 | |
| 4209 | // Included from: js/tinymce/classes/dom/Range.js |
| 4210 | |
| 4211 | /** |
| 4212 | * Range.js |
| 4213 | * |
| 4214 | * Copyright, Moxiecode Systems AB |
| 4215 | * Released under LGPL License. |
| 4216 | * |
| 4217 | * License: http://www.tinymce.com/license |
| 4218 | * Contributing: http://www.tinymce.com/contributing |
| 4219 | */ |
| 4220 | |
| 4221 | define("tinymce/dom/Range", [ |
| 4222 | "tinymce/util/Tools" |
| 4223 | ], function(Tools) { |
| 4224 | // Range constructor |
| 4225 | function Range(dom) { |
| 4226 | var t = this, |
| 4227 | doc = dom.doc, |
| 4228 | EXTRACT = 0, |
| 4229 | CLONE = 1, |
| 4230 | DELETE = 2, |
| 4231 | TRUE = true, |
| 4232 | FALSE = false, |
| 4233 | START_OFFSET = 'startOffset', |
| 4234 | START_CONTAINER = 'startContainer', |
| 4235 | END_CONTAINER = 'endContainer', |
| 4236 | END_OFFSET = 'endOffset', |
| 4237 | extend = Tools.extend, |
| 4238 | nodeIndex = dom.nodeIndex; |
| 4239 | |
| 4240 | function createDocumentFragment() { |
| 4241 | return doc.createDocumentFragment(); |
| 4242 | } |
| 4243 | |
| 4244 | function setStart(n, o) { |
| 4245 | _setEndPoint(TRUE, n, o); |
| 4246 | } |
| 4247 | |
| 4248 | function setEnd(n, o) { |
| 4249 | _setEndPoint(FALSE, n, o); |
| 4250 | } |
| 4251 | |
| 4252 | function setStartBefore(n) { |
| 4253 | setStart(n.parentNode, nodeIndex(n)); |
| 4254 | } |
| 4255 | |
| 4256 | function setStartAfter(n) { |
| 4257 | setStart(n.parentNode, nodeIndex(n) + 1); |
| 4258 | } |
| 4259 | |
| 4260 | function setEndBefore(n) { |
| 4261 | setEnd(n.parentNode, nodeIndex(n)); |
| 4262 | } |
| 4263 | |
| 4264 | function setEndAfter(n) { |
| 4265 | setEnd(n.parentNode, nodeIndex(n) + 1); |
| 4266 | } |
| 4267 | |
| 4268 | function collapse(ts) { |
| 4269 | if (ts) { |
| 4270 | t[END_CONTAINER] = t[START_CONTAINER]; |
| 4271 | t[END_OFFSET] = t[START_OFFSET]; |
| 4272 | } else { |
| 4273 | t[START_CONTAINER] = t[END_CONTAINER]; |
| 4274 | t[START_OFFSET] = t[END_OFFSET]; |
| 4275 | } |
| 4276 | |
| 4277 | t.collapsed = TRUE; |
| 4278 | } |
| 4279 | |
| 4280 | function selectNode(n) { |
| 4281 | setStartBefore(n); |
| 4282 | setEndAfter(n); |
| 4283 | } |
| 4284 | |
| 4285 | function selectNodeContents(n) { |
| 4286 | setStart(n, 0); |
| 4287 | setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length); |
| 4288 | } |
| 4289 | |
| 4290 | function compareBoundaryPoints(h, r) { |
| 4291 | var sc = t[START_CONTAINER], so = t[START_OFFSET], ec = t[END_CONTAINER], eo = t[END_OFFSET], |
| 4292 | rsc = r.startContainer, rso = r.startOffset, rec = r.endContainer, reo = r.endOffset; |
| 4293 | |
| 4294 | // Check START_TO_START |
| 4295 | if (h === 0) { |
| 4296 | return _compareBoundaryPoints(sc, so, rsc, rso); |
| 4297 | } |
| 4298 | |
| 4299 | // Check START_TO_END |
| 4300 | if (h === 1) { |
| 4301 | return _compareBoundaryPoints(ec, eo, rsc, rso); |
| 4302 | } |
| 4303 | |
| 4304 | // Check END_TO_END |
| 4305 | if (h === 2) { |
| 4306 | return _compareBoundaryPoints(ec, eo, rec, reo); |
| 4307 | } |
| 4308 | |
| 4309 | // Check END_TO_START |
| 4310 | if (h === 3) { |
| 4311 | return _compareBoundaryPoints(sc, so, rec, reo); |
| 4312 | } |
| 4313 | } |
| 4314 | |
| 4315 | function deleteContents() { |
| 4316 | _traverse(DELETE); |
| 4317 | } |
| 4318 | |
| 4319 | function extractContents() { |
| 4320 | return _traverse(EXTRACT); |
| 4321 | } |
| 4322 | |
| 4323 | function cloneContents() { |
| 4324 | return _traverse(CLONE); |
| 4325 | } |
| 4326 | |
| 4327 | function insertNode(n) { |
| 4328 | var startContainer = this[START_CONTAINER], |
| 4329 | startOffset = this[START_OFFSET], nn, o; |
| 4330 | |
| 4331 | // Node is TEXT_NODE or CDATA |
| 4332 | if ((startContainer.nodeType === 3 || startContainer.nodeType === 4) && startContainer.nodeValue) { |
| 4333 | if (!startOffset) { |
| 4334 | // At the start of text |
| 4335 | startContainer.parentNode.insertBefore(n, startContainer); |
| 4336 | } else if (startOffset >= startContainer.nodeValue.length) { |
| 4337 | // At the end of text |
| 4338 | dom.insertAfter(n, startContainer); |
| 4339 | } else { |
| 4340 | // Middle, need to split |
| 4341 | nn = startContainer.splitText(startOffset); |
| 4342 | startContainer.parentNode.insertBefore(n, nn); |
| 4343 | } |
| 4344 | } else { |
| 4345 | // Insert element node |
| 4346 | if (startContainer.childNodes.length > 0) { |
| 4347 | o = startContainer.childNodes[startOffset]; |
| 4348 | } |
| 4349 | |
| 4350 | if (o) { |
| 4351 | startContainer.insertBefore(n, o); |
| 4352 | } else { |
| 4353 | if (startContainer.nodeType == 3) { |
| 4354 | dom.insertAfter(n, startContainer); |
| 4355 | } else { |
| 4356 | startContainer.appendChild(n); |
| 4357 | } |
| 4358 | } |
| 4359 | } |
| 4360 | } |
| 4361 | |
| 4362 | function surroundContents(n) { |
| 4363 | var f = t.extractContents(); |
| 4364 | |
| 4365 | t.insertNode(n); |
| 4366 | n.appendChild(f); |
| 4367 | t.selectNode(n); |
| 4368 | } |
| 4369 | |
| 4370 | function cloneRange() { |
| 4371 | return extend(new Range(dom), { |
| 4372 | startContainer: t[START_CONTAINER], |
| 4373 | startOffset: t[START_OFFSET], |
| 4374 | endContainer: t[END_CONTAINER], |
| 4375 | endOffset: t[END_OFFSET], |
| 4376 | collapsed: t.collapsed, |
| 4377 | commonAncestorContainer: t.commonAncestorContainer |
| 4378 | }); |
| 4379 | } |
| 4380 | |
| 4381 | // Private methods |
| 4382 | |
| 4383 | function _getSelectedNode(container, offset) { |
| 4384 | var child; |
| 4385 | |
| 4386 | if (container.nodeType == 3 /* TEXT_NODE */) { |
| 4387 | return container; |
| 4388 | } |
| 4389 | |
| 4390 | if (offset < 0) { |
| 4391 | return container; |
| 4392 | } |
| 4393 | |
| 4394 | child = container.firstChild; |
| 4395 | while (child && offset > 0) { |
| 4396 | --offset; |
| 4397 | child = child.nextSibling; |
| 4398 | } |
| 4399 | |
| 4400 | if (child) { |
| 4401 | return child; |
| 4402 | } |
| 4403 | |
| 4404 | return container; |
| 4405 | } |
| 4406 | |
| 4407 | function _isCollapsed() { |
| 4408 | return (t[START_CONTAINER] == t[END_CONTAINER] && t[START_OFFSET] == t[END_OFFSET]); |
| 4409 | } |
| 4410 | |
| 4411 | function _compareBoundaryPoints(containerA, offsetA, containerB, offsetB) { |
| 4412 | var c, offsetC, n, cmnRoot, childA, childB; |
| 4413 | |
| 4414 | // In the first case the boundary-points have the same container. A is before B |
| 4415 | // if its offset is less than the offset of B, A is equal to B if its offset is |
| 4416 | // equal to the offset of B, and A is after B if its offset is greater than the |
| 4417 | // offset of B. |
| 4418 | if (containerA == containerB) { |
| 4419 | if (offsetA == offsetB) { |
| 4420 | return 0; // equal |
| 4421 | } |
| 4422 | |
| 4423 | if (offsetA < offsetB) { |
| 4424 | return -1; // before |
| 4425 | } |
| 4426 | |
| 4427 | return 1; // after |
| 4428 | } |
| 4429 | |
| 4430 | // In the second case a child node C of the container of A is an ancestor |
| 4431 | // container of B. In this case, A is before B if the offset of A is less than or |
| 4432 | // equal to the index of the child node C and A is after B otherwise. |
| 4433 | c = containerB; |
| 4434 | while (c && c.parentNode != containerA) { |
| 4435 | c = c.parentNode; |
| 4436 | } |
| 4437 | |
| 4438 | if (c) { |
| 4439 | offsetC = 0; |
| 4440 | n = containerA.firstChild; |
| 4441 | |
| 4442 | while (n != c && offsetC < offsetA) { |
| 4443 | offsetC++; |
| 4444 | n = n.nextSibling; |
| 4445 | } |
| 4446 | |
| 4447 | if (offsetA <= offsetC) { |
| 4448 | return -1; // before |
| 4449 | } |
| 4450 | |
| 4451 | return 1; // after |
| 4452 | } |
| 4453 | |
| 4454 | // In the third case a child node C of the container of B is an ancestor container |
| 4455 | // of A. In this case, A is before B if the index of the child node C is less than |
| 4456 | // the offset of B and A is after B otherwise. |
| 4457 | c = containerA; |
| 4458 | while (c && c.parentNode != containerB) { |
| 4459 | c = c.parentNode; |
| 4460 | } |
| 4461 | |
| 4462 | if (c) { |
| 4463 | offsetC = 0; |
| 4464 | n = containerB.firstChild; |
| 4465 | |
| 4466 | while (n != c && offsetC < offsetB) { |
| 4467 | offsetC++; |
| 4468 | n = n.nextSibling; |
| 4469 | } |
| 4470 | |
| 4471 | if (offsetC < offsetB) { |
| 4472 | return -1; // before |
| 4473 | } |
| 4474 | |
| 4475 | return 1; // after |
| 4476 | } |
| 4477 | |
| 4478 | // In the fourth case, none of three other cases hold: the containers of A and B |
| 4479 | // are siblings or descendants of sibling nodes. In this case, A is before B if |
| 4480 | // the container of A is before the container of B in a pre-order traversal of the |
| 4481 | // Ranges' context tree and A is after B otherwise. |
| 4482 | cmnRoot = dom.findCommonAncestor(containerA, containerB); |
| 4483 | childA = containerA; |
| 4484 | |
| 4485 | while (childA && childA.parentNode != cmnRoot) { |
| 4486 | childA = childA.parentNode; |
| 4487 | } |
| 4488 | |
| 4489 | if (!childA) { |
| 4490 | childA = cmnRoot; |
| 4491 | } |
| 4492 | |
| 4493 | childB = containerB; |
| 4494 | while (childB && childB.parentNode != cmnRoot) { |
| 4495 | childB = childB.parentNode; |
| 4496 | } |
| 4497 | |
| 4498 | if (!childB) { |
| 4499 | childB = cmnRoot; |
| 4500 | } |
| 4501 | |
| 4502 | if (childA == childB) { |
| 4503 | return 0; // equal |
| 4504 | } |
| 4505 | |
| 4506 | n = cmnRoot.firstChild; |
| 4507 | while (n) { |
| 4508 | if (n == childA) { |
| 4509 | return -1; // before |
| 4510 | } |
| 4511 | |
| 4512 | if (n == childB) { |
| 4513 | return 1; // after |
| 4514 | } |
| 4515 | |
| 4516 | n = n.nextSibling; |
| 4517 | } |
| 4518 | } |
| 4519 | |
| 4520 | function _setEndPoint(st, n, o) { |
| 4521 | var ec, sc; |
| 4522 | |
| 4523 | if (st) { |
| 4524 | t[START_CONTAINER] = n; |
| 4525 | t[START_OFFSET] = o; |
| 4526 | } else { |
| 4527 | t[END_CONTAINER] = n; |
| 4528 | t[END_OFFSET] = o; |
| 4529 | } |
| 4530 | |
| 4531 | // If one boundary-point of a Range is set to have a root container |
| 4532 | // other than the current one for the Range, the Range is collapsed to |
| 4533 | // the new position. This enforces the restriction that both boundary- |
| 4534 | // points of a Range must have the same root container. |
| 4535 | ec = t[END_CONTAINER]; |
| 4536 | while (ec.parentNode) { |
| 4537 | ec = ec.parentNode; |
| 4538 | } |
| 4539 | |
| 4540 | sc = t[START_CONTAINER]; |
| 4541 | while (sc.parentNode) { |
| 4542 | sc = sc.parentNode; |
| 4543 | } |
| 4544 | |
| 4545 | if (sc == ec) { |
| 4546 | // The start position of a Range is guaranteed to never be after the |
| 4547 | // end position. To enforce this restriction, if the start is set to |
| 4548 | // be at a position after the end, the Range is collapsed to that |
| 4549 | // position. |
| 4550 | if (_compareBoundaryPoints(t[START_CONTAINER], t[START_OFFSET], t[END_CONTAINER], t[END_OFFSET]) > 0) { |
| 4551 | t.collapse(st); |
| 4552 | } |
| 4553 | } else { |
| 4554 | t.collapse(st); |
| 4555 | } |
| 4556 | |
| 4557 | t.collapsed = _isCollapsed(); |
| 4558 | t.commonAncestorContainer = dom.findCommonAncestor(t[START_CONTAINER], t[END_CONTAINER]); |
| 4559 | } |
| 4560 | |
| 4561 | function _traverse(how) { |
| 4562 | var c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep; |
| 4563 | |
| 4564 | if (t[START_CONTAINER] == t[END_CONTAINER]) { |
| 4565 | return _traverseSameContainer(how); |
| 4566 | } |
| 4567 | |
| 4568 | for (c = t[END_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) { |
| 4569 | if (p == t[START_CONTAINER]) { |
| 4570 | return _traverseCommonStartContainer(c, how); |
| 4571 | } |
| 4572 | |
| 4573 | ++endContainerDepth; |
| 4574 | } |
| 4575 | |
| 4576 | for (c = t[START_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) { |
| 4577 | if (p == t[END_CONTAINER]) { |
| 4578 | return _traverseCommonEndContainer(c, how); |
| 4579 | } |
| 4580 | |
| 4581 | ++startContainerDepth; |
| 4582 | } |
| 4583 | |
| 4584 | depthDiff = startContainerDepth - endContainerDepth; |
| 4585 | |
| 4586 | startNode = t[START_CONTAINER]; |
| 4587 | while (depthDiff > 0) { |
| 4588 | startNode = startNode.parentNode; |
| 4589 | depthDiff--; |
| 4590 | } |
| 4591 | |
| 4592 | endNode = t[END_CONTAINER]; |
| 4593 | while (depthDiff < 0) { |
| 4594 | endNode = endNode.parentNode; |
| 4595 | depthDiff++; |
| 4596 | } |
| 4597 | |
| 4598 | // ascend the ancestor hierarchy until we have a common parent. |
| 4599 | for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) { |
| 4600 | startNode = sp; |
| 4601 | endNode = ep; |
| 4602 | } |
| 4603 | |
| 4604 | return _traverseCommonAncestors(startNode, endNode, how); |
| 4605 | } |
| 4606 | |
| 4607 | function _traverseSameContainer(how) { |
| 4608 | var frag, s, sub, n, cnt, sibling, xferNode, start, len; |
| 4609 | |
| 4610 | if (how != DELETE) { |
| 4611 | frag = createDocumentFragment(); |
| 4612 | } |
| 4613 | |
| 4614 | // If selection is empty, just return the fragment |
| 4615 | if (t[START_OFFSET] == t[END_OFFSET]) { |
| 4616 | return frag; |
| 4617 | } |
| 4618 | |
| 4619 | // Text node needs special case handling |
| 4620 | if (t[START_CONTAINER].nodeType == 3 /* TEXT_NODE */) { |
| 4621 | // get the substring |
| 4622 | s = t[START_CONTAINER].nodeValue; |
| 4623 | sub = s.substring(t[START_OFFSET], t[END_OFFSET]); |
| 4624 | |
| 4625 | // set the original text node to its new value |
| 4626 | if (how != CLONE) { |
| 4627 | n = t[START_CONTAINER]; |
| 4628 | start = t[START_OFFSET]; |
| 4629 | len = t[END_OFFSET] - t[START_OFFSET]; |
| 4630 | |
| 4631 | if (start === 0 && len >= n.nodeValue.length - 1) { |
| 4632 | n.parentNode.removeChild(n); |
| 4633 | } else { |
| 4634 | n.deleteData(start, len); |
| 4635 | } |
| 4636 | |
| 4637 | // Nothing is partially selected, so collapse to start point |
| 4638 | t.collapse(TRUE); |
| 4639 | } |
| 4640 | |
| 4641 | if (how == DELETE) { |
| 4642 | return; |
| 4643 | } |
| 4644 | |
| 4645 | if (sub.length > 0) { |
| 4646 | frag.appendChild(doc.createTextNode(sub)); |
| 4647 | } |
| 4648 | |
| 4649 | return frag; |
| 4650 | } |
| 4651 | |
| 4652 | // Copy nodes between the start/end offsets. |
| 4653 | n = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]); |
| 4654 | cnt = t[END_OFFSET] - t[START_OFFSET]; |
| 4655 | |
| 4656 | while (n && cnt > 0) { |
| 4657 | sibling = n.nextSibling; |
| 4658 | xferNode = _traverseFullySelected(n, how); |
| 4659 | |
| 4660 | if (frag) { |
| 4661 | frag.appendChild(xferNode); |
| 4662 | } |
| 4663 | |
| 4664 | --cnt; |
| 4665 | n = sibling; |
| 4666 | } |
| 4667 | |
| 4668 | // Nothing is partially selected, so collapse to start point |
| 4669 | if (how != CLONE) { |
| 4670 | t.collapse(TRUE); |
| 4671 | } |
| 4672 | |
| 4673 | return frag; |
| 4674 | } |
| 4675 | |
| 4676 | function _traverseCommonStartContainer(endAncestor, how) { |
| 4677 | var frag, n, endIdx, cnt, sibling, xferNode; |
| 4678 | |
| 4679 | if (how != DELETE) { |
| 4680 | frag = createDocumentFragment(); |
| 4681 | } |
| 4682 | |
| 4683 | n = _traverseRightBoundary(endAncestor, how); |
| 4684 | |
| 4685 | if (frag) { |
| 4686 | frag.appendChild(n); |
| 4687 | } |
| 4688 | |
| 4689 | endIdx = nodeIndex(endAncestor); |
| 4690 | cnt = endIdx - t[START_OFFSET]; |
| 4691 | |
| 4692 | if (cnt <= 0) { |
| 4693 | // Collapse to just before the endAncestor, which |
| 4694 | // is partially selected. |
| 4695 | if (how != CLONE) { |
| 4696 | t.setEndBefore(endAncestor); |
| 4697 | t.collapse(FALSE); |
| 4698 | } |
| 4699 | |
| 4700 | return frag; |
| 4701 | } |
| 4702 | |
| 4703 | n = endAncestor.previousSibling; |
| 4704 | while (cnt > 0) { |
| 4705 | sibling = n.previousSibling; |
| 4706 | xferNode = _traverseFullySelected(n, how); |
| 4707 | |
| 4708 | if (frag) { |
| 4709 | frag.insertBefore(xferNode, frag.firstChild); |
| 4710 | } |
| 4711 | |
| 4712 | --cnt; |
| 4713 | n = sibling; |
| 4714 | } |
| 4715 | |
| 4716 | // Collapse to just before the endAncestor, which |
| 4717 | // is partially selected. |
| 4718 | if (how != CLONE) { |
| 4719 | t.setEndBefore(endAncestor); |
| 4720 | t.collapse(FALSE); |
| 4721 | } |
| 4722 | |
| 4723 | return frag; |
| 4724 | } |
| 4725 | |
| 4726 | function _traverseCommonEndContainer(startAncestor, how) { |
| 4727 | var frag, startIdx, n, cnt, sibling, xferNode; |
| 4728 | |
| 4729 | if (how != DELETE) { |
| 4730 | frag = createDocumentFragment(); |
| 4731 | } |
| 4732 | |
| 4733 | n = _traverseLeftBoundary(startAncestor, how); |
| 4734 | if (frag) { |
| 4735 | frag.appendChild(n); |
| 4736 | } |
| 4737 | |
| 4738 | startIdx = nodeIndex(startAncestor); |
| 4739 | ++startIdx; // Because we already traversed it |
| 4740 | |
| 4741 | cnt = t[END_OFFSET] - startIdx; |
| 4742 | n = startAncestor.nextSibling; |
| 4743 | while (n && cnt > 0) { |
| 4744 | sibling = n.nextSibling; |
| 4745 | xferNode = _traverseFullySelected(n, how); |
| 4746 | |
| 4747 | if (frag) { |
| 4748 | frag.appendChild(xferNode); |
| 4749 | } |
| 4750 | |
| 4751 | --cnt; |
| 4752 | n = sibling; |
| 4753 | } |
| 4754 | |
| 4755 | if (how != CLONE) { |
| 4756 | t.setStartAfter(startAncestor); |
| 4757 | t.collapse(TRUE); |
| 4758 | } |
| 4759 | |
| 4760 | return frag; |
| 4761 | } |
| 4762 | |
| 4763 | function _traverseCommonAncestors(startAncestor, endAncestor, how) { |
| 4764 | var n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling; |
| 4765 | |
| 4766 | if (how != DELETE) { |
| 4767 | frag = createDocumentFragment(); |
| 4768 | } |
| 4769 | |
| 4770 | n = _traverseLeftBoundary(startAncestor, how); |
| 4771 | if (frag) { |
| 4772 | frag.appendChild(n); |
| 4773 | } |
| 4774 | |
| 4775 | commonParent = startAncestor.parentNode; |
| 4776 | startOffset = nodeIndex(startAncestor); |
| 4777 | endOffset = nodeIndex(endAncestor); |
| 4778 | ++startOffset; |
| 4779 | |
| 4780 | cnt = endOffset - startOffset; |
| 4781 | sibling = startAncestor.nextSibling; |
| 4782 | |
| 4783 | while (cnt > 0) { |
| 4784 | nextSibling = sibling.nextSibling; |
| 4785 | n = _traverseFullySelected(sibling, how); |
| 4786 | |
| 4787 | if (frag) { |
| 4788 | frag.appendChild(n); |
| 4789 | } |
| 4790 | |
| 4791 | sibling = nextSibling; |
| 4792 | --cnt; |
| 4793 | } |
| 4794 | |
| 4795 | n = _traverseRightBoundary(endAncestor, how); |
| 4796 | |
| 4797 | if (frag) { |
| 4798 | frag.appendChild(n); |
| 4799 | } |
| 4800 | |
| 4801 | if (how != CLONE) { |
| 4802 | t.setStartAfter(startAncestor); |
| 4803 | t.collapse(TRUE); |
| 4804 | } |
| 4805 | |
| 4806 | return frag; |
| 4807 | } |
| 4808 | |
| 4809 | function _traverseRightBoundary(root, how) { |
| 4810 | var next = _getSelectedNode(t[END_CONTAINER], t[END_OFFSET] - 1), parent, clonedParent; |
| 4811 | var prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != t[END_CONTAINER]; |
| 4812 | |
| 4813 | if (next == root) { |
| 4814 | return _traverseNode(next, isFullySelected, FALSE, how); |
| 4815 | } |
| 4816 | |
| 4817 | parent = next.parentNode; |
| 4818 | clonedParent = _traverseNode(parent, FALSE, FALSE, how); |
| 4819 | |
| 4820 | while (parent) { |
| 4821 | while (next) { |
| 4822 | prevSibling = next.previousSibling; |
| 4823 | clonedChild = _traverseNode(next, isFullySelected, FALSE, how); |
| 4824 | |
| 4825 | if (how != DELETE) { |
| 4826 | clonedParent.insertBefore(clonedChild, clonedParent.firstChild); |
| 4827 | } |
| 4828 | |
| 4829 | isFullySelected = TRUE; |
| 4830 | next = prevSibling; |
| 4831 | } |
| 4832 | |
| 4833 | if (parent == root) { |
| 4834 | return clonedParent; |
| 4835 | } |
| 4836 | |
| 4837 | next = parent.previousSibling; |
| 4838 | parent = parent.parentNode; |
| 4839 | |
| 4840 | clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how); |
| 4841 | |
| 4842 | if (how != DELETE) { |
| 4843 | clonedGrandParent.appendChild(clonedParent); |
| 4844 | } |
| 4845 | |
| 4846 | clonedParent = clonedGrandParent; |
| 4847 | } |
| 4848 | } |
| 4849 | |
| 4850 | function _traverseLeftBoundary(root, how) { |
| 4851 | var next = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]), isFullySelected = next != t[START_CONTAINER]; |
| 4852 | var parent, clonedParent, nextSibling, clonedChild, clonedGrandParent; |
| 4853 | |
| 4854 | if (next == root) { |
| 4855 | return _traverseNode(next, isFullySelected, TRUE, how); |
| 4856 | } |
| 4857 | |
| 4858 | parent = next.parentNode; |
| 4859 | clonedParent = _traverseNode(parent, FALSE, TRUE, how); |
| 4860 | |
| 4861 | while (parent) { |
| 4862 | while (next) { |
| 4863 | nextSibling = next.nextSibling; |
| 4864 | clonedChild = _traverseNode(next, isFullySelected, TRUE, how); |
| 4865 | |
| 4866 | if (how != DELETE) { |
| 4867 | clonedParent.appendChild(clonedChild); |
| 4868 | } |
| 4869 | |
| 4870 | isFullySelected = TRUE; |
| 4871 | next = nextSibling; |
| 4872 | } |
| 4873 | |
| 4874 | if (parent == root) { |
| 4875 | return clonedParent; |
| 4876 | } |
| 4877 | |
| 4878 | next = parent.nextSibling; |
| 4879 | parent = parent.parentNode; |
| 4880 | |
| 4881 | clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how); |
| 4882 | |
| 4883 | if (how != DELETE) { |
| 4884 | clonedGrandParent.appendChild(clonedParent); |
| 4885 | } |
| 4886 | |
| 4887 | clonedParent = clonedGrandParent; |
| 4888 | } |
| 4889 | } |
| 4890 | |
| 4891 | function _traverseNode(n, isFullySelected, isLeft, how) { |
| 4892 | var txtValue, newNodeValue, oldNodeValue, offset, newNode; |
| 4893 | |
| 4894 | if (isFullySelected) { |
| 4895 | return _traverseFullySelected(n, how); |
| 4896 | } |
| 4897 | |
| 4898 | if (n.nodeType == 3 /* TEXT_NODE */) { |
| 4899 | txtValue = n.nodeValue; |
| 4900 | |
| 4901 | if (isLeft) { |
| 4902 | offset = t[START_OFFSET]; |
| 4903 | newNodeValue = txtValue.substring(offset); |
| 4904 | oldNodeValue = txtValue.substring(0, offset); |
| 4905 | } else { |
| 4906 | offset = t[END_OFFSET]; |
| 4907 | newNodeValue = txtValue.substring(0, offset); |
| 4908 | oldNodeValue = txtValue.substring(offset); |
| 4909 | } |
| 4910 | |
| 4911 | if (how != CLONE) { |
| 4912 | n.nodeValue = oldNodeValue; |
| 4913 | } |
| 4914 | |
| 4915 | if (how == DELETE) { |
| 4916 | return; |
| 4917 | } |
| 4918 | |
| 4919 | newNode = dom.clone(n, FALSE); |
| 4920 | newNode.nodeValue = newNodeValue; |
| 4921 | |
| 4922 | return newNode; |
| 4923 | } |
| 4924 | |
| 4925 | if (how == DELETE) { |
| 4926 | return; |
| 4927 | } |
| 4928 | |
| 4929 | return dom.clone(n, FALSE); |
| 4930 | } |
| 4931 | |
| 4932 | function _traverseFullySelected(n, how) { |
| 4933 | if (how != DELETE) { |
| 4934 | return how == CLONE ? dom.clone(n, TRUE) : n; |
| 4935 | } |
| 4936 | |
| 4937 | n.parentNode.removeChild(n); |
| 4938 | } |
| 4939 | |
| 4940 | function toStringIE() { |
| 4941 | return dom.create('body', null, cloneContents()).outerText; |
| 4942 | } |
| 4943 | |
| 4944 | extend(t, { |
| 4945 | // Inital states |
| 4946 | startContainer: doc, |
| 4947 | startOffset: 0, |
| 4948 | endContainer: doc, |
| 4949 | endOffset: 0, |
| 4950 | collapsed: TRUE, |
| 4951 | commonAncestorContainer: doc, |
| 4952 | |
| 4953 | // Range constants |
| 4954 | START_TO_START: 0, |
| 4955 | START_TO_END: 1, |
| 4956 | END_TO_END: 2, |
| 4957 | END_TO_START: 3, |
| 4958 | |
| 4959 | // Public methods |
| 4960 | setStart: setStart, |
| 4961 | setEnd: setEnd, |
| 4962 | setStartBefore: setStartBefore, |
| 4963 | setStartAfter: setStartAfter, |
| 4964 | setEndBefore: setEndBefore, |
| 4965 | setEndAfter: setEndAfter, |
| 4966 | collapse: collapse, |
| 4967 | selectNode: selectNode, |
| 4968 | selectNodeContents: selectNodeContents, |
| 4969 | compareBoundaryPoints: compareBoundaryPoints, |
| 4970 | deleteContents: deleteContents, |
| 4971 | extractContents: extractContents, |
| 4972 | cloneContents: cloneContents, |
| 4973 | insertNode: insertNode, |
| 4974 | surroundContents: surroundContents, |
| 4975 | cloneRange: cloneRange, |
| 4976 | toStringIE: toStringIE |
| 4977 | }); |
| 4978 | |
| 4979 | return t; |
| 4980 | } |
| 4981 | |
| 4982 | // Older IE versions doesn't let you override toString by it's constructor so we have to stick it in the prototype |
| 4983 | Range.prototype.toString = function() { |
| 4984 | return this.toStringIE(); |
| 4985 | }; |
| 4986 | |
| 4987 | return Range; |
| 4988 | }); |
| 4989 | |
| 4990 | // Included from: js/tinymce/classes/html/Entities.js |
| 4991 | |
| 4992 | /** |
| 4993 | * Entities.js |
| 4994 | * |
| 4995 | * Copyright, Moxiecode Systems AB |
| 4996 | * Released under LGPL License. |
| 4997 | * |
| 4998 | * License: http://www.tinymce.com/license |
| 4999 | * Contributing: http://www.tinymce.com/contributing |
| 5000 | */ |
| 5001 | |
| 5002 | /*jshint bitwise:false */ |
| 5003 | |
| 5004 | /** |
| 5005 | * Entity encoder class. |
| 5006 | * |
| 5007 | * @class tinymce.html.Entities |
| 5008 | * @static |
| 5009 | * @version 3.4 |
| 5010 | */ |
| 5011 | define("tinymce/html/Entities", [ |
| 5012 | "tinymce/util/Tools" |
| 5013 | ], function(Tools) { |
| 5014 | var makeMap = Tools.makeMap; |
| 5015 | |
| 5016 | var namedEntities, baseEntities, reverseEntities, |
| 5017 | attrsCharsRegExp = /[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, |
| 5018 | textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, |
| 5019 | rawCharsRegExp = /[<>&\"\']/g, |
| 5020 | entityRegExp = /&(#x|#)?([\w]+);/g, |
| 5021 | asciiMap = { |
| 5022 | 128: "\u20AC", 130: "\u201A", 131: "\u0192", 132: "\u201E", 133: "\u2026", 134: "\u2020", |
| 5023 | 135: "\u2021", 136: "\u02C6", 137: "\u2030", 138: "\u0160", 139: "\u2039", 140: "\u0152", |
| 5024 | 142: "\u017D", 145: "\u2018", 146: "\u2019", 147: "\u201C", 148: "\u201D", 149: "\u2022", |
| 5025 | 150: "\u2013", 151: "\u2014", 152: "\u02DC", 153: "\u2122", 154: "\u0161", 155: "\u203A", |
| 5026 | 156: "\u0153", 158: "\u017E", 159: "\u0178" |
| 5027 | }; |
| 5028 | |
| 5029 | // Raw entities |
| 5030 | baseEntities = { |
| 5031 | '\"': '"', // Needs to be escaped since the YUI compressor would otherwise break the code |
| 5032 | "'": ''', |
| 5033 | '<': '<', |
| 5034 | '>': '>', |
| 5035 | '&': '&' |
| 5036 | }; |
| 5037 | |
| 5038 | // Reverse lookup table for raw entities |
| 5039 | reverseEntities = { |
| 5040 | '<': '<', |
| 5041 | '>': '>', |
| 5042 | '&': '&', |
| 5043 | '"': '"', |
| 5044 | ''': "'" |
| 5045 | }; |
| 5046 | |
| 5047 | // Decodes text by using the browser |
| 5048 | function nativeDecode(text) { |
| 5049 | var elm; |
| 5050 | |
| 5051 | elm = document.createElement("div"); |
| 5052 | elm.innerHTML = text; |
| 5053 | |
| 5054 | return elm.textContent || elm.innerText || text; |
| 5055 | } |
| 5056 | |
| 5057 | // Build a two way lookup table for the entities |
| 5058 | function buildEntitiesLookup(items, radix) { |
| 5059 | var i, chr, entity, lookup = {}; |
| 5060 | |
| 5061 | if (items) { |
| 5062 | items = items.split(','); |
| 5063 | radix = radix || 10; |
| 5064 | |
| 5065 | // Build entities lookup table |
| 5066 | for (i = 0; i < items.length; i += 2) { |
| 5067 | chr = String.fromCharCode(parseInt(items[i], radix)); |
| 5068 | |
| 5069 | // Only add non base entities |
| 5070 | if (!baseEntities[chr]) { |
| 5071 | entity = '&' + items[i + 1] + ';'; |
| 5072 | lookup[chr] = entity; |
| 5073 | lookup[entity] = chr; |
| 5074 | } |
| 5075 | } |
| 5076 | |
| 5077 | return lookup; |
| 5078 | } |
| 5079 | } |
| 5080 | |
| 5081 | // Unpack entities lookup where the numbers are in radix 32 to reduce the size |
| 5082 | namedEntities = buildEntitiesLookup( |
| 5083 | '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + |
| 5084 | '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + |
| 5085 | '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + |
| 5086 | '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + |
| 5087 | '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + |
| 5088 | '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + |
| 5089 | '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + |
| 5090 | '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + |
| 5091 | '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + |
| 5092 | '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + |
| 5093 | 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + |
| 5094 | 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + |
| 5095 | 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + |
| 5096 | 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + |
| 5097 | 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + |
| 5098 | '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + |
| 5099 | '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + |
| 5100 | '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + |
| 5101 | '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + |
| 5102 | '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + |
| 5103 | 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + |
| 5104 | 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + |
| 5105 | 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + |
| 5106 | '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + |
| 5107 | '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32); |
| 5108 | |
| 5109 | var Entities = { |
| 5110 | /** |
| 5111 | * Encodes the specified string using raw entities. This means only the required XML base entities will be endoded. |
| 5112 | * |
| 5113 | * @method encodeRaw |
| 5114 | * @param {String} text Text to encode. |
| 5115 | * @param {Boolean} attr Optional flag to specify if the text is attribute contents. |
| 5116 | * @return {String} Entity encoded text. |
| 5117 | */ |
| 5118 | encodeRaw: function(text, attr) { |
| 5119 | return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) { |
| 5120 | return baseEntities[chr] || chr; |
| 5121 | }); |
| 5122 | }, |
| 5123 | |
| 5124 | /** |
| 5125 | * Encoded the specified text with both the attributes and text entities. This function will produce larger text contents |
| 5126 | * since it doesn't know if the context is within a attribute or text node. This was added for compatibility |
| 5127 | * and is exposed as the DOMUtils.encode function. |
| 5128 | * |
| 5129 | * @method encodeAllRaw |
| 5130 | * @param {String} text Text to encode. |
| 5131 | * @return {String} Entity encoded text. |
| 5132 | */ |
| 5133 | encodeAllRaw: function(text) { |
| 5134 | return ('' + text).replace(rawCharsRegExp, function(chr) { |
| 5135 | return baseEntities[chr] || chr; |
| 5136 | }); |
| 5137 | }, |
| 5138 | |
| 5139 | /** |
| 5140 | * Encodes the specified string using numeric entities. The core entities will be |
| 5141 | * encoded as named ones but all non lower ascii characters will be encoded into numeric entities. |
| 5142 | * |
| 5143 | * @method encodeNumeric |
| 5144 | * @param {String} text Text to encode. |
| 5145 | * @param {Boolean} attr Optional flag to specify if the text is attribute contents. |
| 5146 | * @return {String} Entity encoded text. |
| 5147 | */ |
| 5148 | encodeNumeric: function(text, attr) { |
| 5149 | return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) { |
| 5150 | // Multi byte sequence convert it to a single entity |
| 5151 | if (chr.length > 1) { |
| 5152 | return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';'; |
| 5153 | } |
| 5154 | |
| 5155 | return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';'; |
| 5156 | }); |
| 5157 | }, |
| 5158 | |
| 5159 | /** |
| 5160 | * Encodes the specified string using named entities. The core entities will be encoded |
| 5161 | * as named ones but all non lower ascii characters will be encoded into named entities. |
| 5162 | * |
| 5163 | * @method encodeNamed |
| 5164 | * @param {String} text Text to encode. |
| 5165 | * @param {Boolean} attr Optional flag to specify if the text is attribute contents. |
| 5166 | * @param {Object} entities Optional parameter with entities to use. |
| 5167 | * @return {String} Entity encoded text. |
| 5168 | */ |
| 5169 | encodeNamed: function(text, attr, entities) { |
| 5170 | entities = entities || namedEntities; |
| 5171 | |
| 5172 | return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) { |
| 5173 | return baseEntities[chr] || entities[chr] || chr; |
| 5174 | }); |
| 5175 | }, |
| 5176 | |
| 5177 | /** |
| 5178 | * Returns an encode function based on the name(s) and it's optional entities. |
| 5179 | * |
| 5180 | * @method getEncodeFunc |
| 5181 | * @param {String} name Comma separated list of encoders for example named,numeric. |
| 5182 | * @param {String} entities Optional parameter with entities to use instead of the built in set. |
| 5183 | * @return {function} Encode function to be used. |
| 5184 | */ |
| 5185 | getEncodeFunc: function(name, entities) { |
| 5186 | entities = buildEntitiesLookup(entities) || namedEntities; |
| 5187 | |
| 5188 | function encodeNamedAndNumeric(text, attr) { |
| 5189 | return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) { |
| 5190 | return baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr; |
| 5191 | }); |
| 5192 | } |
| 5193 | |
| 5194 | function encodeCustomNamed(text, attr) { |
| 5195 | return Entities.encodeNamed(text, attr, entities); |
| 5196 | } |
| 5197 | |
| 5198 | // Replace + with , to be compatible with previous TinyMCE versions |
| 5199 | name = makeMap(name.replace(/\+/g, ',')); |
| 5200 | |
| 5201 | // Named and numeric encoder |
| 5202 | if (name.named && name.numeric) { |
| 5203 | return encodeNamedAndNumeric; |
| 5204 | } |
| 5205 | |
| 5206 | // Named encoder |
| 5207 | if (name.named) { |
| 5208 | // Custom names |
| 5209 | if (entities) { |
| 5210 | return encodeCustomNamed; |
| 5211 | } |
| 5212 | |
| 5213 | return Entities.encodeNamed; |
| 5214 | } |
| 5215 | |
| 5216 | // Numeric |
| 5217 | if (name.numeric) { |
| 5218 | return Entities.encodeNumeric; |
| 5219 | } |
| 5220 | |
| 5221 | // Raw encoder |
| 5222 | return Entities.encodeRaw; |
| 5223 | }, |
| 5224 | |
| 5225 | /** |
| 5226 | * Decodes the specified string, this will replace entities with raw UTF characters. |
| 5227 | * |
| 5228 | * @method decode |
| 5229 | * @param {String} text Text to entity decode. |
| 5230 | * @return {String} Entity decoded string. |
| 5231 | */ |
| 5232 | decode: function(text) { |
| 5233 | return text.replace(entityRegExp, function(all, numeric, value) { |
| 5234 | if (numeric) { |
| 5235 | value = parseInt(value, numeric.length === 2 ? 16 : 10); |
| 5236 | |
| 5237 | // Support upper UTF |
| 5238 | if (value > 0xFFFF) { |
| 5239 | value -= 0x10000; |
| 5240 | |
| 5241 | return String.fromCharCode(0xD800 + (value >> 10), 0xDC00 + (value & 0x3FF)); |
| 5242 | } else { |
| 5243 | return asciiMap[value] || String.fromCharCode(value); |
| 5244 | } |
| 5245 | } |
| 5246 | |
| 5247 | return reverseEntities[all] || namedEntities[all] || nativeDecode(all); |
| 5248 | }); |
| 5249 | } |
| 5250 | }; |
| 5251 | |
| 5252 | return Entities; |
| 5253 | }); |
| 5254 | |
| 5255 | // Included from: js/tinymce/classes/Env.js |
| 5256 | |
| 5257 | /** |
| 5258 | * Env.js |
| 5259 | * |
| 5260 | * Copyright, Moxiecode Systems AB |
| 5261 | * Released under LGPL License. |
| 5262 | * |
| 5263 | * License: http://www.tinymce.com/license |
| 5264 | * Contributing: http://www.tinymce.com/contributing |
| 5265 | */ |
| 5266 | |
| 5267 | /** |
| 5268 | * This class contains various environment constants like browser versions etc. |
| 5269 | * Normally you don't want to sniff specific browser versions but sometimes you have |
| 5270 | * to when it's impossible to feature detect. So use this with care. |
| 5271 | * |
| 5272 | * @class tinymce.Env |
| 5273 | * @static |
| 5274 | */ |
| 5275 | define("tinymce/Env", [], function() { |
| 5276 | var nav = navigator, userAgent = nav.userAgent; |
| 5277 | var opera, webkit, ie, ie11, gecko, mac, iDevice; |
| 5278 | |
| 5279 | opera = window.opera && window.opera.buildNumber; |
| 5280 | webkit = /WebKit/.test(userAgent); |
| 5281 | ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName); |
| 5282 | ie = ie && /MSIE (\w+)\./.exec(userAgent)[1]; |
| 5283 | ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false; |
| 5284 | ie = ie || ie11; |
| 5285 | gecko = !webkit && !ie11 && /Gecko/.test(userAgent); |
| 5286 | mac = userAgent.indexOf('Mac') != -1; |
| 5287 | iDevice = /(iPad|iPhone)/.test(userAgent); |
| 5288 | |
| 5289 | // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions |
| 5290 | // says it has contentEditable support but there is no visible caret. |
| 5291 | var contentEditable = !iDevice || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534; |
| 5292 | |
| 5293 | return { |
| 5294 | /** |
| 5295 | * Constant that is true if the browser is Opera. |
| 5296 | * |
| 5297 | * @property opera |
| 5298 | * @type Boolean |
| 5299 | * @final |
| 5300 | */ |
| 5301 | opera: opera, |
| 5302 | |
| 5303 | /** |
| 5304 | * Constant that is true if the browser is WebKit (Safari/Chrome). |
| 5305 | * |
| 5306 | * @property webKit |
| 5307 | * @type Boolean |
| 5308 | * @final |
| 5309 | */ |
| 5310 | webkit: webkit, |
| 5311 | |
| 5312 | /** |
| 5313 | * Constant that is more than zero if the browser is IE. |
| 5314 | * |
| 5315 | * @property ie |
| 5316 | * @type Boolean |
| 5317 | * @final |
| 5318 | */ |
| 5319 | ie: ie, |
| 5320 | |
| 5321 | /** |
| 5322 | * Constant that is true if the browser is Gecko. |
| 5323 | * |
| 5324 | * @property gecko |
| 5325 | * @type Boolean |
| 5326 | * @final |
| 5327 | */ |
| 5328 | gecko: gecko, |
| 5329 | |
| 5330 | /** |
| 5331 | * Constant that is true if the os is Mac OS. |
| 5332 | * |
| 5333 | * @property mac |
| 5334 | * @type Boolean |
| 5335 | * @final |
| 5336 | */ |
| 5337 | mac: mac, |
| 5338 | |
| 5339 | /** |
| 5340 | * Constant that is true if the os is iOS. |
| 5341 | * |
| 5342 | * @property iOS |
| 5343 | * @type Boolean |
| 5344 | * @final |
| 5345 | */ |
| 5346 | iOS: iDevice, |
| 5347 | |
| 5348 | /** |
| 5349 | * Constant that is true if the browser supports editing. |
| 5350 | * |
| 5351 | * @property contentEditable |
| 5352 | * @type Boolean |
| 5353 | * @final |
| 5354 | */ |
| 5355 | contentEditable: contentEditable, |
| 5356 | |
| 5357 | /** |
| 5358 | * Transparent image data url. |
| 5359 | * |
| 5360 | * @property transparentSrc |
| 5361 | * @type Boolean |
| 5362 | * @final |
| 5363 | */ |
| 5364 | transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", |
| 5365 | |
| 5366 | /** |
| 5367 | * Returns true/false if the browser can or can't place the caret after a inline block like an image. |
| 5368 | * |
| 5369 | * @property noCaretAfter |
| 5370 | * @type Boolean |
| 5371 | * @final |
| 5372 | */ |
| 5373 | caretAfter: ie != 8, |
| 5374 | |
| 5375 | /** |
| 5376 | * Constant that is true if the browser supports native DOM Ranges. IE 9+. |
| 5377 | * |
| 5378 | * @property range |
| 5379 | * @type Boolean |
| 5380 | */ |
| 5381 | range: window.getSelection && "Range" in window, |
| 5382 | |
| 5383 | /** |
| 5384 | * Returns the IE document mode for non IE browsers this will fake IE 10. |
| 5385 | * |
| 5386 | * @property documentMode |
| 5387 | * @type Number |
| 5388 | */ |
| 5389 | documentMode: ie ? (document.documentMode || 7) : 10 |
| 5390 | }; |
| 5391 | }); |
| 5392 | |
| 5393 | // Included from: js/tinymce/classes/dom/DOMUtils.js |
| 5394 | |
| 5395 | /** |
| 5396 | * DOMUtils.js |
| 5397 | * |
| 5398 | * Copyright, Moxiecode Systems AB |
| 5399 | * Released under LGPL License. |
| 5400 | * |
| 5401 | * License: http://www.tinymce.com/license |
| 5402 | * Contributing: http://www.tinymce.com/contributing |
| 5403 | */ |
| 5404 | |
| 5405 | /** |
| 5406 | * Utility class for various DOM manipulation and retrieval functions. |
| 5407 | * |
| 5408 | * @class tinymce.dom.DOMUtils |
| 5409 | * @example |
| 5410 | * // Add a class to an element by id in the page |
| 5411 | * tinymce.DOM.addClass('someid', 'someclass'); |
| 5412 | * |
| 5413 | * // Add a class to an element by id inside the editor |
| 5414 | * tinymce.activeEditor.dom.addClass('someid', 'someclass'); |
| 5415 | */ |
| 5416 | define("tinymce/dom/DOMUtils", [ |
| 5417 | "tinymce/dom/Sizzle", |
| 5418 | "tinymce/html/Styles", |
| 5419 | "tinymce/dom/EventUtils", |
| 5420 | "tinymce/dom/TreeWalker", |
| 5421 | "tinymce/dom/Range", |
| 5422 | "tinymce/html/Entities", |
| 5423 | "tinymce/Env", |
| 5424 | "tinymce/util/Tools" |
| 5425 | ], function(Sizzle, Styles, EventUtils, TreeWalker, Range, Entities, Env, Tools) { |
| 5426 | // Shorten names |
| 5427 | var each = Tools.each, is = Tools.is, grep = Tools.grep, trim = Tools.trim, extend = Tools.extend; |
| 5428 | var isWebKit = Env.webkit, isIE = Env.ie; |
| 5429 | var simpleSelectorRe = /^([a-z0-9],?)+$/i; |
| 5430 | var whiteSpaceRegExp = /^[ \t\r\n]*$/; |
| 5431 | var numericCssMap = Tools.makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom', ' '); |
| 5432 | |
| 5433 | /** |
| 5434 | * Constructs a new DOMUtils instance. Consult the Wiki for more details on settings etc for this class. |
| 5435 | * |
| 5436 | * @constructor |
| 5437 | * @method DOMUtils |
| 5438 | * @param {Document} d Document reference to bind the utility class to. |
| 5439 | * @param {settings} s Optional settings collection. |
| 5440 | */ |
| 5441 | function DOMUtils(doc, settings) { |
| 5442 | var self = this, blockElementsMap; |
| 5443 | |
| 5444 | self.doc = doc; |
| 5445 | self.win = window; |
| 5446 | self.files = {}; |
| 5447 | self.counter = 0; |
| 5448 | self.stdMode = !isIE || doc.documentMode >= 8; |
| 5449 | self.boxModel = !isIE || doc.compatMode == "CSS1Compat" || self.stdMode; |
| 5450 | self.hasOuterHTML = "outerHTML" in doc.createElement("a"); |
| 5451 | this.boundEvents = []; |
| 5452 | |
| 5453 | self.settings = settings = extend({ |
| 5454 | keep_values: false, |
| 5455 | hex_colors: 1 |
| 5456 | }, settings); |
| 5457 | |
| 5458 | self.schema = settings.schema; |
| 5459 | self.styles = new Styles({ |
| 5460 | url_converter: settings.url_converter, |
| 5461 | url_converter_scope: settings.url_converter_scope |
| 5462 | }, settings.schema); |
| 5463 | |
| 5464 | self.fixDoc(doc); |
| 5465 | self.events = settings.ownEvents ? new EventUtils(settings.proxy) : EventUtils.Event; |
| 5466 | blockElementsMap = settings.schema ? settings.schema.getBlockElements() : {}; |
| 5467 | |
| 5468 | /** |
| 5469 | * Returns true/false if the specified element is a block element or not. |
| 5470 | * |
| 5471 | * @method isBlock |
| 5472 | * @param {Node/String} node Element/Node to check. |
| 5473 | * @return {Boolean} True/False state if the node is a block element or not. |
| 5474 | */ |
| 5475 | self.isBlock = function(node) { |
| 5476 | // Fix for #5446 |
| 5477 | if (!node) { |
| 5478 | return false; |
| 5479 | } |
| 5480 | |
| 5481 | // This function is called in module pattern style since it might be executed with the wrong this scope |
| 5482 | var type = node.nodeType; |
| 5483 | |
| 5484 | // If it's a node then check the type and use the nodeName |
| 5485 | if (type) { |
| 5486 | return !!(type === 1 && blockElementsMap[node.nodeName]); |
| 5487 | } |
| 5488 | |
| 5489 | return !!blockElementsMap[node]; |
| 5490 | }; |
| 5491 | } |
| 5492 | |
| 5493 | DOMUtils.prototype = { |
| 5494 | root: null, |
| 5495 | props: { |
| 5496 | "for": "htmlFor", |
| 5497 | "class": "className", |
| 5498 | className: "className", |
| 5499 | checked: "checked", |
| 5500 | disabled: "disabled", |
| 5501 | maxlength: "maxLength", |
| 5502 | readonly: "readOnly", |
| 5503 | selected: "selected", |
| 5504 | value: "value", |
| 5505 | id: "id", |
| 5506 | name: "name", |
| 5507 | type: "type" |
| 5508 | }, |
| 5509 | |
| 5510 | fixDoc: function(doc) { |
| 5511 | var settings = this.settings, name; |
| 5512 | |
| 5513 | if (isIE && settings.schema) { |
| 5514 | // Add missing HTML 4/5 elements to IE |
| 5515 | ('abbr article aside audio canvas ' + |
| 5516 | 'details figcaption figure footer ' + |
| 5517 | 'header hgroup mark menu meter nav ' + |
| 5518 | 'output progress section summary ' + |
| 5519 | 'time video').replace(/\w+/g, function(name) { |
| 5520 | doc.createElement(name); |
| 5521 | }); |
| 5522 | |
| 5523 | // Create all custom elements |
| 5524 | for (name in settings.schema.getCustomElements()) { |
| 5525 | doc.createElement(name); |
| 5526 | } |
| 5527 | } |
| 5528 | }, |
| 5529 | |
| 5530 | clone: function(node, deep) { |
| 5531 | var self = this, clone, doc; |
| 5532 | |
| 5533 | // TODO: Add feature detection here in the future |
| 5534 | if (!isIE || node.nodeType !== 1 || deep) { |
| 5535 | return node.cloneNode(deep); |
| 5536 | } |
| 5537 | |
| 5538 | doc = self.doc; |
| 5539 | |
| 5540 | // Make a HTML5 safe shallow copy |
| 5541 | if (!deep) { |
| 5542 | clone = doc.createElement(node.nodeName); |
| 5543 | |
| 5544 | // Copy attribs |
| 5545 | each(self.getAttribs(node), function(attr) { |
| 5546 | self.setAttrib(clone, attr.nodeName, self.getAttrib(node, attr.nodeName)); |
| 5547 | }); |
| 5548 | |
| 5549 | return clone; |
| 5550 | } |
| 5551 | /* |
| 5552 | // Setup HTML5 patched document fragment |
| 5553 | if (!self.frag) { |
| 5554 | self.frag = doc.createDocumentFragment(); |
| 5555 | self.fixDoc(self.frag); |
| 5556 | } |
| 5557 | |
| 5558 | // Make a deep copy by adding it to the document fragment then removing it this removed the :section |
| 5559 | clone = doc.createElement('div'); |
| 5560 | self.frag.appendChild(clone); |
| 5561 | clone.innerHTML = node.outerHTML; |
| 5562 | self.frag.removeChild(clone); |
| 5563 | */ |
| 5564 | return clone.firstChild; |
| 5565 | }, |
| 5566 | |
| 5567 | /** |
| 5568 | * Returns the root node of the document. This is normally the body but might be a DIV. Parents like getParent will not |
| 5569 | * go above the point of this root node. |
| 5570 | * |
| 5571 | * @method getRoot |
| 5572 | * @return {Element} Root element for the utility class. |
| 5573 | */ |
| 5574 | getRoot: function() { |
| 5575 | var self = this; |
| 5576 | |
| 5577 | return self.get(self.settings.root_element) || self.doc.body; |
| 5578 | }, |
| 5579 | |
| 5580 | /** |
| 5581 | * Returns the viewport of the window. |
| 5582 | * |
| 5583 | * @method getViewPort |
| 5584 | * @param {Window} win Optional window to get viewport of. |
| 5585 | * @return {Object} Viewport object with fields x, y, w and h. |
| 5586 | */ |
| 5587 | getViewPort: function(win) { |
| 5588 | var doc, rootElm; |
| 5589 | |
| 5590 | win = !win ? this.win : win; |
| 5591 | doc = win.document; |
| 5592 | rootElm = this.boxModel ? doc.documentElement : doc.body; |
| 5593 | |
| 5594 | // Returns viewport size excluding scrollbars |
| 5595 | return { |
| 5596 | x: win.pageXOffset || rootElm.scrollLeft, |
| 5597 | y: win.pageYOffset || rootElm.scrollTop, |
| 5598 | w: win.innerWidth || rootElm.clientWidth, |
| 5599 | h: win.innerHeight || rootElm.clientHeight |
| 5600 | }; |
| 5601 | }, |
| 5602 | |
| 5603 | /** |
| 5604 | * Returns the rectangle for a specific element. |
| 5605 | * |
| 5606 | * @method getRect |
| 5607 | * @param {Element/String} elm Element object or element ID to get rectangle from. |
| 5608 | * @return {object} Rectangle for specified element object with x, y, w, h fields. |
| 5609 | */ |
| 5610 | getRect: function(elm) { |
| 5611 | var self = this, pos, size; |
| 5612 | |
| 5613 | elm = self.get(elm); |
| 5614 | pos = self.getPos(elm); |
| 5615 | size = self.getSize(elm); |
| 5616 | |
| 5617 | return { |
| 5618 | x: pos.x, y: pos.y, |
| 5619 | w: size.w, h: size.h |
| 5620 | }; |
| 5621 | }, |
| 5622 | |
| 5623 | /** |
| 5624 | * Returns the size dimensions of the specified element. |
| 5625 | * |
| 5626 | * @method getSize |
| 5627 | * @param {Element/String} elm Element object or element ID to get rectangle from. |
| 5628 | * @return {object} Rectangle for specified element object with w, h fields. |
| 5629 | */ |
| 5630 | getSize: function(elm) { |
| 5631 | var self = this, w, h; |
| 5632 | |
| 5633 | elm = self.get(elm); |
| 5634 | w = self.getStyle(elm, 'width'); |
| 5635 | h = self.getStyle(elm, 'height'); |
| 5636 | |
| 5637 | // Non pixel value, then force offset/clientWidth |
| 5638 | if (w.indexOf('px') === -1) { |
| 5639 | w = 0; |
| 5640 | } |
| 5641 | |
| 5642 | // Non pixel value, then force offset/clientWidth |
| 5643 | if (h.indexOf('px') === -1) { |
| 5644 | h = 0; |
| 5645 | } |
| 5646 | |
| 5647 | return { |
| 5648 | w: parseInt(w, 10) || elm.offsetWidth || elm.clientWidth, |
| 5649 | h: parseInt(h, 10) || elm.offsetHeight || elm.clientHeight |
| 5650 | }; |
| 5651 | }, |
| 5652 | |
| 5653 | /** |
| 5654 | * Returns a node by the specified selector function. This function will |
| 5655 | * loop through all parent nodes and call the specified function for each node. |
| 5656 | * If the function then returns true indicating that it has found what it was looking for, the loop execution will then end |
| 5657 | * and the node it found will be returned. |
| 5658 | * |
| 5659 | * @method getParent |
| 5660 | * @param {Node/String} node DOM node to search parents on or ID string. |
| 5661 | * @param {function} selector Selection function or CSS selector to execute on each node. |
| 5662 | * @param {Node} root Optional root element, never go below this point. |
| 5663 | * @return {Node} DOM Node or null if it wasn't found. |
| 5664 | */ |
| 5665 | getParent: function(node, selector, root) { |
| 5666 | return this.getParents(node, selector, root, false); |
| 5667 | }, |
| 5668 | |
| 5669 | /** |
| 5670 | * Returns a node list of all parents matching the specified selector function or pattern. |
| 5671 | * If the function then returns true indicating that it has found what it was looking for and that node will be collected. |
| 5672 | * |
| 5673 | * @method getParents |
| 5674 | * @param {Node/String} node DOM node to search parents on or ID string. |
| 5675 | * @param {function} selector Selection function to execute on each node or CSS pattern. |
| 5676 | * @param {Node} root Optional root element, never go below this point. |
| 5677 | * @return {Array} Array of nodes or null if it wasn't found. |
| 5678 | */ |
| 5679 | getParents: function(node, selector, root, collect) { |
| 5680 | var self = this, selectorVal, result = []; |
| 5681 | |
| 5682 | node = self.get(node); |
| 5683 | collect = collect === undefined; |
| 5684 | |
| 5685 | // Default root on inline mode |
| 5686 | root = root || (self.getRoot().nodeName != 'BODY' ? self.getRoot().parentNode : null); |
| 5687 | |
| 5688 | // Wrap node name as func |
| 5689 | if (is(selector, 'string')) { |
| 5690 | selectorVal = selector; |
| 5691 | |
| 5692 | if (selector === '*') { |
| 5693 | selector = function(node) {return node.nodeType == 1;}; |
| 5694 | } else { |
| 5695 | selector = function(node) { |
| 5696 | return self.is(node, selectorVal); |
| 5697 | }; |
| 5698 | } |
| 5699 | } |
| 5700 | |
| 5701 | while (node) { |
| 5702 | if (node == root || !node.nodeType || node.nodeType === 9) { |
| 5703 | break; |
| 5704 | } |
| 5705 | |
| 5706 | if (!selector || selector(node)) { |
| 5707 | if (collect) { |
| 5708 | result.push(node); |
| 5709 | } else { |
| 5710 | return node; |
| 5711 | } |
| 5712 | } |
| 5713 | |
| 5714 | node = node.parentNode; |
| 5715 | } |
| 5716 | |
| 5717 | return collect ? result : null; |
| 5718 | }, |
| 5719 | |
| 5720 | /** |
| 5721 | * Returns the specified element by ID or the input element if it isn't a string. |
| 5722 | * |
| 5723 | * @method get |
| 5724 | * @param {String/Element} n Element id to look for or element to just pass though. |
| 5725 | * @return {Element} Element matching the specified id or null if it wasn't found. |
| 5726 | */ |
| 5727 | get: function(elm) { |
| 5728 | var name; |
| 5729 | |
| 5730 | if (elm && this.doc && typeof(elm) == 'string') { |
| 5731 | name = elm; |
| 5732 | elm = this.doc.getElementById(elm); |
| 5733 | |
| 5734 | // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick |
| 5735 | if (elm && elm.id !== name) { |
| 5736 | return this.doc.getElementsByName(name)[1]; |
| 5737 | } |
| 5738 | } |
| 5739 | |
| 5740 | return elm; |
| 5741 | }, |
| 5742 | |
| 5743 | /** |
| 5744 | * Returns the next node that matches selector or function |
| 5745 | * |
| 5746 | * @method getNext |
| 5747 | * @param {Node} node Node to find siblings from. |
| 5748 | * @param {String/function} selector Selector CSS expression or function. |
| 5749 | * @return {Node} Next node item matching the selector or null if it wasn't found. |
| 5750 | */ |
| 5751 | getNext: function(node, selector) { |
| 5752 | return this._findSib(node, selector, 'nextSibling'); |
| 5753 | }, |
| 5754 | |
| 5755 | /** |
| 5756 | * Returns the previous node that matches selector or function |
| 5757 | * |
| 5758 | * @method getPrev |
| 5759 | * @param {Node} node Node to find siblings from. |
| 5760 | * @param {String/function} selector Selector CSS expression or function. |
| 5761 | * @return {Node} Previous node item matching the selector or null if it wasn't found. |
| 5762 | */ |
| 5763 | getPrev: function(node, selector) { |
| 5764 | return this._findSib(node, selector, 'previousSibling'); |
| 5765 | }, |
| 5766 | |
| 5767 | // #ifndef jquery |
| 5768 | |
| 5769 | /** |
| 5770 | * Selects specific elements by a CSS level 3 pattern. For example "div#a1 p.test". |
| 5771 | * This function is optimized for the most common patterns needed in TinyMCE but it also performs well enough |
| 5772 | * on more complex patterns. |
| 5773 | * |
| 5774 | * @method select |
| 5775 | * @param {String} selector CSS level 3 pattern to select/find elements by. |
| 5776 | * @param {Object} scope Optional root element/scope element to search in. |
| 5777 | * @return {Array} Array with all matched elements. |
| 5778 | * @example |
| 5779 | * // Adds a class to all paragraphs in the currently active editor |
| 5780 | * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'someclass'); |
| 5781 | * |
| 5782 | * // Adds a class to all spans that have the test class in the currently active editor |
| 5783 | * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('span.test'), 'someclass') |
| 5784 | */ |
| 5785 | select: function(selector, scope) { |
| 5786 | var self = this; |
| 5787 | |
| 5788 | //Sizzle.selectors.cacheLength = 0; |
| 5789 | return Sizzle(selector, self.get(scope) || self.get(self.settings.root_element) || self.doc, []); |
| 5790 | }, |
| 5791 | |
| 5792 | /** |
| 5793 | * Returns true/false if the specified element matches the specified css pattern. |
| 5794 | * |
| 5795 | * @method is |
| 5796 | * @param {Node/NodeList} elm DOM node to match or an array of nodes to match. |
| 5797 | * @param {String} selector CSS pattern to match the element against. |
| 5798 | */ |
| 5799 | is: function(elm, selector) { |
| 5800 | var i; |
| 5801 | |
| 5802 | // If it isn't an array then try to do some simple selectors instead of Sizzle for to boost performance |
| 5803 | if (elm.length === undefined) { |
| 5804 | // Simple all selector |
| 5805 | if (selector === '*') { |
| 5806 | return elm.nodeType == 1; |
| 5807 | } |
| 5808 | |
| 5809 | // Simple selector just elements |
| 5810 | if (simpleSelectorRe.test(selector)) { |
| 5811 | selector = selector.toLowerCase().split(/,/); |
| 5812 | elm = elm.nodeName.toLowerCase(); |
| 5813 | |
| 5814 | for (i = selector.length - 1; i >= 0; i--) { |
| 5815 | if (selector[i] == elm) { |
| 5816 | return true; |
| 5817 | } |
| 5818 | } |
| 5819 | |
| 5820 | return false; |
| 5821 | } |
| 5822 | } |
| 5823 | |
| 5824 | // Is non element |
| 5825 | if (elm.nodeType && elm.nodeType != 1) { |
| 5826 | return false; |
| 5827 | } |
| 5828 | |
| 5829 | return Sizzle.matches(selector, elm.nodeType ? [elm] : elm).length > 0; |
| 5830 | }, |
| 5831 | |
| 5832 | // #endif |
| 5833 | |
| 5834 | /** |
| 5835 | * Adds the specified element to another element or elements. |
| 5836 | * |
| 5837 | * @method add |
| 5838 | * @param {String/Element/Array} parentElm Element id string, DOM node element or array of ids or elements to add to. |
| 5839 | * @param {String/Element} name Name of new element to add or existing element to add. |
| 5840 | * @param {Object} attrs Optional object collection with arguments to add to the new element(s). |
| 5841 | * @param {String} html Optional inner HTML contents to add for each element. |
| 5842 | * @return {Element/Array} Element that got created, or an array of created elements if multiple input elements |
| 5843 | * were passed in. |
| 5844 | * @example |
| 5845 | * // Adds a new paragraph to the end of the active editor |
| 5846 | * tinymce.activeEditor.dom.add(tinymce.activeEditor.getBody(), 'p', {title: 'my title'}, 'Some content'); |
| 5847 | */ |
| 5848 | add: function(parentElm, name, attrs, html, create) { |
| 5849 | var self = this; |
| 5850 | |
| 5851 | return this.run(parentElm, function(parentElm) { |
| 5852 | var newElm; |
| 5853 | |
| 5854 | newElm = is(name, 'string') ? self.doc.createElement(name) : name; |
| 5855 | self.setAttribs(newElm, attrs); |
| 5856 | |
| 5857 | if (html) { |
| 5858 | if (html.nodeType) { |
| 5859 | newElm.appendChild(html); |
| 5860 | } else { |
| 5861 | self.setHTML(newElm, html); |
| 5862 | } |
| 5863 | } |
| 5864 | |
| 5865 | return !create ? parentElm.appendChild(newElm) : newElm; |
| 5866 | }); |
| 5867 | }, |
| 5868 | |
| 5869 | /** |
| 5870 | * Creates a new element. |
| 5871 | * |
| 5872 | * @method create |
| 5873 | * @param {String} name Name of new element. |
| 5874 | * @param {Object} attrs Optional object name/value collection with element attributes. |
| 5875 | * @param {String} html Optional HTML string to set as inner HTML of the element. |
| 5876 | * @return {Element} HTML DOM node element that got created. |
| 5877 | * @example |
| 5878 | * // Adds an element where the caret/selection is in the active editor |
| 5879 | * var el = tinymce.activeEditor.dom.create('div', {id: 'test', 'class': 'myclass'}, 'some content'); |
| 5880 | * tinymce.activeEditor.selection.setNode(el); |
| 5881 | */ |
| 5882 | create: function(name, attrs, html) { |
| 5883 | return this.add(this.doc.createElement(name), name, attrs, html, 1); |
| 5884 | }, |
| 5885 | |
| 5886 | /** |
| 5887 | * Creates HTML string for element. The element will be closed unless an empty inner HTML string is passed in. |
| 5888 | * |
| 5889 | * @method createHTML |
| 5890 | * @param {String} name Name of new element. |
| 5891 | * @param {Object} attrs Optional object name/value collection with element attributes. |
| 5892 | * @param {String} html Optional HTML string to set as inner HTML of the element. |
| 5893 | * @return {String} String with new HTML element, for example: <a href="#">test</a>. |
| 5894 | * @example |
| 5895 | * // Creates a html chunk and inserts it at the current selection/caret location |
| 5896 | * tinymce.activeEditor.selection.setContent(tinymce.activeEditor.dom.createHTML('a', {href: 'test.html'}, 'some line')); |
| 5897 | */ |
| 5898 | createHTML: function(name, attrs, html) { |
| 5899 | var outHtml = '', key; |
| 5900 | |
| 5901 | outHtml += '<' + name; |
| 5902 | |
| 5903 | for (key in attrs) { |
| 5904 | if (attrs.hasOwnProperty(key) && attrs[key] !== null) { |
| 5905 | outHtml += ' ' + key + '="' + this.encode(attrs[key]) + '"'; |
| 5906 | } |
| 5907 | } |
| 5908 | |
| 5909 | // A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime |
| 5910 | if (typeof(html) != "undefined") { |
| 5911 | return outHtml + '>' + html + '</' + name + '>'; |
| 5912 | } |
| 5913 | |
| 5914 | return outHtml + ' />'; |
| 5915 | }, |
| 5916 | |
| 5917 | /** |
| 5918 | * Creates a document fragment out of the specified HTML string. |
| 5919 | * |
| 5920 | * @method createFragment |
| 5921 | * @param {String} html Html string to create fragment from. |
| 5922 | * @return {DocumentFragment} Document fragment node. |
| 5923 | */ |
| 5924 | createFragment: function(html) { |
| 5925 | var frag, node, doc = this.doc, container; |
| 5926 | |
| 5927 | container = doc.createElement("div"); |
| 5928 | frag = doc.createDocumentFragment(); |
| 5929 | |
| 5930 | if (html) { |
| 5931 | container.innerHTML = html; |
| 5932 | } |
| 5933 | |
| 5934 | while ((node = container.firstChild)) { |
| 5935 | frag.appendChild(node); |
| 5936 | } |
| 5937 | |
| 5938 | return frag; |
| 5939 | }, |
| 5940 | |
| 5941 | /** |
| 5942 | * Removes/deletes the specified element(s) from the DOM. |
| 5943 | * |
| 5944 | * @method remove |
| 5945 | * @param {String/Element/Array} node ID of element or DOM element object or array containing multiple elements/ids. |
| 5946 | * @param {Boolean} keep_children Optional state to keep children or not. If set to true all children will be |
| 5947 | * placed at the location of the removed element. |
| 5948 | * @return {Element/Array} HTML DOM element that got removed, or an array of removed elements if multiple input elements |
| 5949 | * were passed in. |
| 5950 | * @example |
| 5951 | * // Removes all paragraphs in the active editor |
| 5952 | * tinymce.activeEditor.dom.remove(tinymce.activeEditor.dom.select('p')); |
| 5953 | * |
| 5954 | * // Removes an element by id in the document |
| 5955 | * tinymce.DOM.remove('mydiv'); |
| 5956 | */ |
| 5957 | remove: function(node, keep_children) { |
| 5958 | return this.run(node, function(node) { |
| 5959 | var child, parent = node.parentNode; |
| 5960 | |
| 5961 | if (!parent) { |
| 5962 | return null; |
| 5963 | } |
| 5964 | |
| 5965 | if (keep_children) { |
| 5966 | while ((child = node.firstChild)) { |
| 5967 | // IE 8 will crash if you don't remove completely empty text nodes |
| 5968 | if (!isIE || child.nodeType !== 3 || child.nodeValue) { |
| 5969 | parent.insertBefore(child, node); |
| 5970 | } else { |
| 5971 | node.removeChild(child); |
| 5972 | } |
| 5973 | } |
| 5974 | } |
| 5975 | |
| 5976 | return parent.removeChild(node); |
| 5977 | }); |
| 5978 | }, |
| 5979 | |
| 5980 | /** |
| 5981 | * Sets the CSS style value on a HTML element. The name can be a camelcase string |
| 5982 | * or the CSS style name like background-color. |
| 5983 | * |
| 5984 | * @method setStyle |
| 5985 | * @param {String/Element/Array} n HTML element/Element ID or Array of elements/ids to set CSS style value on. |
| 5986 | * @param {String} na Name of the style value to set. |
| 5987 | * @param {String} v Value to set on the style. |
| 5988 | * @example |
| 5989 | * // Sets a style value on all paragraphs in the currently active editor |
| 5990 | * tinymce.activeEditor.dom.setStyle(tinymce.activeEditor.dom.select('p'), 'background-color', 'red'); |
| 5991 | * |
| 5992 | * // Sets a style value to an element by id in the current document |
| 5993 | * tinymce.DOM.setStyle('mydiv', 'background-color', 'red'); |
| 5994 | */ |
| 5995 | setStyle: function(elm, name, value) { |
| 5996 | return this.run(elm, function(elm) { |
| 5997 | var self = this, style, key; |
| 5998 | |
| 5999 | if (name) { |
| 6000 | if (typeof(name) === 'string') { |
| 6001 | style = elm.style; |
| 6002 | |
| 6003 | // Camelcase it, if needed |
| 6004 | name = name.replace(/-(\D)/g, function(a, b) { |
| 6005 | return b.toUpperCase(); |
| 6006 | }); |
| 6007 | |
| 6008 | // Default px suffix on these |
| 6009 | if (typeof(value) === 'number' && !numericCssMap[name]) { |
| 6010 | value += 'px'; |
| 6011 | } |
| 6012 | |
| 6013 | // IE specific opacity |
| 6014 | if (name === "opacity" && elm.runtimeStyle && typeof(elm.runtimeStyle.opacity) === "undefined") { |
| 6015 | style.filter = value === '' ? '' : "alpha(opacity=" + (value * 100) + ")"; |
| 6016 | } |
| 6017 | |
| 6018 | if (name == "float") { |
| 6019 | // Old IE vs modern browsers |
| 6020 | name = "cssFloat" in elm.style ? "cssFloat" : "styleFloat"; |
| 6021 | } |
| 6022 | |
| 6023 | try { |
| 6024 | style[name] = value; |
| 6025 | } catch (ex) { |
| 6026 | // Ignore IE errors |
| 6027 | } |
| 6028 | |
| 6029 | // Force update of the style data |
| 6030 | if (self.settings.update_styles) { |
| 6031 | elm.removeAttribute('data-mce-style'); |
| 6032 | } |
| 6033 | } else { |
| 6034 | for (key in name) { |
| 6035 | self.setStyle(elm, key, name[key]); |
| 6036 | } |
| 6037 | } |
| 6038 | } |
| 6039 | }); |
| 6040 | }, |
| 6041 | |
| 6042 | /** |
| 6043 | * Returns the current style or runtime/computed value of an element. |
| 6044 | * |
| 6045 | * @method getStyle |
| 6046 | * @param {String/Element} elm HTML element or element id string to get style from. |
| 6047 | * @param {String} name Style name to return. |
| 6048 | * @param {Boolean} computed Computed style. |
| 6049 | * @return {String} Current style or computed style value of an element. |
| 6050 | */ |
| 6051 | getStyle: function(elm, name, computed) { |
| 6052 | elm = this.get(elm); |
| 6053 | |
| 6054 | if (!elm) { |
| 6055 | return; |
| 6056 | } |
| 6057 | |
| 6058 | // W3C |
| 6059 | if (this.doc.defaultView && computed) { |
| 6060 | // Remove camelcase |
| 6061 | name = name.replace(/[A-Z]/g, function(a){ |
| 6062 | return '-' + a; |
| 6063 | }); |
| 6064 | |
| 6065 | try { |
| 6066 | return this.doc.defaultView.getComputedStyle(elm, null).getPropertyValue(name); |
| 6067 | } catch (ex) { |
| 6068 | // Old safari might fail |
| 6069 | return null; |
| 6070 | } |
| 6071 | } |
| 6072 | |
| 6073 | // Camelcase it, if needed |
| 6074 | name = name.replace(/-(\D)/g, function(a, b) { |
| 6075 | return b.toUpperCase(); |
| 6076 | }); |
| 6077 | |
| 6078 | if (name == 'float') { |
| 6079 | name = isIE ? 'styleFloat' : 'cssFloat'; |
| 6080 | } |
| 6081 | |
| 6082 | // IE & Opera |
| 6083 | if (elm.currentStyle && computed) { |
| 6084 | return elm.currentStyle[name]; |
| 6085 | } |
| 6086 | |
| 6087 | return elm.style ? elm.style[name] : undefined; |
| 6088 | }, |
| 6089 | |
| 6090 | /** |
| 6091 | * Sets multiple styles on the specified element(s). |
| 6092 | * |
| 6093 | * @method setStyles |
| 6094 | * @param {Element/String/Array} e DOM element, element id string or array of elements/ids to set styles on. |
| 6095 | * @param {Object} o Name/Value collection of style items to add to the element(s). |
| 6096 | * @example |
| 6097 | * // Sets styles on all paragraphs in the currently active editor |
| 6098 | * tinymce.activeEditor.dom.setStyles(tinymce.activeEditor.dom.select('p'), {'background-color': 'red', 'color': 'green'}); |
| 6099 | * |
| 6100 | * // Sets styles to an element by id in the current document |
| 6101 | * tinymce.DOM.setStyles('mydiv', {'background-color': 'red', 'color': 'green'}); |
| 6102 | */ |
| 6103 | setStyles: function(elm, styles) { |
| 6104 | this.setStyle(elm, styles); |
| 6105 | }, |
| 6106 | |
| 6107 | css: function(elm, name, value) { |
| 6108 | this.setStyle(elm, name, value); |
| 6109 | }, |
| 6110 | |
| 6111 | /** |
| 6112 | * Removes all attributes from an element or elements. |
| 6113 | * |
| 6114 | * @method removeAllAttribs |
| 6115 | * @param {Element/String/Array} e DOM element, element id string or array of elements/ids to remove attributes from. |
| 6116 | */ |
| 6117 | removeAllAttribs: function(e) { |
| 6118 | return this.run(e, function(e) { |
| 6119 | var i, attrs = e.attributes; |
| 6120 | for (i = attrs.length - 1; i >= 0; i--) { |
| 6121 | e.removeAttributeNode(attrs.item(i)); |
| 6122 | } |
| 6123 | }); |
| 6124 | }, |
| 6125 | |
| 6126 | /** |
| 6127 | * Sets the specified attribute of an element or elements. |
| 6128 | * |
| 6129 | * @method setAttrib |
| 6130 | * @param {Element/String/Array} e DOM element, element id string or array of elements/ids to set attribute on. |
| 6131 | * @param {String} n Name of attribute to set. |
| 6132 | * @param {String} v Value to set on the attribute - if this value is falsy like null, 0 or '' it will remove the attribute instead. |
| 6133 | * @example |
| 6134 | * // Sets class attribute on all paragraphs in the active editor |
| 6135 | * tinymce.activeEditor.dom.setAttrib(tinymce.activeEditor.dom.select('p'), 'class', 'myclass'); |
| 6136 | * |
| 6137 | * // Sets class attribute on a specific element in the current page |
| 6138 | * tinymce.dom.setAttrib('mydiv', 'class', 'myclass'); |
| 6139 | */ |
| 6140 | setAttrib: function(e, n, v) { |
| 6141 | var t = this; |
| 6142 | |
| 6143 | // What's the point |
| 6144 | if (!e || !n) { |
| 6145 | return; |
| 6146 | } |
| 6147 | |
| 6148 | return this.run(e, function(e) { |
| 6149 | var s = t.settings; |
| 6150 | var originalValue = e.getAttribute(n); |
| 6151 | if (v !== null) { |
| 6152 | switch (n) { |
| 6153 | case "style": |
| 6154 | if (!is(v, 'string')) { |
| 6155 | each(v, function(v, n) { |
| 6156 | t.setStyle(e, n, v); |
| 6157 | }); |
| 6158 | |
| 6159 | return; |
| 6160 | } |
| 6161 | |
| 6162 | // No mce_style for elements with these since they might get resized by the user |
| 6163 | if (s.keep_values) { |
| 6164 | if (v) { |
| 6165 | e.setAttribute('data-mce-style', v, 2); |
| 6166 | } else { |
| 6167 | e.removeAttribute('data-mce-style', 2); |
| 6168 | } |
| 6169 | } |
| 6170 | |
| 6171 | e.style.cssText = v; |
| 6172 | break; |
| 6173 | |
| 6174 | case "class": |
| 6175 | e.className = v || ''; // Fix IE null bug |
| 6176 | break; |
| 6177 | |
| 6178 | case "src": |
| 6179 | case "href": |
| 6180 | if (s.keep_values) { |
| 6181 | if (s.url_converter) { |
| 6182 | v = s.url_converter.call(s.url_converter_scope || t, v, n, e); |
| 6183 | } |
| 6184 | |
| 6185 | t.setAttrib(e, 'data-mce-' + n, v, 2); |
| 6186 | } |
| 6187 | |
| 6188 | break; |
| 6189 | |
| 6190 | case "shape": |
| 6191 | e.setAttribute('data-mce-style', v); |
| 6192 | break; |
| 6193 | } |
| 6194 | } |
| 6195 | if (is(v) && v !== null && v.length !== 0) { |
| 6196 | e.setAttribute(n, '' + v, 2); |
| 6197 | } else { |
| 6198 | e.removeAttribute(n, 2); |
| 6199 | } |
| 6200 | |
| 6201 | // fire onChangeAttrib event for attributes that have changed |
| 6202 | if (originalValue != v && s.onSetAttrib) { |
| 6203 | s.onSetAttrib({attrElm: e, attrName: n, attrValue: v}); |
| 6204 | } |
| 6205 | }); |
| 6206 | }, |
| 6207 | |
| 6208 | /** |
| 6209 | * Sets two or more specified attributes of an element or elements. |
| 6210 | * |
| 6211 | * @method setAttribs |
| 6212 | * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set attributes on. |
| 6213 | * @param {Object} attrs Name/Value collection of attribute items to add to the element(s). |
| 6214 | * @example |
| 6215 | * // Sets class and title attributes on all paragraphs in the active editor |
| 6216 | * tinymce.activeEditor.dom.setAttribs(tinymce.activeEditor.dom.select('p'), {'class': 'myclass', title: 'some title'}); |
| 6217 | * |
| 6218 | * // Sets class and title attributes on a specific element in the current page |
| 6219 | * tinymce.DOM.setAttribs('mydiv', {'class': 'myclass', title: 'some title'}); |
| 6220 | */ |
| 6221 | setAttribs: function(elm, attrs) { |
| 6222 | var self = this; |
| 6223 | |
| 6224 | return this.run(elm, function(elm) { |
| 6225 | each(attrs, function(value, name) { |
| 6226 | self.setAttrib(elm, name, value); |
| 6227 | }); |
| 6228 | }); |
| 6229 | }, |
| 6230 | |
| 6231 | /** |
| 6232 | * Returns the specified attribute by name. |
| 6233 | * |
| 6234 | * @method getAttrib |
| 6235 | * @param {String/Element} elm Element string id or DOM element to get attribute from. |
| 6236 | * @param {String} name Name of attribute to get. |
| 6237 | * @param {String} defaultVal Optional default value to return if the attribute didn't exist. |
| 6238 | * @return {String} Attribute value string, default value or null if the attribute wasn't found. |
| 6239 | */ |
| 6240 | getAttrib: function(elm, name, defaultVal) { |
| 6241 | var value, self = this, undef; |
| 6242 | |
| 6243 | elm = self.get(elm); |
| 6244 | |
| 6245 | if (!elm || elm.nodeType !== 1) { |
| 6246 | return defaultVal === undef ? false : defaultVal; |
| 6247 | } |
| 6248 | |
| 6249 | if (!is(defaultVal)) { |
| 6250 | defaultVal = ''; |
| 6251 | } |
| 6252 | |
| 6253 | // Try the mce variant for these |
| 6254 | if (/^(src|href|style|coords|shape)$/.test(name)) { |
| 6255 | value = elm.getAttribute("data-mce-" + name); |
| 6256 | |
| 6257 | if (value) { |
| 6258 | return value; |
| 6259 | } |
| 6260 | } |
| 6261 | |
| 6262 | if (isIE && self.props[name]) { |
| 6263 | value = elm[self.props[name]]; |
| 6264 | value = value && value.nodeValue ? value.nodeValue : value; |
| 6265 | } |
| 6266 | |
| 6267 | if (!value) { |
| 6268 | value = elm.getAttribute(name, 2); |
| 6269 | } |
| 6270 | |
| 6271 | // Check boolean attribs |
| 6272 | if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(name)) { |
| 6273 | if (elm[self.props[name]] === true && value === '') { |
| 6274 | return name; |
| 6275 | } |
| 6276 | |
| 6277 | return value ? name : ''; |
| 6278 | } |
| 6279 | |
| 6280 | // Inner input elements will override attributes on form elements |
| 6281 | if (elm.nodeName === "FORM" && elm.getAttributeNode(name)) { |
| 6282 | return elm.getAttributeNode(name).nodeValue; |
| 6283 | } |
| 6284 | |
| 6285 | if (name === 'style') { |
| 6286 | value = value || elm.style.cssText; |
| 6287 | |
| 6288 | if (value) { |
| 6289 | value = self.serializeStyle(self.parseStyle(value), elm.nodeName); |
| 6290 | |
| 6291 | if (self.settings.keep_values) { |
| 6292 | elm.setAttribute('data-mce-style', value); |
| 6293 | } |
| 6294 | } |
| 6295 | } |
| 6296 | |
| 6297 | // Remove Apple and WebKit stuff |
| 6298 | if (isWebKit && name === "class" && value) { |
| 6299 | value = value.replace(/(apple|webkit)\-[a-z\-]+/gi, ''); |
| 6300 | } |
| 6301 | |
| 6302 | // Handle IE issues |
| 6303 | if (isIE) { |
| 6304 | switch (name) { |
| 6305 | case 'rowspan': |
| 6306 | case 'colspan': |
| 6307 | // IE returns 1 as default value |
| 6308 | if (value === 1) { |
| 6309 | value = ''; |
| 6310 | } |
| 6311 | |
| 6312 | break; |
| 6313 | |
| 6314 | case 'size': |
| 6315 | // IE returns +0 as default value for size |
| 6316 | if (value === '+0' || value === 20 || value === 0) { |
| 6317 | value = ''; |
| 6318 | } |
| 6319 | |
| 6320 | break; |
| 6321 | |
| 6322 | case 'width': |
| 6323 | case 'height': |
| 6324 | case 'vspace': |
| 6325 | case 'checked': |
| 6326 | case 'disabled': |
| 6327 | case 'readonly': |
| 6328 | if (value === 0) { |
| 6329 | value = ''; |
| 6330 | } |
| 6331 | |
| 6332 | break; |
| 6333 | |
| 6334 | case 'hspace': |
| 6335 | // IE returns -1 as default value |
| 6336 | if (value === -1) { |
| 6337 | value = ''; |
| 6338 | } |
| 6339 | |
| 6340 | break; |
| 6341 | |
| 6342 | case 'maxlength': |
| 6343 | case 'tabindex': |
| 6344 | // IE returns default value |
| 6345 | if (value === 32768 || value === 2147483647 || value === '32768') { |
| 6346 | value = ''; |
| 6347 | } |
| 6348 | |
| 6349 | break; |
| 6350 | |
| 6351 | case 'multiple': |
| 6352 | case 'compact': |
| 6353 | case 'noshade': |
| 6354 | case 'nowrap': |
| 6355 | if (value === 65535) { |
| 6356 | return name; |
| 6357 | } |
| 6358 | |
| 6359 | return defaultVal; |
| 6360 | |
| 6361 | case 'shape': |
| 6362 | value = value.toLowerCase(); |
| 6363 | break; |
| 6364 | |
| 6365 | default: |
| 6366 | // IE has odd anonymous function for event attributes |
| 6367 | if (name.indexOf('on') === 0 && value) { |
| 6368 | value = ('' + value).replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1'); |
| 6369 | } |
| 6370 | } |
| 6371 | } |
| 6372 | |
| 6373 | return (value !== undef && value !== null && value !== '') ? '' + value : defaultVal; |
| 6374 | }, |
| 6375 | |
| 6376 | /** |
| 6377 | * Returns the absolute x, y position of a node. The position will be returned in an object with x, y fields. |
| 6378 | * |
| 6379 | * @method getPos |
| 6380 | * @param {Element/String} elm HTML element or element id to get x, y position from. |
| 6381 | * @param {Element} rootElm Optional root element to stop calculations at. |
| 6382 | * @return {object} Absolute position of the specified element object with x, y fields. |
| 6383 | */ |
| 6384 | getPos: function(elm, rootElm) { |
| 6385 | var self = this, x = 0, y = 0, offsetParent, doc = self.doc, pos; |
| 6386 | |
| 6387 | elm = self.get(elm); |
| 6388 | rootElm = rootElm || doc.body; |
| 6389 | |
| 6390 | if (elm) { |
| 6391 | // Use getBoundingClientRect if it exists since it's faster than looping offset nodes |
| 6392 | if (rootElm === doc.body && elm.getBoundingClientRect) { |
| 6393 | pos = elm.getBoundingClientRect(); |
| 6394 | rootElm = self.boxModel ? doc.documentElement : doc.body; |
| 6395 | |
| 6396 | // Add scroll offsets from documentElement or body since IE with the wrong box model will use d.body and so do WebKit |
| 6397 | // Also remove the body/documentelement clientTop/clientLeft on IE 6, 7 since they offset the position |
| 6398 | x = pos.left + (doc.documentElement.scrollLeft || doc.body.scrollLeft) - rootElm.clientTop; |
| 6399 | y = pos.top + (doc.documentElement.scrollTop || doc.body.scrollTop) - rootElm.clientLeft; |
| 6400 | |
| 6401 | return {x: x, y: y}; |
| 6402 | } |
| 6403 | |
| 6404 | offsetParent = elm; |
| 6405 | while (offsetParent && offsetParent != rootElm && offsetParent.nodeType) { |
| 6406 | x += offsetParent.offsetLeft || 0; |
| 6407 | y += offsetParent.offsetTop || 0; |
| 6408 | offsetParent = offsetParent.offsetParent; |
| 6409 | } |
| 6410 | |
| 6411 | offsetParent = elm.parentNode; |
| 6412 | while (offsetParent && offsetParent != rootElm && offsetParent.nodeType) { |
| 6413 | x -= offsetParent.scrollLeft || 0; |
| 6414 | y -= offsetParent.scrollTop || 0; |
| 6415 | offsetParent = offsetParent.parentNode; |
| 6416 | } |
| 6417 | } |
| 6418 | |
| 6419 | return {x: x, y: y}; |
| 6420 | }, |
| 6421 | |
| 6422 | /** |
| 6423 | * Parses the specified style value into an object collection. This parser will also |
| 6424 | * merge and remove any redundant items that browsers might have added. It will also convert non-hex |
| 6425 | * colors to hex values. Urls inside the styles will also be converted to absolute/relative based on settings. |
| 6426 | * |
| 6427 | * @method parseStyle |
| 6428 | * @param {String} cssText Style value to parse, for example: border:1px solid red;. |
| 6429 | * @return {Object} Object representation of that style, for example: {border: '1px solid red'} |
| 6430 | */ |
| 6431 | parseStyle: function(cssText) { |
| 6432 | return this.styles.parse(cssText); |
| 6433 | }, |
| 6434 | |
| 6435 | /** |
| 6436 | * Serializes the specified style object into a string. |
| 6437 | * |
| 6438 | * @method serializeStyle |
| 6439 | * @param {Object} styles Object to serialize as string, for example: {border: '1px solid red'} |
| 6440 | * @param {String} name Optional element name. |
| 6441 | * @return {String} String representation of the style object, for example: border: 1px solid red. |
| 6442 | */ |
| 6443 | serializeStyle: function(styles, name) { |
| 6444 | return this.styles.serialize(styles, name); |
| 6445 | }, |
| 6446 | |
| 6447 | /** |
| 6448 | * Adds a style element at the top of the document with the specified cssText content. |
| 6449 | * |
| 6450 | * @method addStyle |
| 6451 | * @param {String} cssText CSS Text style to add to top of head of document. |
| 6452 | */ |
| 6453 | addStyle: function(cssText) { |
| 6454 | var self = this, doc = self.doc, head, styleElm; |
| 6455 | |
| 6456 | // Prevent inline from loading the same styles twice |
| 6457 | if (self !== DOMUtils.DOM && doc === document) { |
| 6458 | var addedStyles = DOMUtils.DOM.addedStyles; |
| 6459 | |
| 6460 | addedStyles = addedStyles || []; |
| 6461 | if (addedStyles[cssText]) { |
| 6462 | return; |
| 6463 | } |
| 6464 | |
| 6465 | addedStyles[cssText] = true; |
| 6466 | DOMUtils.DOM.addedStyles = addedStyles; |
| 6467 | } |
| 6468 | |
| 6469 | // Create style element if needed |
| 6470 | styleElm = doc.getElementById('mceDefaultStyles'); |
| 6471 | if (!styleElm) { |
| 6472 | styleElm = doc.createElement('style'); |
| 6473 | styleElm.id = 'mceDefaultStyles'; |
| 6474 | styleElm.type = 'text/css'; |
| 6475 | |
| 6476 | head = doc.getElementsByTagName('head')[0]; |
| 6477 | if (head.firstChild) { |
| 6478 | head.insertBefore(styleElm, head.firstChild); |
| 6479 | } else { |
| 6480 | head.appendChild(styleElm); |
| 6481 | } |
| 6482 | } |
| 6483 | |
| 6484 | // Append style data to old or new style element |
| 6485 | if (styleElm.styleSheet) { |
| 6486 | styleElm.styleSheet.cssText += cssText; |
| 6487 | } else { |
| 6488 | styleElm.appendChild(doc.createTextNode(cssText)); |
| 6489 | } |
| 6490 | }, |
| 6491 | |
| 6492 | /** |
| 6493 | * Imports/loads the specified CSS file into the document bound to the class. |
| 6494 | * |
| 6495 | * @method loadCSS |
| 6496 | * @param {String} u URL to CSS file to load. |
| 6497 | * @example |
| 6498 | * // Loads a CSS file dynamically into the current document |
| 6499 | * tinymce.DOM.loadCSS('somepath/some.css'); |
| 6500 | * |
| 6501 | * // Loads a CSS file into the currently active editor instance |
| 6502 | * tinymce.activeEditor.dom.loadCSS('somepath/some.css'); |
| 6503 | * |
| 6504 | * // Loads a CSS file into an editor instance by id |
| 6505 | * tinymce.get('someid').dom.loadCSS('somepath/some.css'); |
| 6506 | * |
| 6507 | * // Loads multiple CSS files into the current document |
| 6508 | * tinymce.DOM.loadCSS('somepath/some.css,somepath/someother.css'); |
| 6509 | */ |
| 6510 | loadCSS: function(url) { |
| 6511 | var self = this, doc = self.doc, head; |
| 6512 | |
| 6513 | // Prevent inline from loading the same CSS file twice |
| 6514 | if (self !== DOMUtils.DOM && doc === document) { |
| 6515 | DOMUtils.DOM.loadCSS(url); |
| 6516 | return; |
| 6517 | } |
| 6518 | |
| 6519 | if (!url) { |
| 6520 | url = ''; |
| 6521 | } |
| 6522 | |
| 6523 | head = doc.getElementsByTagName('head')[0]; |
| 6524 | |
| 6525 | each(url.split(','), function(url) { |
| 6526 | var link; |
| 6527 | |
| 6528 | if (self.files[url]) { |
| 6529 | return; |
| 6530 | } |
| 6531 | |
| 6532 | self.files[url] = true; |
| 6533 | link = self.create('link', {rel: 'stylesheet', href: url}); |
| 6534 | |
| 6535 | // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug |
| 6536 | // This fix seems to resolve that issue by recalcing the document once a stylesheet finishes loading |
| 6537 | // It's ugly but it seems to work fine. |
| 6538 | if (isIE && doc.documentMode && doc.recalc) { |
| 6539 | link.onload = function() { |
| 6540 | if (doc.recalc) { |
| 6541 | doc.recalc(); |
| 6542 | } |
| 6543 | |
| 6544 | link.onload = null; |
| 6545 | }; |
| 6546 | } |
| 6547 | |
| 6548 | head.appendChild(link); |
| 6549 | }); |
| 6550 | }, |
| 6551 | |
| 6552 | /** |
| 6553 | * Adds a class to the specified element or elements. |
| 6554 | * |
| 6555 | * @method addClass |
| 6556 | * @param {String/Element/Array} elm Element ID string or DOM element or array with elements or IDs. |
| 6557 | * @param {String} cls Class name to add to each element. |
| 6558 | * @return {String/Array} String with new class value or array with new class values for all elements. |
| 6559 | * @example |
| 6560 | * // Adds a class to all paragraphs in the active editor |
| 6561 | * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'myclass'); |
| 6562 | * |
| 6563 | * // Adds a class to a specific element in the current page |
| 6564 | * tinymce.DOM.addClass('mydiv', 'myclass'); |
| 6565 | */ |
| 6566 | addClass: function(elm, cls) { |
| 6567 | return this.run(elm, function(elm) { |
| 6568 | var clsVal; |
| 6569 | |
| 6570 | if (!cls) { |
| 6571 | return 0; |
| 6572 | } |
| 6573 | |
| 6574 | if (this.hasClass(elm, cls)) { |
| 6575 | return elm.className; |
| 6576 | } |
| 6577 | |
| 6578 | clsVal = this.removeClass(elm, cls); |
| 6579 | elm.className = clsVal = (clsVal !== '' ? (clsVal + ' ') : '') + cls; |
| 6580 | |
| 6581 | return clsVal; |
| 6582 | }); |
| 6583 | }, |
| 6584 | |
| 6585 | /** |
| 6586 | * Removes a class from the specified element or elements. |
| 6587 | * |
| 6588 | * @method removeClass |
| 6589 | * @param {String/Element/Array} elm Element ID string or DOM element or array with elements or IDs. |
| 6590 | * @param {String} cls Class name to remove from each element. |
| 6591 | * @return {String/Array} String of remaining class name(s), or an array of strings if multiple input elements |
| 6592 | * were passed in. |
| 6593 | * @example |
| 6594 | * // Removes a class from all paragraphs in the active editor |
| 6595 | * tinymce.activeEditor.dom.removeClass(tinymce.activeEditor.dom.select('p'), 'myclass'); |
| 6596 | * |
| 6597 | * // Removes a class from a specific element in the current page |
| 6598 | * tinymce.DOM.removeClass('mydiv', 'myclass'); |
| 6599 | */ |
| 6600 | removeClass: function(elm, cls) { |
| 6601 | var self = this, re; |
| 6602 | |
| 6603 | return self.run(elm, function(elm) { |
| 6604 | var val; |
| 6605 | |
| 6606 | if (self.hasClass(elm, cls)) { |
| 6607 | if (!re) { |
| 6608 | re = new RegExp("(^|\\s+)" + cls + "(\\s+|$)", "g"); |
| 6609 | } |
| 6610 | |
| 6611 | val = elm.className.replace(re, ' '); |
| 6612 | val = trim(val != ' ' ? val : ''); |
| 6613 | |
| 6614 | elm.className = val; |
| 6615 | |
| 6616 | // Empty class attr |
| 6617 | if (!val) { |
| 6618 | elm.removeAttribute('class'); |
| 6619 | elm.removeAttribute('className'); |
| 6620 | } |
| 6621 | |
| 6622 | return val; |
| 6623 | } |
| 6624 | |
| 6625 | return elm.className; |
| 6626 | }); |
| 6627 | }, |
| 6628 | |
| 6629 | /** |
| 6630 | * Returns true if the specified element has the specified class. |
| 6631 | * |
| 6632 | * @method hasClass |
| 6633 | * @param {String/Element} n HTML element or element id string to check CSS class on. |
| 6634 | * @param {String} c CSS class to check for. |
| 6635 | * @return {Boolean} true/false if the specified element has the specified class. |
| 6636 | */ |
| 6637 | hasClass: function(elm, cls) { |
| 6638 | elm = this.get(elm); |
| 6639 | |
| 6640 | if (!elm || !cls) { |
| 6641 | return false; |
| 6642 | } |
| 6643 | |
| 6644 | return (' ' + elm.className + ' ').indexOf(' ' + cls + ' ') !== -1; |
| 6645 | }, |
| 6646 | |
| 6647 | /** |
| 6648 | * Toggles the specified class on/off. |
| 6649 | * |
| 6650 | * @method toggleClass |
| 6651 | * @param {Element} elm Element to toggle class on. |
| 6652 | * @param {[type]} cls Class to toggle on/off. |
| 6653 | * @param {[type]} state Optional state to set. |
| 6654 | */ |
| 6655 | toggleClass: function(elm, cls, state) { |
| 6656 | state = state === undefined ? !this.hasClass(elm, cls) : state; |
| 6657 | |
| 6658 | if (this.hasClass(elm, cls) !== state) { |
| 6659 | if (state) { |
| 6660 | this.addClass(elm, cls); |
| 6661 | } else { |
| 6662 | this.removeClass(elm, cls); |
| 6663 | } |
| 6664 | } |
| 6665 | }, |
| 6666 | |
| 6667 | /** |
| 6668 | * Shows the specified element(s) by ID by setting the "display" style. |
| 6669 | * |
| 6670 | * @method show |
| 6671 | * @param {String/Element/Array} elm ID of DOM element or DOM element or array with elements or IDs to show. |
| 6672 | */ |
| 6673 | show: function(elm) { |
| 6674 | return this.setStyle(elm, 'display', 'block'); |
| 6675 | }, |
| 6676 | |
| 6677 | /** |
| 6678 | * Hides the specified element(s) by ID by setting the "display" style. |
| 6679 | * |
| 6680 | * @method hide |
| 6681 | * @param {String/Element/Array} e ID of DOM element or DOM element or array with elements or IDs to hide. |
| 6682 | * @example |
| 6683 | * // Hides an element by id in the document |
| 6684 | * tinymce.DOM.hide('myid'); |
| 6685 | */ |
| 6686 | hide: function(elm) { |
| 6687 | return this.setStyle(elm, 'display', 'none'); |
| 6688 | }, |
| 6689 | |
| 6690 | /** |
| 6691 | * Returns true/false if the element is hidden or not by checking the "display" style. |
| 6692 | * |
| 6693 | * @method isHidden |
| 6694 | * @param {String/Element} e Id or element to check display state on. |
| 6695 | * @return {Boolean} true/false if the element is hidden or not. |
| 6696 | */ |
| 6697 | isHidden: function(elm) { |
| 6698 | elm = this.get(elm); |
| 6699 | |
| 6700 | return !elm || elm.style.display == 'none' || this.getStyle(elm, 'display') == 'none'; |
| 6701 | }, |
| 6702 | |
| 6703 | /** |
| 6704 | * Returns a unique id. This can be useful when generating elements on the fly. |
| 6705 | * This method will not check if the element already exists. |
| 6706 | * |
| 6707 | * @method uniqueId |
| 6708 | * @param {String} prefix Optional prefix to add in front of all ids - defaults to "mce_". |
| 6709 | * @return {String} Unique id. |
| 6710 | */ |
| 6711 | uniqueId: function(prefix) { |
| 6712 | return (!prefix ? 'mce_' : prefix) + (this.counter++); |
| 6713 | }, |
| 6714 | |
| 6715 | /** |
| 6716 | * Sets the specified HTML content inside the element or elements. The HTML will first be processed. This means |
| 6717 | * URLs will get converted, hex color values fixed etc. Check processHTML for details. |
| 6718 | * |
| 6719 | * @method setHTML |
| 6720 | * @param {Element/String/Array} e DOM element, element id string or array of elements/ids to set HTML inside of. |
| 6721 | * @param {String} h HTML content to set as inner HTML of the element. |
| 6722 | * @example |
| 6723 | * // Sets the inner HTML of all paragraphs in the active editor |
| 6724 | * tinymce.activeEditor.dom.setHTML(tinymce.activeEditor.dom.select('p'), 'some inner html'); |
| 6725 | * |
| 6726 | * // Sets the inner HTML of an element by id in the document |
| 6727 | * tinymce.DOM.setHTML('mydiv', 'some inner html'); |
| 6728 | */ |
| 6729 | setHTML: function(element, html) { |
| 6730 | var self = this; |
| 6731 | |
| 6732 | return self.run(element, function(element) { |
| 6733 | if (isIE) { |
| 6734 | // Remove all child nodes, IE keeps empty text nodes in DOM |
| 6735 | while (element.firstChild) { |
| 6736 | element.removeChild(element.firstChild); |
| 6737 | } |
| 6738 | |
| 6739 | try { |
| 6740 | // IE will remove comments from the beginning |
| 6741 | // unless you padd the contents with something |
| 6742 | element.innerHTML = '<br />' + html; |
| 6743 | element.removeChild(element.firstChild); |
| 6744 | } catch (ex) { |
| 6745 | // IE sometimes produces an unknown runtime error on innerHTML if it's a block element |
| 6746 | // within a block element for example a div inside a p |
| 6747 | // This seems to fix this problem |
| 6748 | |
| 6749 | // Create new div with HTML contents and a BR in front to keep comments |
| 6750 | var newElement = self.create('div'); |
| 6751 | newElement.innerHTML = '<br />' + html; |
| 6752 | |
| 6753 | // Add all children from div to target |
| 6754 | each (grep(newElement.childNodes), function(node, i) { |
| 6755 | // Skip br element |
| 6756 | if (i && element.canHaveHTML) { |
| 6757 | element.appendChild(node); |
| 6758 | } |
| 6759 | }); |
| 6760 | } |
| 6761 | } else { |
| 6762 | element.innerHTML = html; |
| 6763 | } |
| 6764 | |
| 6765 | return html; |
| 6766 | }); |
| 6767 | }, |
| 6768 | |
| 6769 | /** |
| 6770 | * Returns the outer HTML of an element. |
| 6771 | * |
| 6772 | * @method getOuterHTML |
| 6773 | * @param {String/Element} elm Element ID or element object to get outer HTML from. |
| 6774 | * @return {String} Outer HTML string. |
| 6775 | * @example |
| 6776 | * tinymce.DOM.getOuterHTML(editorElement); |
| 6777 | * tinymce.activeEditor.getOuterHTML(tinymce.activeEditor.getBody()); |
| 6778 | */ |
| 6779 | getOuterHTML: function(elm) { |
| 6780 | var doc, self = this; |
| 6781 | |
| 6782 | elm = self.get(elm); |
| 6783 | |
| 6784 | if (!elm) { |
| 6785 | return null; |
| 6786 | } |
| 6787 | |
| 6788 | if (elm.nodeType === 1 && self.hasOuterHTML) { |
| 6789 | return elm.outerHTML; |
| 6790 | } |
| 6791 | |
| 6792 | doc = (elm.ownerDocument || self.doc).createElement("body"); |
| 6793 | doc.appendChild(elm.cloneNode(true)); |
| 6794 | |
| 6795 | return doc.innerHTML; |
| 6796 | }, |
| 6797 | |
| 6798 | /** |
| 6799 | * Sets the specified outer HTML on an element or elements. |
| 6800 | * |
| 6801 | * @method setOuterHTML |
| 6802 | * @param {Element/String/Array} elm DOM element, element id string or array of elements/ids to set outer HTML on. |
| 6803 | * @param {Object} html HTML code to set as outer value for the element. |
| 6804 | * @param {Document} doc Optional document scope to use in this process - defaults to the document of the DOM class. |
| 6805 | * @example |
| 6806 | * // Sets the outer HTML of all paragraphs in the active editor |
| 6807 | * tinymce.activeEditor.dom.setOuterHTML(tinymce.activeEditor.dom.select('p'), '<div>some html</div>'); |
| 6808 | * |
| 6809 | * // Sets the outer HTML of an element by id in the document |
| 6810 | * tinymce.DOM.setOuterHTML('mydiv', '<div>some html</div>'); |
| 6811 | */ |
| 6812 | setOuterHTML: function(elm, html, doc) { |
| 6813 | var self = this; |
| 6814 | |
| 6815 | return self.run(elm, function(elm) { |
| 6816 | function set() { |
| 6817 | var node, tempElm; |
| 6818 | |
| 6819 | tempElm = doc.createElement("body"); |
| 6820 | tempElm.innerHTML = html; |
| 6821 | |
| 6822 | node = tempElm.lastChild; |
| 6823 | while (node) { |
| 6824 | self.insertAfter(node.cloneNode(true), elm); |
| 6825 | node = node.previousSibling; |
| 6826 | } |
| 6827 | |
| 6828 | self.remove(elm); |
| 6829 | } |
| 6830 | |
| 6831 | // Only set HTML on elements |
| 6832 | if (elm.nodeType == 1) { |
| 6833 | doc = doc || elm.ownerDocument || self.doc; |
| 6834 | |
| 6835 | if (isIE) { |
| 6836 | try { |
| 6837 | // Try outerHTML for IE it sometimes produces an unknown runtime error |
| 6838 | if (elm.nodeType == 1 && self.hasOuterHTML) { |
| 6839 | elm.outerHTML = html; |
| 6840 | } else { |
| 6841 | set(); |
| 6842 | } |
| 6843 | } catch (ex) { |
| 6844 | // Fix for unknown runtime error |
| 6845 | set(); |
| 6846 | } |
| 6847 | } else { |
| 6848 | set(); |
| 6849 | } |
| 6850 | } |
| 6851 | }); |
| 6852 | }, |
| 6853 | |
| 6854 | /** |
| 6855 | * Entity decodes a string. This method decodes any HTML entities, such as å. |
| 6856 | * |
| 6857 | * @method decode |
| 6858 | * @param {String} s String to decode entities on. |
| 6859 | * @return {String} Entity decoded string. |
| 6860 | */ |
| 6861 | decode: Entities.decode, |
| 6862 | |
| 6863 | /** |
| 6864 | * Entity encodes a string. This method encodes the most common entities, such as <>"&. |
| 6865 | * |
| 6866 | * @method encode |
| 6867 | * @param {String} text String to encode with entities. |
| 6868 | * @return {String} Entity encoded string. |
| 6869 | */ |
| 6870 | encode: Entities.encodeAllRaw, |
| 6871 | |
| 6872 | /** |
| 6873 | * Inserts an element after the reference element. |
| 6874 | * |
| 6875 | * @method insertAfter |
| 6876 | * @param {Element} node Element to insert after the reference. |
| 6877 | * @param {Element/String/Array} reference_node Reference element, element id or array of elements to insert after. |
| 6878 | * @return {Element/Array} Element that got added or an array with elements. |
| 6879 | */ |
| 6880 | insertAfter: function(node, reference_node) { |
| 6881 | reference_node = this.get(reference_node); |
| 6882 | |
| 6883 | return this.run(node, function(node) { |
| 6884 | var parent, nextSibling; |
| 6885 | |
| 6886 | parent = reference_node.parentNode; |
| 6887 | nextSibling = reference_node.nextSibling; |
| 6888 | |
| 6889 | if (nextSibling) { |
| 6890 | parent.insertBefore(node, nextSibling); |
| 6891 | } else { |
| 6892 | parent.appendChild(node); |
| 6893 | } |
| 6894 | |
| 6895 | return node; |
| 6896 | }); |
| 6897 | }, |
| 6898 | |
| 6899 | /** |
| 6900 | * Replaces the specified element or elements with the new element specified. The new element will |
| 6901 | * be cloned if multiple input elements are passed in. |
| 6902 | * |
| 6903 | * @method replace |
| 6904 | * @param {Element} newElm New element to replace old ones with. |
| 6905 | * @param {Element/String/Array} oldELm Element DOM node, element id or array of elements or ids to replace. |
| 6906 | * @param {Boolean} k Optional keep children state, if set to true child nodes from the old object will be added to new ones. |
| 6907 | */ |
| 6908 | replace: function(newElm, oldElm, keepChildren) { |
| 6909 | var self = this; |
| 6910 | |
| 6911 | return self.run(oldElm, function(oldElm) { |
| 6912 | if (is(oldElm, 'array')) { |
| 6913 | newElm = newElm.cloneNode(true); |
| 6914 | } |
| 6915 | |
| 6916 | if (keepChildren) { |
| 6917 | each(grep(oldElm.childNodes), function(node) { |
| 6918 | newElm.appendChild(node); |
| 6919 | }); |
| 6920 | } |
| 6921 | |
| 6922 | return oldElm.parentNode.replaceChild(newElm, oldElm); |
| 6923 | }); |
| 6924 | }, |
| 6925 | |
| 6926 | /** |
| 6927 | * Renames the specified element and keeps its attributes and children. |
| 6928 | * |
| 6929 | * @method rename |
| 6930 | * @param {Element} elm Element to rename. |
| 6931 | * @param {String} name Name of the new element. |
| 6932 | * @return {Element} New element or the old element if it needed renaming. |
| 6933 | */ |
| 6934 | rename: function(elm, name) { |
| 6935 | var self = this, newElm; |
| 6936 | |
| 6937 | if (elm.nodeName != name.toUpperCase()) { |
| 6938 | // Rename block element |
| 6939 | newElm = self.create(name); |
| 6940 | |
| 6941 | // Copy attribs to new block |
| 6942 | each(self.getAttribs(elm), function(attr_node) { |
| 6943 | self.setAttrib(newElm, attr_node.nodeName, self.getAttrib(elm, attr_node.nodeName)); |
| 6944 | }); |
| 6945 | |
| 6946 | // Replace block |
| 6947 | self.replace(newElm, elm, 1); |
| 6948 | } |
| 6949 | |
| 6950 | return newElm || elm; |
| 6951 | }, |
| 6952 | |
| 6953 | /** |
| 6954 | * Find the common ancestor of two elements. This is a shorter method than using the DOM Range logic. |
| 6955 | * |
| 6956 | * @method findCommonAncestor |
| 6957 | * @param {Element} a Element to find common ancestor of. |
| 6958 | * @param {Element} b Element to find common ancestor of. |
| 6959 | * @return {Element} Common ancestor element of the two input elements. |
| 6960 | */ |
| 6961 | findCommonAncestor: function(a, b) { |
| 6962 | var ps = a, pe; |
| 6963 | |
| 6964 | while (ps) { |
| 6965 | pe = b; |
| 6966 | |
| 6967 | while (pe && ps != pe) { |
| 6968 | pe = pe.parentNode; |
| 6969 | } |
| 6970 | |
| 6971 | if (ps == pe) { |
| 6972 | break; |
| 6973 | } |
| 6974 | |
| 6975 | ps = ps.parentNode; |
| 6976 | } |
| 6977 | |
| 6978 | if (!ps && a.ownerDocument) { |
| 6979 | return a.ownerDocument.documentElement; |
| 6980 | } |
| 6981 | |
| 6982 | return ps; |
| 6983 | }, |
| 6984 | |
| 6985 | /** |
| 6986 | * Parses the specified RGB color value and returns a hex version of that color. |
| 6987 | * |
| 6988 | * @method toHex |
| 6989 | * @param {String} rgbVal RGB string value like rgb(1,2,3) |
| 6990 | * @return {String} Hex version of that RGB value like #FF00FF. |
| 6991 | */ |
| 6992 | toHex: function(rgbVal) { |
| 6993 | return this.styles.toHex(Tools.trim(rgbVal)); |
| 6994 | }, |
| 6995 | |
| 6996 | /** |
| 6997 | * Executes the specified function on the element by id or dom element node or array of elements/id. |
| 6998 | * |
| 6999 | * @method run |
| 7000 | * @param {String/Element/Array} Element ID or DOM element object or array with ids or elements. |
| 7001 | * @param {function} f Function to execute for each item. |
| 7002 | * @param {Object} s Optional scope to execute the function in. |
| 7003 | * @return {Object/Array} Single object, or an array of objects if multiple input elements were passed in. |
| 7004 | */ |
| 7005 | run: function(elm, func, scope) { |
| 7006 | var self = this, result; |
| 7007 | |
| 7008 | if (typeof(elm) === 'string') { |
| 7009 | elm = self.get(elm); |
| 7010 | } |
| 7011 | |
| 7012 | if (!elm) { |
| 7013 | return false; |
| 7014 | } |
| 7015 | |
| 7016 | scope = scope || this; |
| 7017 | if (!elm.nodeType && (elm.length || elm.length === 0)) { |
| 7018 | result = []; |
| 7019 | |
| 7020 | each(elm, function(elm, i) { |
| 7021 | if (elm) { |
| 7022 | if (typeof(elm) == 'string') { |
| 7023 | elm = self.get(elm); |
| 7024 | } |
| 7025 | |
| 7026 | result.push(func.call(scope, elm, i)); |
| 7027 | } |
| 7028 | }); |
| 7029 | |
| 7030 | return result; |
| 7031 | } |
| 7032 | |
| 7033 | return func.call(scope, elm); |
| 7034 | }, |
| 7035 | |
| 7036 | /** |
| 7037 | * Returns a NodeList with attributes for the element. |
| 7038 | * |
| 7039 | * @method getAttribs |
| 7040 | * @param {HTMLElement/string} elm Element node or string id to get attributes from. |
| 7041 | * @return {NodeList} NodeList with attributes. |
| 7042 | */ |
| 7043 | getAttribs: function(elm) { |
| 7044 | var attrs; |
| 7045 | |
| 7046 | elm = this.get(elm); |
| 7047 | |
| 7048 | if (!elm) { |
| 7049 | return []; |
| 7050 | } |
| 7051 | |
| 7052 | if (isIE) { |
| 7053 | attrs = []; |
| 7054 | |
| 7055 | // Object will throw exception in IE |
| 7056 | if (elm.nodeName == 'OBJECT') { |
| 7057 | return elm.attributes; |
| 7058 | } |
| 7059 | |
| 7060 | // IE doesn't keep the selected attribute if you clone option elements |
| 7061 | if (elm.nodeName === 'OPTION' && this.getAttrib(elm, 'selected')) { |
| 7062 | attrs.push({specified: 1, nodeName: 'selected'}); |
| 7063 | } |
| 7064 | |
| 7065 | // It's crazy that this is faster in IE but it's because it returns all attributes all the time |
| 7066 | var attrRegExp = /<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi; |
| 7067 | elm.cloneNode(false).outerHTML.replace(attrRegExp, '').replace(/[\w:\-]+/gi, function(a) { |
| 7068 | attrs.push({specified: 1, nodeName: a}); |
| 7069 | }); |
| 7070 | |
| 7071 | return attrs; |
| 7072 | } |
| 7073 | |
| 7074 | return elm.attributes; |
| 7075 | }, |
| 7076 | |
| 7077 | /** |
| 7078 | * Returns true/false if the specified node is to be considered empty or not. |
| 7079 | * |
| 7080 | * @example |
| 7081 | * tinymce.DOM.isEmpty(node, {img: true}); |
| 7082 | * @method isEmpty |
| 7083 | * @param {Object} elements Optional name/value object with elements that are automatically treated as non-empty elements. |
| 7084 | * @return {Boolean} true/false if the node is empty or not. |
| 7085 | */ |
| 7086 | isEmpty: function(node, elements) { |
| 7087 | var self = this, i, attributes, type, walker, name, brCount = 0; |
| 7088 | |
| 7089 | node = node.firstChild; |
| 7090 | if (node) { |
| 7091 | walker = new TreeWalker(node, node.parentNode); |
| 7092 | elements = elements || self.schema ? self.schema.getNonEmptyElements() : null; |
| 7093 | |
| 7094 | do { |
| 7095 | type = node.nodeType; |
| 7096 | |
| 7097 | if (type === 1) { |
| 7098 | // Ignore bogus elements |
| 7099 | if (node.getAttribute('data-mce-bogus')) { |
| 7100 | continue; |
| 7101 | } |
| 7102 | |
| 7103 | // Keep empty elements like <img /> |
| 7104 | name = node.nodeName.toLowerCase(); |
| 7105 | if (elements && elements[name]) { |
| 7106 | // Ignore single BR elements in blocks like <p><br /></p> or <p><span><br /></span></p> |
| 7107 | if (name === 'br') { |
| 7108 | brCount++; |
| 7109 | continue; |
| 7110 | } |
| 7111 | |
| 7112 | return false; |
| 7113 | } |
| 7114 | |
| 7115 | // Keep elements with data-bookmark attributes or name attribute like <a name="1"></a> |
| 7116 | attributes = self.getAttribs(node); |
| 7117 | i = node.attributes.length; |
| 7118 | while (i--) { |
| 7119 | name = node.attributes[i].nodeName; |
| 7120 | if (name === "name" || name === 'data-mce-bookmark') { |
| 7121 | return false; |
| 7122 | } |
| 7123 | } |
| 7124 | } |
| 7125 | |
| 7126 | // Keep comment nodes |
| 7127 | if (type == 8) { |
| 7128 | return false; |
| 7129 | } |
| 7130 | |
| 7131 | // Keep non whitespace text nodes |
| 7132 | if ((type === 3 && !whiteSpaceRegExp.test(node.nodeValue))) { |
| 7133 | return false; |
| 7134 | } |
| 7135 | } while ((node = walker.next())); |
| 7136 | } |
| 7137 | |
| 7138 | return brCount <= 1; |
| 7139 | }, |
| 7140 | |
| 7141 | /** |
| 7142 | * Creates a new DOM Range object. This will use the native DOM Range API if it's |
| 7143 | * available. If it's not, it will fall back to the custom TinyMCE implementation. |
| 7144 | * |
| 7145 | * @method createRng |
| 7146 | * @return {DOMRange} DOM Range object. |
| 7147 | * @example |
| 7148 | * var rng = tinymce.DOM.createRng(); |
| 7149 | * alert(rng.startContainer + "," + rng.startOffset); |
| 7150 | */ |
| 7151 | createRng: function() { |
| 7152 | var doc = this.doc; |
| 7153 | |
| 7154 | return doc.createRange ? doc.createRange() : new Range(this); |
| 7155 | }, |
| 7156 | |
| 7157 | /** |
| 7158 | * Returns the index of the specified node within its parent. |
| 7159 | * |
| 7160 | * @method nodeIndex |
| 7161 | * @param {Node} node Node to look for. |
| 7162 | * @param {boolean} normalized Optional true/false state if the index is what it would be after a normalization. |
| 7163 | * @return {Number} Index of the specified node. |
| 7164 | */ |
| 7165 | nodeIndex: function(node, normalized) { |
| 7166 | var idx = 0, lastNodeType, lastNode, nodeType; |
| 7167 | |
| 7168 | if (node) { |
| 7169 | for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) { |
| 7170 | nodeType = node.nodeType; |
| 7171 | |
| 7172 | // Normalize text nodes |
| 7173 | if (normalized && nodeType == 3) { |
| 7174 | if (nodeType == lastNodeType || !node.nodeValue.length) { |
| 7175 | continue; |
| 7176 | } |
| 7177 | } |
| 7178 | idx++; |
| 7179 | lastNodeType = nodeType; |
| 7180 | } |
| 7181 | } |
| 7182 | |
| 7183 | return idx; |
| 7184 | }, |
| 7185 | |
| 7186 | /** |
| 7187 | * Splits an element into two new elements and places the specified split |
| 7188 | * element or elements between the new ones. For example splitting the paragraph at the bold element in |
| 7189 | * this example <p>abc<b>abc</b>123</p> would produce <p>abc</p><b>abc</b><p>123</p>. |
| 7190 | * |
| 7191 | * @method split |
| 7192 | * @param {Element} parentElm Parent element to split. |
| 7193 | * @param {Element} splitElm Element to split at. |
| 7194 | * @param {Element} replacementElm Optional replacement element to replace the split element with. |
| 7195 | * @return {Element} Returns the split element or the replacement element if that is specified. |
| 7196 | */ |
| 7197 | split: function(parentElm, splitElm, replacementElm) { |
| 7198 | var self = this, r = self.createRng(), bef, aft, pa; |
| 7199 | |
| 7200 | // W3C valid browsers tend to leave empty nodes to the left/right side of the contents - this makes sense |
| 7201 | // but we don't want that in our code since it serves no purpose for the end user |
| 7202 | // For example splitting this html at the bold element: |
| 7203 | // <p>text 1<span><b>CHOP</b></span>text 2</p> |
| 7204 | // would produce: |
| 7205 | // <p>text 1<span></span></p><b>CHOP</b><p><span></span>text 2</p> |
| 7206 | // this function will then trim off empty edges and produce: |
| 7207 | // <p>text 1</p><b>CHOP</b><p>text 2</p> |
| 7208 | function trimNode(node) { |
| 7209 | var i, children = node.childNodes, type = node.nodeType; |
| 7210 | |
| 7211 | function surroundedBySpans(node) { |
| 7212 | var previousIsSpan = node.previousSibling && node.previousSibling.nodeName == 'SPAN'; |
| 7213 | var nextIsSpan = node.nextSibling && node.nextSibling.nodeName == 'SPAN'; |
| 7214 | return previousIsSpan && nextIsSpan; |
| 7215 | } |
| 7216 | |
| 7217 | if (type == 1 && node.getAttribute('data-mce-type') == 'bookmark') { |
| 7218 | return; |
| 7219 | } |
| 7220 | |
| 7221 | for (i = children.length - 1; i >= 0; i--) { |
| 7222 | trimNode(children[i]); |
| 7223 | } |
| 7224 | |
| 7225 | if (type != 9) { |
| 7226 | // Keep non whitespace text nodes |
| 7227 | if (type == 3 && node.nodeValue.length > 0) { |
| 7228 | // If parent element isn't a block or there isn't any useful contents for example "<p> </p>" |
| 7229 | // Also keep text nodes with only spaces if surrounded by spans. |
| 7230 | // eg. "<p><span>a</span> <span>b</span></p>" should keep space between a and b |
| 7231 | var trimmedLength = trim(node.nodeValue).length; |
| 7232 | if (!self.isBlock(node.parentNode) || trimmedLength > 0 || trimmedLength === 0 && surroundedBySpans(node)) { |
| 7233 | return; |
| 7234 | } |
| 7235 | } else if (type == 1) { |
| 7236 | // If the only child is a bookmark then move it up |
| 7237 | children = node.childNodes; |
| 7238 | |
| 7239 | // TODO fix this complex if |
| 7240 | if (children.length == 1 && children[0] && children[0].nodeType == 1 && |
| 7241 | children[0].getAttribute('data-mce-type') == 'bookmark') { |
| 7242 | node.parentNode.insertBefore(children[0], node); |
| 7243 | } |
| 7244 | |
| 7245 | // Keep non empty elements or img, hr etc |
| 7246 | if (children.length || /^(br|hr|input|img)$/i.test(node.nodeName)) { |
| 7247 | return; |
| 7248 | } |
| 7249 | } |
| 7250 | |
| 7251 | self.remove(node); |
| 7252 | } |
| 7253 | |
| 7254 | return node; |
| 7255 | } |
| 7256 | |
| 7257 | if (parentElm && splitElm) { |
| 7258 | // Get before chunk |
| 7259 | r.setStart(parentElm.parentNode, self.nodeIndex(parentElm)); |
| 7260 | r.setEnd(splitElm.parentNode, self.nodeIndex(splitElm)); |
| 7261 | bef = r.extractContents(); |
| 7262 | |
| 7263 | // Get after chunk |
| 7264 | r = self.createRng(); |
| 7265 | r.setStart(splitElm.parentNode, self.nodeIndex(splitElm) + 1); |
| 7266 | r.setEnd(parentElm.parentNode, self.nodeIndex(parentElm) + 1); |
| 7267 | aft = r.extractContents(); |
| 7268 | |
| 7269 | // Insert before chunk |
| 7270 | pa = parentElm.parentNode; |
| 7271 | pa.insertBefore(trimNode(bef), parentElm); |
| 7272 | |
| 7273 | // Insert middle chunk |
| 7274 | if (replacementElm) { |
| 7275 | pa.replaceChild(replacementElm, splitElm); |
| 7276 | } else { |
| 7277 | pa.insertBefore(splitElm, parentElm); |
| 7278 | } |
| 7279 | |
| 7280 | // Insert after chunk |
| 7281 | pa.insertBefore(trimNode(aft), parentElm); |
| 7282 | self.remove(parentElm); |
| 7283 | |
| 7284 | return replacementElm || splitElm; |
| 7285 | } |
| 7286 | }, |
| 7287 | |
| 7288 | /** |
| 7289 | * Adds an event handler to the specified object. |
| 7290 | * |
| 7291 | * @method bind |
| 7292 | * @param {Element/Document/Window/Array} target Target element to bind events to. |
| 7293 | * handler to or an array of elements/ids/documents. |
| 7294 | * @param {String} name Name of event handler to add, for example: click. |
| 7295 | * @param {function} func Function to execute when the event occurs. |
| 7296 | * @param {Object} scope Optional scope to execute the function in. |
| 7297 | * @return {function} Function callback handler the same as the one passed in. |
| 7298 | */ |
| 7299 | bind: function(target, name, func, scope) { |
| 7300 | var self = this; |
| 7301 | |
| 7302 | if (Tools.isArray(target)) { |
| 7303 | var i = target.length; |
| 7304 | |
| 7305 | while (i--) { |
| 7306 | target[i] = self.bind(target[i], name, func, scope); |
| 7307 | } |
| 7308 | |
| 7309 | return target; |
| 7310 | } |
| 7311 | |
| 7312 | // Collect all window/document events bound by editor instance |
| 7313 | if (self.settings.collect && (target === self.doc || target === self.win)) { |
| 7314 | self.boundEvents.push([target, name, func, scope]); |
| 7315 | } |
| 7316 | |
| 7317 | return self.events.bind(target, name, func, scope || self); |
| 7318 | }, |
| 7319 | |
| 7320 | /** |
| 7321 | * Removes the specified event handler by name and function from an element or collection of elements. |
| 7322 | * |
| 7323 | * @method unbind |
| 7324 | * @param {Element/Document/Window/Array} target Target element to unbind events on. |
| 7325 | * @param {String} name Event handler name, for example: "click" |
| 7326 | * @param {function} func Function to remove. |
| 7327 | * @return {bool/Array} Bool state of true if the handler was removed, or an array of states if multiple input elements |
| 7328 | * were passed in. |
| 7329 | */ |
| 7330 | unbind: function(target, name, func) { |
| 7331 | var self = this, i; |
| 7332 | |
| 7333 | if (Tools.isArray(target)) { |
| 7334 | i = target.length; |
| 7335 | |
| 7336 | while (i--) { |
| 7337 | target[i] = self.unbind(target[i], name, func); |
| 7338 | } |
| 7339 | |
| 7340 | return target; |
| 7341 | } |
| 7342 | |
| 7343 | // Remove any bound events matching the input |
| 7344 | if (self.boundEvents && (target === self.doc || target === self.win)) { |
| 7345 | i = self.boundEvents.length; |
| 7346 | |
| 7347 | while (i--) { |
| 7348 | var item = self.boundEvents[i]; |
| 7349 | |
| 7350 | if (target == item[0] && (!name || name == item[1]) && (!func || func == item[2])) { |
| 7351 | this.events.unbind(item[0], item[1], item[2]); |
| 7352 | } |
| 7353 | } |
| 7354 | } |
| 7355 | |
| 7356 | return this.events.unbind(target, name, func); |
| 7357 | }, |
| 7358 | |
| 7359 | /** |
| 7360 | * Fires the specified event name with object on target. |
| 7361 | * |
| 7362 | * @method fire |
| 7363 | * @param {Node/Document/Window} target Target element or object to fire event on. |
| 7364 | * @param {String} name Name of the event to fire. |
| 7365 | * @param {Object} evt Event object to send. |
| 7366 | * @return {Event} Event object. |
| 7367 | */ |
| 7368 | fire: function(target, name, evt) { |
| 7369 | return this.events.fire(target, name, evt); |
| 7370 | }, |
| 7371 | |
| 7372 | // Returns the content editable state of a node |
| 7373 | getContentEditable: function(node) { |
| 7374 | var contentEditable; |
| 7375 | |
| 7376 | // Check type |
| 7377 | if (node.nodeType != 1) { |
| 7378 | return null; |
| 7379 | } |
| 7380 | |
| 7381 | // Check for fake content editable |
| 7382 | contentEditable = node.getAttribute("data-mce-contenteditable"); |
| 7383 | if (contentEditable && contentEditable !== "inherit") { |
| 7384 | return contentEditable; |
| 7385 | } |
| 7386 | |
| 7387 | // Check for real content editable |
| 7388 | return node.contentEditable !== "inherit" ? node.contentEditable : null; |
| 7389 | }, |
| 7390 | |
| 7391 | /** |
| 7392 | * Destroys all internal references to the DOM to solve IE leak issues. |
| 7393 | * |
| 7394 | * @method destroy |
| 7395 | */ |
| 7396 | destroy: function() { |
| 7397 | var self = this; |
| 7398 | |
| 7399 | // Unbind all events bound to window/document by editor instance |
| 7400 | if (self.boundEvents) { |
| 7401 | var i = self.boundEvents.length; |
| 7402 | |
| 7403 | while (i--) { |
| 7404 | var item = self.boundEvents[i]; |
| 7405 | this.events.unbind(item[0], item[1], item[2]); |
| 7406 | } |
| 7407 | |
| 7408 | self.boundEvents = null; |
| 7409 | } |
| 7410 | |
| 7411 | // Restore sizzle document to window.document |
| 7412 | // Since the current document might be removed producing "Permission denied" on IE see #6325 |
| 7413 | if (Sizzle.setDocument) { |
| 7414 | Sizzle.setDocument(); |
| 7415 | } |
| 7416 | |
| 7417 | self.win = self.doc = self.root = self.events = self.frag = null; |
| 7418 | }, |
| 7419 | |
| 7420 | // #ifdef debug |
| 7421 | |
| 7422 | dumpRng: function(r) { |
| 7423 | return ( |
| 7424 | 'startContainer: ' + r.startContainer.nodeName + |
| 7425 | ', startOffset: ' + r.startOffset + |
| 7426 | ', endContainer: ' + r.endContainer.nodeName + |
| 7427 | ', endOffset: ' + r.endOffset |
| 7428 | ); |
| 7429 | }, |
| 7430 | |
| 7431 | // #endif |
| 7432 | |
| 7433 | _findSib: function(node, selector, name) { |
| 7434 | var self = this, func = selector; |
| 7435 | |
| 7436 | if (node) { |
| 7437 | // If expression make a function of it using is |
| 7438 | if (typeof(func) == 'string') { |
| 7439 | func = function(node) { |
| 7440 | return self.is(node, selector); |
| 7441 | }; |
| 7442 | } |
| 7443 | |
| 7444 | // Loop all siblings |
| 7445 | for (node = node[name]; node; node = node[name]) { |
| 7446 | if (func(node)) { |
| 7447 | return node; |
| 7448 | } |
| 7449 | } |
| 7450 | } |
| 7451 | |
| 7452 | return null; |
| 7453 | } |
| 7454 | }; |
| 7455 | |
| 7456 | /** |
| 7457 | * Instance of DOMUtils for the current document. |
| 7458 | * |
| 7459 | * @static |
| 7460 | * @property DOM |
| 7461 | * @type tinymce.dom.DOMUtils |
| 7462 | * @example |
| 7463 | * // Example of how to add a class to some element by id |
| 7464 | * tinymce.DOM.addClass('someid', 'someclass'); |
| 7465 | */ |
| 7466 | DOMUtils.DOM = new DOMUtils(document); |
| 7467 | |
| 7468 | return DOMUtils; |
| 7469 | }); |
| 7470 | |
| 7471 | // Included from: js/tinymce/classes/dom/ScriptLoader.js |
| 7472 | |
| 7473 | /** |
| 7474 | * ScriptLoader.js |
| 7475 | * |
| 7476 | * Copyright, Moxiecode Systems AB |
| 7477 | * Released under LGPL License. |
| 7478 | * |
| 7479 | * License: http://www.tinymce.com/license |
| 7480 | * Contributing: http://www.tinymce.com/contributing |
| 7481 | */ |
| 7482 | |
| 7483 | /*globals console*/ |
| 7484 | |
| 7485 | /** |
| 7486 | * This class handles asynchronous/synchronous loading of JavaScript files it will execute callbacks |
| 7487 | * when various items gets loaded. This class is useful to load external JavaScript files. |
| 7488 | * |
| 7489 | * @class tinymce.dom.ScriptLoader |
| 7490 | * @example |
| 7491 | * // Load a script from a specific URL using the global script loader |
| 7492 | * tinymce.ScriptLoader.load('somescript.js'); |
| 7493 | * |
| 7494 | * // Load a script using a unique instance of the script loader |
| 7495 | * var scriptLoader = new tinymce.dom.ScriptLoader(); |
| 7496 | * |
| 7497 | * scriptLoader.load('somescript.js'); |
| 7498 | * |
| 7499 | * // Load multiple scripts |
| 7500 | * var scriptLoader = new tinymce.dom.ScriptLoader(); |
| 7501 | * |
| 7502 | * scriptLoader.add('somescript1.js'); |
| 7503 | * scriptLoader.add('somescript2.js'); |
| 7504 | * scriptLoader.add('somescript3.js'); |
| 7505 | * |
| 7506 | * scriptLoader.loadQueue(function() { |
| 7507 | * alert('All scripts are now loaded.'); |
| 7508 | * }); |
| 7509 | */ |
| 7510 | define("tinymce/dom/ScriptLoader", [ |
| 7511 | "tinymce/dom/DOMUtils", |
| 7512 | "tinymce/util/Tools" |
| 7513 | ], function(DOMUtils, Tools) { |
| 7514 | var DOM = DOMUtils.DOM; |
| 7515 | var each = Tools.each, grep = Tools.grep; |
| 7516 | |
| 7517 | function ScriptLoader() { |
| 7518 | var QUEUED = 0, |
| 7519 | LOADING = 1, |
| 7520 | LOADED = 2, |
| 7521 | states = {}, |
| 7522 | queue = [], |
| 7523 | scriptLoadedCallbacks = {}, |
| 7524 | queueLoadedCallbacks = [], |
| 7525 | loading = 0, |
| 7526 | undef; |
| 7527 | |
| 7528 | /** |
| 7529 | * Loads a specific script directly without adding it to the load queue. |
| 7530 | * |
| 7531 | * @method load |
| 7532 | * @param {String} url Absolute URL to script to add. |
| 7533 | * @param {function} callback Optional callback function to execute ones this script gets loaded. |
| 7534 | * @param {Object} scope Optional scope to execute callback in. |
| 7535 | */ |
| 7536 | function loadScript(url, callback) { |
| 7537 | var dom = DOM, elm, id; |
| 7538 | |
| 7539 | // Execute callback when script is loaded |
| 7540 | function done() { |
| 7541 | dom.remove(id); |
| 7542 | |
| 7543 | if (elm) { |
| 7544 | elm.onreadystatechange = elm.onload = elm = null; |
| 7545 | } |
| 7546 | |
| 7547 | callback(); |
| 7548 | } |
| 7549 | |
| 7550 | function error() { |
| 7551 | // Report the error so it's easier for people to spot loading errors |
| 7552 | if (typeof(console) !== "undefined" && console.log) { |
| 7553 | console.log("Failed to load: " + url); |
| 7554 | } |
| 7555 | |
| 7556 | // We can't mark it as done if there is a load error since |
| 7557 | // A) We don't want to produce 404 errors on the server and |
| 7558 | // B) the onerror event won't fire on all browsers. |
| 7559 | // done(); |
| 7560 | } |
| 7561 | |
| 7562 | id = dom.uniqueId(); |
| 7563 | |
| 7564 | // Create new script element |
| 7565 | elm = document.createElement('script'); |
| 7566 | elm.id = id; |
| 7567 | elm.type = 'text/javascript'; |
| 7568 | elm.src = url; |
| 7569 | |
| 7570 | // Seems that onreadystatechange works better on IE 10 onload seems to fire incorrectly |
| 7571 | if ("onreadystatechange" in elm) { |
| 7572 | elm.onreadystatechange = function() { |
| 7573 | if (/loaded|complete/.test(elm.readyState)) { |
| 7574 | done(); |
| 7575 | } |
| 7576 | }; |
| 7577 | } else { |
| 7578 | elm.onload = done; |
| 7579 | } |
| 7580 | |
| 7581 | // Add onerror event will get fired on some browsers but not all of them |
| 7582 | elm.onerror = error; |
| 7583 | |
| 7584 | // Add script to document |
| 7585 | (document.getElementsByTagName('head')[0] || document.body).appendChild(elm); |
| 7586 | } |
| 7587 | |
| 7588 | /** |
| 7589 | * Returns true/false if a script has been loaded or not. |
| 7590 | * |
| 7591 | * @method isDone |
| 7592 | * @param {String} url URL to check for. |
| 7593 | * @return {Boolean} true/false if the URL is loaded. |
| 7594 | */ |
| 7595 | this.isDone = function(url) { |
| 7596 | return states[url] == LOADED; |
| 7597 | }; |
| 7598 | |
| 7599 | /** |
| 7600 | * Marks a specific script to be loaded. This can be useful if a script got loaded outside |
| 7601 | * the script loader or to skip it from loading some script. |
| 7602 | * |
| 7603 | * @method markDone |
| 7604 | * @param {string} u Absolute URL to the script to mark as loaded. |
| 7605 | */ |
| 7606 | this.markDone = function(url) { |
| 7607 | states[url] = LOADED; |
| 7608 | }; |
| 7609 | |
| 7610 | /** |
| 7611 | * Adds a specific script to the load queue of the script loader. |
| 7612 | * |
| 7613 | * @method add |
| 7614 | * @param {String} url Absolute URL to script to add. |
| 7615 | * @param {function} callback Optional callback function to execute ones this script gets loaded. |
| 7616 | * @param {Object} scope Optional scope to execute callback in. |
| 7617 | */ |
| 7618 | this.add = this.load = function(url, callback, scope) { |
| 7619 | var state = states[url]; |
| 7620 | |
| 7621 | // Add url to load queue |
| 7622 | if (state == undef) { |
| 7623 | queue.push(url); |
| 7624 | states[url] = QUEUED; |
| 7625 | } |
| 7626 | |
| 7627 | if (callback) { |
| 7628 | // Store away callback for later execution |
| 7629 | if (!scriptLoadedCallbacks[url]) { |
| 7630 | scriptLoadedCallbacks[url] = []; |
| 7631 | } |
| 7632 | |
| 7633 | scriptLoadedCallbacks[url].push({ |
| 7634 | func: callback, |
| 7635 | scope: scope || this |
| 7636 | }); |
| 7637 | } |
| 7638 | }; |
| 7639 | |
| 7640 | /** |
| 7641 | * Starts the loading of the queue. |
| 7642 | * |
| 7643 | * @method loadQueue |
| 7644 | * @param {function} callback Optional callback to execute when all queued items are loaded. |
| 7645 | * @param {Object} scope Optional scope to execute the callback in. |
| 7646 | */ |
| 7647 | this.loadQueue = function(callback, scope) { |
| 7648 | this.loadScripts(queue, callback, scope); |
| 7649 | }; |
| 7650 | |
| 7651 | /** |
| 7652 | * Loads the specified queue of files and executes the callback ones they are loaded. |
| 7653 | * This method is generally not used outside this class but it might be useful in some scenarios. |
| 7654 | * |
| 7655 | * @method loadScripts |
| 7656 | * @param {Array} scripts Array of queue items to load. |
| 7657 | * @param {function} callback Optional callback to execute ones all items are loaded. |
| 7658 | * @param {Object} scope Optional scope to execute callback in. |
| 7659 | */ |
| 7660 | this.loadScripts = function(scripts, callback, scope) { |
| 7661 | var loadScripts; |
| 7662 | |
| 7663 | function execScriptLoadedCallbacks(url) { |
| 7664 | // Execute URL callback functions |
| 7665 | each(scriptLoadedCallbacks[url], function(callback) { |
| 7666 | callback.func.call(callback.scope); |
| 7667 | }); |
| 7668 | |
| 7669 | scriptLoadedCallbacks[url] = undef; |
| 7670 | } |
| 7671 | |
| 7672 | queueLoadedCallbacks.push({ |
| 7673 | func: callback, |
| 7674 | scope: scope || this |
| 7675 | }); |
| 7676 | |
| 7677 | loadScripts = function() { |
| 7678 | var loadingScripts = grep(scripts); |
| 7679 | |
| 7680 | // Current scripts has been handled |
| 7681 | scripts.length = 0; |
| 7682 | |
| 7683 | // Load scripts that needs to be loaded |
| 7684 | each(loadingScripts, function(url) { |
| 7685 | // Script is already loaded then execute script callbacks directly |
| 7686 | if (states[url] == LOADED) { |
| 7687 | execScriptLoadedCallbacks(url); |
| 7688 | return; |
| 7689 | } |
| 7690 | |
| 7691 | // Is script not loading then start loading it |
| 7692 | if (states[url] != LOADING) { |
| 7693 | states[url] = LOADING; |
| 7694 | loading++; |
| 7695 | |
| 7696 | loadScript(url, function() { |
| 7697 | states[url] = LOADED; |
| 7698 | loading--; |
| 7699 | |
| 7700 | execScriptLoadedCallbacks(url); |
| 7701 | |
| 7702 | // Load more scripts if they where added by the recently loaded script |
| 7703 | loadScripts(); |
| 7704 | }); |
| 7705 | } |
| 7706 | }); |
| 7707 | |
| 7708 | // No scripts are currently loading then execute all pending queue loaded callbacks |
| 7709 | if (!loading) { |
| 7710 | each(queueLoadedCallbacks, function(callback) { |
| 7711 | callback.func.call(callback.scope); |
| 7712 | }); |
| 7713 | |
| 7714 | queueLoadedCallbacks.length = 0; |
| 7715 | } |
| 7716 | }; |
| 7717 | |
| 7718 | loadScripts(); |
| 7719 | }; |
| 7720 | } |
| 7721 | |
| 7722 | ScriptLoader.ScriptLoader = new ScriptLoader(); |
| 7723 | |
| 7724 | return ScriptLoader; |
| 7725 | }); |
| 7726 | |
| 7727 | // Included from: js/tinymce/classes/AddOnManager.js |
| 7728 | |
| 7729 | /** |
| 7730 | * AddOnManager.js |
| 7731 | * |
| 7732 | * Copyright, Moxiecode Systems AB |
| 7733 | * Released under LGPL License. |
| 7734 | * |
| 7735 | * License: http://www.tinymce.com/license |
| 7736 | * Contributing: http://www.tinymce.com/contributing |
| 7737 | */ |
| 7738 | |
| 7739 | /** |
| 7740 | * This class handles the loading of themes/plugins or other add-ons and their language packs. |
| 7741 | * |
| 7742 | * @class tinymce.AddOnManager |
| 7743 | */ |
| 7744 | define("tinymce/AddOnManager", [ |
| 7745 | "tinymce/dom/ScriptLoader", |
| 7746 | "tinymce/util/Tools" |
| 7747 | ], function(ScriptLoader, Tools) { |
| 7748 | var each = Tools.each; |
| 7749 | |
| 7750 | function AddOnManager() { |
| 7751 | var self = this; |
| 7752 | |
| 7753 | self.items = []; |
| 7754 | self.urls = {}; |
| 7755 | self.lookup = {}; |
| 7756 | } |
| 7757 | |
| 7758 | AddOnManager.prototype = { |
| 7759 | /** |
| 7760 | * Returns the specified add on by the short name. |
| 7761 | * |
| 7762 | * @method get |
| 7763 | * @param {String} name Add-on to look for. |
| 7764 | * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined. |
| 7765 | */ |
| 7766 | get: function(name) { |
| 7767 | if (this.lookup[name]) { |
| 7768 | return this.lookup[name].instance; |
| 7769 | } else { |
| 7770 | return undefined; |
| 7771 | } |
| 7772 | }, |
| 7773 | |
| 7774 | dependencies: function(name) { |
| 7775 | var result; |
| 7776 | |
| 7777 | if (this.lookup[name]) { |
| 7778 | result = this.lookup[name].dependencies; |
| 7779 | } |
| 7780 | |
| 7781 | return result || []; |
| 7782 | }, |
| 7783 | |
| 7784 | /** |
| 7785 | * Loads a language pack for the specified add-on. |
| 7786 | * |
| 7787 | * @method requireLangPack |
| 7788 | * @param {String} name Short name of the add-on. |
| 7789 | * @param {String} languages Optional comma or space separated list of languages to check if it matches the name. |
| 7790 | */ |
| 7791 | requireLangPack: function(name, languages) { |
| 7792 | if (AddOnManager.language && AddOnManager.languageLoad !== false) { |
| 7793 | if (languages && new RegExp('([, ]|\\b)' + AddOnManager.language + '([, ]|\\b)').test(languages) === false) { |
| 7794 | return; |
| 7795 | } |
| 7796 | |
| 7797 | ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js'); |
| 7798 | } |
| 7799 | }, |
| 7800 | |
| 7801 | /** |
| 7802 | * Adds a instance of the add-on by it's short name. |
| 7803 | * |
| 7804 | * @method add |
| 7805 | * @param {String} id Short name/id for the add-on. |
| 7806 | * @param {tinymce.Theme/tinymce.Plugin} addOn Theme or plugin to add. |
| 7807 | * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in. |
| 7808 | * @example |
| 7809 | * // Create a simple plugin |
| 7810 | * tinymce.create('tinymce.plugins.TestPlugin', { |
| 7811 | * TestPlugin: function(ed, url) { |
| 7812 | * ed.on('click', function(e) { |
| 7813 | * ed.windowManager.alert('Hello World!'); |
| 7814 | * }); |
| 7815 | * } |
| 7816 | * }); |
| 7817 | * |
| 7818 | * // Register plugin using the add method |
| 7819 | * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin); |
| 7820 | * |
| 7821 | * // Initialize TinyMCE |
| 7822 | * tinymce.init({ |
| 7823 | * ... |
| 7824 | * plugins: '-test' // Init the plugin but don't try to load it |
| 7825 | * }); |
| 7826 | */ |
| 7827 | add: function(id, addOn, dependencies) { |
| 7828 | this.items.push(addOn); |
| 7829 | this.lookup[id] = {instance: addOn, dependencies: dependencies}; |
| 7830 | |
| 7831 | return addOn; |
| 7832 | }, |
| 7833 | |
| 7834 | createUrl: function(baseUrl, dep) { |
| 7835 | if (typeof dep === "object") { |
| 7836 | return dep; |
| 7837 | } else { |
| 7838 | return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix}; |
| 7839 | } |
| 7840 | }, |
| 7841 | |
| 7842 | /** |
| 7843 | * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url. |
| 7844 | * This should be used in development mode. A new compressor/javascript munger process will ensure that the |
| 7845 | * components are put together into the plugin.js file and compressed correctly. |
| 7846 | * |
| 7847 | * @method addComponents |
| 7848 | * @param {String} pluginName name of the plugin to load scripts from (will be used to get the base url for the plugins). |
| 7849 | * @param {Array} scripts Array containing the names of the scripts to load. |
| 7850 | */ |
| 7851 | addComponents: function(pluginName, scripts) { |
| 7852 | var pluginUrl = this.urls[pluginName]; |
| 7853 | |
| 7854 | each(scripts, function(script) { |
| 7855 | ScriptLoader.ScriptLoader.add(pluginUrl + "/" + script); |
| 7856 | }); |
| 7857 | }, |
| 7858 | |
| 7859 | /** |
| 7860 | * Loads an add-on from a specific url. |
| 7861 | * |
| 7862 | * @method load |
| 7863 | * @param {String} n Short name of the add-on that gets loaded. |
| 7864 | * @param {String} u URL to the add-on that will get loaded. |
| 7865 | * @param {function} cb Optional callback to execute ones the add-on is loaded. |
| 7866 | * @param {Object} s Optional scope to execute the callback in. |
| 7867 | * @example |
| 7868 | * // Loads a plugin from an external URL |
| 7869 | * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js'); |
| 7870 | * |
| 7871 | * // Initialize TinyMCE |
| 7872 | * tinymce.init({ |
| 7873 | * ... |
| 7874 | * plugins: '-myplugin' // Don't try to load it again |
| 7875 | * }); |
| 7876 | */ |
| 7877 | load: function(n, u, cb, s) { |
| 7878 | var t = this, url = u; |
| 7879 | |
| 7880 | function loadDependencies() { |
| 7881 | var dependencies = t.dependencies(n); |
| 7882 | |
| 7883 | each(dependencies, function(dep) { |
| 7884 | var newUrl = t.createUrl(u, dep); |
| 7885 | |
| 7886 | t.load(newUrl.resource, newUrl, undefined, undefined); |
| 7887 | }); |
| 7888 | |
| 7889 | if (cb) { |
| 7890 | if (s) { |
| 7891 | cb.call(s); |
| 7892 | } else { |
| 7893 | cb.call(ScriptLoader); |
| 7894 | } |
| 7895 | } |
| 7896 | } |
| 7897 | |
| 7898 | if (t.urls[n]) { |
| 7899 | return; |
| 7900 | } |
| 7901 | |
| 7902 | if (typeof u === "object") { |
| 7903 | url = u.prefix + u.resource + u.suffix; |
| 7904 | } |
| 7905 | |
| 7906 | if (url.indexOf('/') !== 0 && url.indexOf('://') == -1) { |
| 7907 | url = AddOnManager.baseURL + '/' + url; |
| 7908 | } |
| 7909 | |
| 7910 | t.urls[n] = url.substring(0, url.lastIndexOf('/')); |
| 7911 | |
| 7912 | if (t.lookup[n]) { |
| 7913 | loadDependencies(); |
| 7914 | } else { |
| 7915 | ScriptLoader.ScriptLoader.add(url, loadDependencies, s); |
| 7916 | } |
| 7917 | } |
| 7918 | }; |
| 7919 | |
| 7920 | AddOnManager.PluginManager = new AddOnManager(); |
| 7921 | AddOnManager.ThemeManager = new AddOnManager(); |
| 7922 | |
| 7923 | return AddOnManager; |
| 7924 | }); |
| 7925 | |
| 7926 | /** |
| 7927 | * TinyMCE theme class. |
| 7928 | * |
| 7929 | * @class tinymce.Theme |
| 7930 | */ |
| 7931 | |
| 7932 | /** |
| 7933 | * This method is responsible for rendering/generating the overall user interface with toolbars, buttons, iframe containers etc. |
| 7934 | * |
| 7935 | * @method renderUI |
| 7936 | * @param {Object} obj Object parameter containing the targetNode DOM node that will be replaced visually with an editor instance. |
| 7937 | * @return {Object} an object with items like iframeContainer, editorContainer, sizeContainer, deltaWidth, deltaHeight. |
| 7938 | */ |
| 7939 | |
| 7940 | /** |
| 7941 | * Plugin base class, this is a pseudo class that describes how a plugin is to be created for TinyMCE. The methods below are all optional. |
| 7942 | * |
| 7943 | * @class tinymce.Plugin |
| 7944 | * @example |
| 7945 | * tinymce.PluginManager.add('example', function(editor, url) { |
| 7946 | * // Add a button that opens a window |
| 7947 | * editor.addButton('example', { |
| 7948 | * text: 'My button', |
| 7949 | * icon: false, |
| 7950 | * onclick: function() { |
| 7951 | * // Open window |
| 7952 | * editor.windowManager.open({ |
| 7953 | * title: 'Example plugin', |
| 7954 | * body: [ |
| 7955 | * {type: 'textbox', name: 'title', label: 'Title'} |
| 7956 | * ], |
| 7957 | * onsubmit: function(e) { |
| 7958 | * // Insert content when the window form is submitted |
| 7959 | * editor.insertContent('Title: ' + e.data.title); |
| 7960 | * } |
| 7961 | * }); |
| 7962 | * } |
| 7963 | * }); |
| 7964 | * |
| 7965 | * // Adds a menu item to the tools menu |
| 7966 | * editor.addMenuItem('example', { |
| 7967 | * text: 'Example plugin', |
| 7968 | * context: 'tools', |
| 7969 | * onclick: function() { |
| 7970 | * // Open window with a specific url |
| 7971 | * editor.windowManager.open({ |
| 7972 | * title: 'TinyMCE site', |
| 7973 | * url: 'http://www.tinymce.com', |
| 7974 | * width: 800, |
| 7975 | * height: 600, |
| 7976 | * buttons: [{ |
| 7977 | * text: 'Close', |
| 7978 | * onclick: 'close' |
| 7979 | * }] |
| 7980 | * }); |
| 7981 | * } |
| 7982 | * }); |
| 7983 | * }); |
| 7984 | */ |
| 7985 | |
| 7986 | // Included from: js/tinymce/classes/html/Node.js |
| 7987 | |
| 7988 | /** |
| 7989 | * Node.js |
| 7990 | * |
| 7991 | * Copyright, Moxiecode Systems AB |
| 7992 | * Released under LGPL License. |
| 7993 | * |
| 7994 | * License: http://www.tinymce.com/license |
| 7995 | * Contributing: http://www.tinymce.com/contributing |
| 7996 | */ |
| 7997 | |
| 7998 | /** |
| 7999 | * This class is a minimalistic implementation of a DOM like node used by the DomParser class. |
| 8000 | * |
| 8001 | * @example |
| 8002 | * var node = new tinymce.html.Node('strong', 1); |
| 8003 | * someRoot.append(node); |
| 8004 | * |
| 8005 | * @class tinymce.html.Node |
| 8006 | * @version 3.4 |
| 8007 | */ |
| 8008 | define("tinymce/html/Node", [], function() { |
| 8009 | var whiteSpaceRegExp = /^[ \t\r\n]*$/, typeLookup = { |
| 8010 | '#text': 3, |
| 8011 | '#comment': 8, |
| 8012 | '#cdata': 4, |
| 8013 | '#pi': 7, |
| 8014 | '#doctype': 10, |
| 8015 | '#document-fragment': 11 |
| 8016 | }; |
| 8017 | |
| 8018 | // Walks the tree left/right |
| 8019 | function walk(node, root_node, prev) { |
| 8020 | var sibling, parent, startName = prev ? 'lastChild' : 'firstChild', siblingName = prev ? 'prev' : 'next'; |
| 8021 | |
| 8022 | // Walk into nodes if it has a start |
| 8023 | if (node[startName]) { |
| 8024 | return node[startName]; |
| 8025 | } |
| 8026 | |
| 8027 | // Return the sibling if it has one |
| 8028 | if (node !== root_node) { |
| 8029 | sibling = node[siblingName]; |
| 8030 | |
| 8031 | if (sibling) { |
| 8032 | return sibling; |
| 8033 | } |
| 8034 | |
| 8035 | // Walk up the parents to look for siblings |
| 8036 | for (parent = node.parent; parent && parent !== root_node; parent = parent.parent) { |
| 8037 | sibling = parent[siblingName]; |
| 8038 | |
| 8039 | if (sibling) { |
| 8040 | return sibling; |
| 8041 | } |
| 8042 | } |
| 8043 | } |
| 8044 | } |
| 8045 | |
| 8046 | /** |
| 8047 | * Constructs a new Node instance. |
| 8048 | * |
| 8049 | * @constructor |
| 8050 | * @method Node |
| 8051 | * @param {String} name Name of the node type. |
| 8052 | * @param {Number} type Numeric type representing the node. |
| 8053 | */ |
| 8054 | function Node(name, type) { |
| 8055 | this.name = name; |
| 8056 | this.type = type; |
| 8057 | |
| 8058 | if (type === 1) { |
| 8059 | this.attributes = []; |
| 8060 | this.attributes.map = {}; |
| 8061 | } |
| 8062 | } |
| 8063 | |
| 8064 | Node.prototype = { |
| 8065 | /** |
| 8066 | * Replaces the current node with the specified one. |
| 8067 | * |
| 8068 | * @example |
| 8069 | * someNode.replace(someNewNode); |
| 8070 | * |
| 8071 | * @method replace |
| 8072 | * @param {tinymce.html.Node} node Node to replace the current node with. |
| 8073 | * @return {tinymce.html.Node} The old node that got replaced. |
| 8074 | */ |
| 8075 | replace: function(node) { |
| 8076 | var self = this; |
| 8077 | |
| 8078 | if (node.parent) { |
| 8079 | node.remove(); |
| 8080 | } |
| 8081 | |
| 8082 | self.insert(node, self); |
| 8083 | self.remove(); |
| 8084 | |
| 8085 | return self; |
| 8086 | }, |
| 8087 | |
| 8088 | /** |
| 8089 | * Gets/sets or removes an attribute by name. |
| 8090 | * |
| 8091 | * @example |
| 8092 | * someNode.attr("name", "value"); // Sets an attribute |
| 8093 | * console.log(someNode.attr("name")); // Gets an attribute |
| 8094 | * someNode.attr("name", null); // Removes an attribute |
| 8095 | * |
| 8096 | * @method attr |
| 8097 | * @param {String} name Attribute name to set or get. |
| 8098 | * @param {String} value Optional value to set. |
| 8099 | * @return {String/tinymce.html.Node} String or undefined on a get operation or the current node on a set operation. |
| 8100 | */ |
| 8101 | attr: function(name, value) { |
| 8102 | var self = this, attrs, i, undef; |
| 8103 | |
| 8104 | if (typeof name !== "string") { |
| 8105 | for (i in name) { |
| 8106 | self.attr(i, name[i]); |
| 8107 | } |
| 8108 | |
| 8109 | return self; |
| 8110 | } |
| 8111 | |
| 8112 | if ((attrs = self.attributes)) { |
| 8113 | if (value !== undef) { |
| 8114 | // Remove attribute |
| 8115 | if (value === null) { |
| 8116 | if (name in attrs.map) { |
| 8117 | delete attrs.map[name]; |
| 8118 | |
| 8119 | i = attrs.length; |
| 8120 | while (i--) { |
| 8121 | if (attrs[i].name === name) { |
| 8122 | attrs = attrs.splice(i, 1); |
| 8123 | return self; |
| 8124 | } |
| 8125 | } |
| 8126 | } |
| 8127 | |
| 8128 | return self; |
| 8129 | } |
| 8130 | |
| 8131 | // Set attribute |
| 8132 | if (name in attrs.map) { |
| 8133 | // Set attribute |
| 8134 | i = attrs.length; |
| 8135 | while (i--) { |
| 8136 | if (attrs[i].name === name) { |
| 8137 | attrs[i].value = value; |
| 8138 | break; |
| 8139 | } |
| 8140 | } |
| 8141 | } else { |
| 8142 | attrs.push({name: name, value: value}); |
| 8143 | } |
| 8144 | |
| 8145 | attrs.map[name] = value; |
| 8146 | |
| 8147 | return self; |
| 8148 | } else { |
| 8149 | return attrs.map[name]; |
| 8150 | } |
| 8151 | } |
| 8152 | }, |
| 8153 | |
| 8154 | /** |
| 8155 | * Does a shallow clones the node into a new node. It will also exclude id attributes since |
| 8156 | * there should only be one id per document. |
| 8157 | * |
| 8158 | * @example |
| 8159 | * var clonedNode = node.clone(); |
| 8160 | * |
| 8161 | * @method clone |
| 8162 | * @return {tinymce.html.Node} New copy of the original node. |
| 8163 | */ |
| 8164 | clone: function() { |
| 8165 | var self = this, clone = new Node(self.name, self.type), i, l, selfAttrs, selfAttr, cloneAttrs; |
| 8166 | |
| 8167 | // Clone element attributes |
| 8168 | if ((selfAttrs = self.attributes)) { |
| 8169 | cloneAttrs = []; |
| 8170 | cloneAttrs.map = {}; |
| 8171 | |
| 8172 | for (i = 0, l = selfAttrs.length; i < l; i++) { |
| 8173 | selfAttr = selfAttrs[i]; |
| 8174 | |
| 8175 | // Clone everything except id |
| 8176 | if (selfAttr.name !== 'id') { |
| 8177 | cloneAttrs[cloneAttrs.length] = {name: selfAttr.name, value: selfAttr.value}; |
| 8178 | cloneAttrs.map[selfAttr.name] = selfAttr.value; |
| 8179 | } |
| 8180 | } |
| 8181 | |
| 8182 | clone.attributes = cloneAttrs; |
| 8183 | } |
| 8184 | |
| 8185 | clone.value = self.value; |
| 8186 | clone.shortEnded = self.shortEnded; |
| 8187 | |
| 8188 | return clone; |
| 8189 | }, |
| 8190 | |
| 8191 | /** |
| 8192 | * Wraps the node in in another node. |
| 8193 | * |
| 8194 | * @example |
| 8195 | * node.wrap(wrapperNode); |
| 8196 | * |
| 8197 | * @method wrap |
| 8198 | */ |
| 8199 | wrap: function(wrapper) { |
| 8200 | var self = this; |
| 8201 | |
| 8202 | self.parent.insert(wrapper, self); |
| 8203 | wrapper.append(self); |
| 8204 | |
| 8205 | return self; |
| 8206 | }, |
| 8207 | |
| 8208 | /** |
| 8209 | * Unwraps the node in other words it removes the node but keeps the children. |
| 8210 | * |
| 8211 | * @example |
| 8212 | * node.unwrap(); |
| 8213 | * |
| 8214 | * @method unwrap |
| 8215 | */ |
| 8216 | unwrap: function() { |
| 8217 | var self = this, node, next; |
| 8218 | |
| 8219 | for (node = self.firstChild; node; ) { |
| 8220 | next = node.next; |
| 8221 | self.insert(node, self, true); |
| 8222 | node = next; |
| 8223 | } |
| 8224 | |
| 8225 | self.remove(); |
| 8226 | }, |
| 8227 | |
| 8228 | /** |
| 8229 | * Removes the node from it's parent. |
| 8230 | * |
| 8231 | * @example |
| 8232 | * node.remove(); |
| 8233 | * |
| 8234 | * @method remove |
| 8235 | * @return {tinymce.html.Node} Current node that got removed. |
| 8236 | */ |
| 8237 | remove: function() { |
| 8238 | var self = this, parent = self.parent, next = self.next, prev = self.prev; |
| 8239 | |
| 8240 | if (parent) { |
| 8241 | if (parent.firstChild === self) { |
| 8242 | parent.firstChild = next; |
| 8243 | |
| 8244 | if (next) { |
| 8245 | next.prev = null; |
| 8246 | } |
| 8247 | } else { |
| 8248 | prev.next = next; |
| 8249 | } |
| 8250 | |
| 8251 | if (parent.lastChild === self) { |
| 8252 | parent.lastChild = prev; |
| 8253 | |
| 8254 | if (prev) { |
| 8255 | prev.next = null; |
| 8256 | } |
| 8257 | } else { |
| 8258 | next.prev = prev; |
| 8259 | } |
| 8260 | |
| 8261 | self.parent = self.next = self.prev = null; |
| 8262 | } |
| 8263 | |
| 8264 | return self; |
| 8265 | }, |
| 8266 | |
| 8267 | /** |
| 8268 | * Appends a new node as a child of the current node. |
| 8269 | * |
| 8270 | * @example |
| 8271 | * node.append(someNode); |
| 8272 | * |
| 8273 | * @method append |
| 8274 | * @param {tinymce.html.Node} node Node to append as a child of the current one. |
| 8275 | * @return {tinymce.html.Node} The node that got appended. |
| 8276 | */ |
| 8277 | append: function(node) { |
| 8278 | var self = this, last; |
| 8279 | |
| 8280 | if (node.parent) { |
| 8281 | node.remove(); |
| 8282 | } |
| 8283 | |
| 8284 | last = self.lastChild; |
| 8285 | if (last) { |
| 8286 | last.next = node; |
| 8287 | node.prev = last; |
| 8288 | self.lastChild = node; |
| 8289 | } else { |
| 8290 | self.lastChild = self.firstChild = node; |
| 8291 | } |
| 8292 | |
| 8293 | node.parent = self; |
| 8294 | |
| 8295 | return node; |
| 8296 | }, |
| 8297 | |
| 8298 | /** |
| 8299 | * Inserts a node at a specific position as a child of the current node. |
| 8300 | * |
| 8301 | * @example |
| 8302 | * parentNode.insert(newChildNode, oldChildNode); |
| 8303 | * |
| 8304 | * @method insert |
| 8305 | * @param {tinymce.html.Node} node Node to insert as a child of the current node. |
| 8306 | * @param {tinymce.html.Node} ref_node Reference node to set node before/after. |
| 8307 | * @param {Boolean} before Optional state to insert the node before the reference node. |
| 8308 | * @return {tinymce.html.Node} The node that got inserted. |
| 8309 | */ |
| 8310 | insert: function(node, ref_node, before) { |
| 8311 | var parent; |
| 8312 | |
| 8313 | if (node.parent) { |
| 8314 | node.remove(); |
| 8315 | } |
| 8316 | |
| 8317 | parent = ref_node.parent || this; |
| 8318 | |
| 8319 | if (before) { |
| 8320 | if (ref_node === parent.firstChild) { |
| 8321 | parent.firstChild = node; |
| 8322 | } else { |
| 8323 | ref_node.prev.next = node; |
| 8324 | } |
| 8325 | |
| 8326 | node.prev = ref_node.prev; |
| 8327 | node.next = ref_node; |
| 8328 | ref_node.prev = node; |
| 8329 | } else { |
| 8330 | if (ref_node === parent.lastChild) { |
| 8331 | parent.lastChild = node; |
| 8332 | } else { |
| 8333 | ref_node.next.prev = node; |
| 8334 | } |
| 8335 | |
| 8336 | node.next = ref_node.next; |
| 8337 | node.prev = ref_node; |
| 8338 | ref_node.next = node; |
| 8339 | } |
| 8340 | |
| 8341 | node.parent = parent; |
| 8342 | |
| 8343 | return node; |
| 8344 | }, |
| 8345 | |
| 8346 | /** |
| 8347 | * Get all children by name. |
| 8348 | * |
| 8349 | * @method getAll |
| 8350 | * @param {String} name Name of the child nodes to collect. |
| 8351 | * @return {Array} Array with child nodes matchin the specified name. |
| 8352 | */ |
| 8353 | getAll: function(name) { |
| 8354 | var self = this, node, collection = []; |
| 8355 | |
| 8356 | for (node = self.firstChild; node; node = walk(node, self)) { |
| 8357 | if (node.name === name) { |
| 8358 | collection.push(node); |
| 8359 | } |
| 8360 | } |
| 8361 | |
| 8362 | return collection; |
| 8363 | }, |
| 8364 | |
| 8365 | /** |
| 8366 | * Removes all children of the current node. |
| 8367 | * |
| 8368 | * @method empty |
| 8369 | * @return {tinymce.html.Node} The current node that got cleared. |
| 8370 | */ |
| 8371 | empty: function() { |
| 8372 | var self = this, nodes, i, node; |
| 8373 | |
| 8374 | // Remove all children |
| 8375 | if (self.firstChild) { |
| 8376 | nodes = []; |
| 8377 | |
| 8378 | // Collect the children |
| 8379 | for (node = self.firstChild; node; node = walk(node, self)) { |
| 8380 | nodes.push(node); |
| 8381 | } |
| 8382 | |
| 8383 | // Remove the children |
| 8384 | i = nodes.length; |
| 8385 | while (i--) { |
| 8386 | node = nodes[i]; |
| 8387 | node.parent = node.firstChild = node.lastChild = node.next = node.prev = null; |
| 8388 | } |
| 8389 | } |
| 8390 | |
| 8391 | self.firstChild = self.lastChild = null; |
| 8392 | |
| 8393 | return self; |
| 8394 | }, |
| 8395 | |
| 8396 | /** |
| 8397 | * Returns true/false if the node is to be considered empty or not. |
| 8398 | * |
| 8399 | * @example |
| 8400 | * node.isEmpty({img: true}); |
| 8401 | * @method isEmpty |
| 8402 | * @param {Object} elements Name/value object with elements that are automatically treated as non empty elements. |
| 8403 | * @return {Boolean} true/false if the node is empty or not. |
| 8404 | */ |
| 8405 | isEmpty: function(elements) { |
| 8406 | var self = this, node = self.firstChild, i, name; |
| 8407 | |
| 8408 | if (node) { |
| 8409 | do { |
| 8410 | if (node.type === 1) { |
| 8411 | // Ignore bogus elements |
| 8412 | if (node.attributes.map['data-mce-bogus']) { |
| 8413 | continue; |
| 8414 | } |
| 8415 | |
| 8416 | // Keep empty elements like <img /> |
| 8417 | if (elements[node.name]) { |
| 8418 | return false; |
| 8419 | } |
| 8420 | |
| 8421 | // Keep elements with data attributes or name attribute like <a name="1"></a> |
| 8422 | i = node.attributes.length; |
| 8423 | while (i--) { |
| 8424 | name = node.attributes[i].name; |
| 8425 | if (name === "name" || name.indexOf('data-mce-') === 0) { |
| 8426 | return false; |
| 8427 | } |
| 8428 | } |
| 8429 | } |
| 8430 | |
| 8431 | // Keep comments |
| 8432 | if (node.type === 8) { |
| 8433 | return false; |
| 8434 | } |
| 8435 | |
| 8436 | // Keep non whitespace text nodes |
| 8437 | if ((node.type === 3 && !whiteSpaceRegExp.test(node.value))) { |
| 8438 | return false; |
| 8439 | } |
| 8440 | } while ((node = walk(node, self))); |
| 8441 | } |
| 8442 | |
| 8443 | return true; |
| 8444 | }, |
| 8445 | |
| 8446 | /** |
| 8447 | * Walks to the next or previous node and returns that node or null if it wasn't found. |
| 8448 | * |
| 8449 | * @method walk |
| 8450 | * @param {Boolean} prev Optional previous node state defaults to false. |
| 8451 | * @return {tinymce.html.Node} Node that is next to or previous of the current node. |
| 8452 | */ |
| 8453 | walk: function(prev) { |
| 8454 | return walk(this, null, prev); |
| 8455 | } |
| 8456 | }; |
| 8457 | |
| 8458 | /** |
| 8459 | * Creates a node of a specific type. |
| 8460 | * |
| 8461 | * @static |
| 8462 | * @method create |
| 8463 | * @param {String} name Name of the node type to create for example "b" or "#text". |
| 8464 | * @param {Object} attrs Name/value collection of attributes that will be applied to elements. |
| 8465 | */ |
| 8466 | Node.create = function(name, attrs) { |
| 8467 | var node, attrName; |
| 8468 | |
| 8469 | // Create node |
| 8470 | node = new Node(name, typeLookup[name] || 1); |
| 8471 | |
| 8472 | // Add attributes if needed |
| 8473 | if (attrs) { |
| 8474 | for (attrName in attrs) { |
| 8475 | node.attr(attrName, attrs[attrName]); |
| 8476 | } |
| 8477 | } |
| 8478 | |
| 8479 | return node; |
| 8480 | }; |
| 8481 | |
| 8482 | return Node; |
| 8483 | }); |
| 8484 | |
| 8485 | // Included from: js/tinymce/classes/html/Schema.js |
| 8486 | |
| 8487 | /** |
| 8488 | * Schema.js |
| 8489 | * |
| 8490 | * Copyright, Moxiecode Systems AB |
| 8491 | * Released under LGPL License. |
| 8492 | * |
| 8493 | * License: http://www.tinymce.com/license |
| 8494 | * Contributing: http://www.tinymce.com/contributing |
| 8495 | */ |
| 8496 | |
| 8497 | /** |
| 8498 | * Schema validator class. |
| 8499 | * |
| 8500 | * @class tinymce.html.Schema |
| 8501 | * @example |
| 8502 | * if (tinymce.activeEditor.schema.isValidChild('p', 'span')) |
| 8503 | * alert('span is valid child of p.'); |
| 8504 | * |
| 8505 | * if (tinymce.activeEditor.schema.getElementRule('p')) |
| 8506 | * alert('P is a valid element.'); |
| 8507 | * |
| 8508 | * @class tinymce.html.Schema |
| 8509 | * @version 3.4 |
| 8510 | */ |
| 8511 | define("tinymce/html/Schema", [ |
| 8512 | "tinymce/util/Tools" |
| 8513 | ], function(Tools) { |
| 8514 | var mapCache = {}; |
| 8515 | var makeMap = Tools.makeMap, each = Tools.each, extend = Tools.extend, explode = Tools.explode, inArray = Tools.inArray; |
| 8516 | |
| 8517 | function split(items, delim) { |
| 8518 | return items ? items.split(delim || ' ') : []; |
| 8519 | } |
| 8520 | |
| 8521 | /** |
| 8522 | * Builds a schema lookup table |
| 8523 | * |
| 8524 | * @private |
| 8525 | * @param {String} type html4, html5 or html5-strict schema type. |
| 8526 | * @return {Object} Schema lookup table. |
| 8527 | */ |
| 8528 | function compileSchema(type) { |
| 8529 | var schema = {}, globalAttributes, eventAttributes, blockContent; |
| 8530 | var phrasingContent, flowContent, html4BlockContent, html4PhrasingContent; |
| 8531 | |
| 8532 | function add(name, attributes, children) { |
| 8533 | var ni, i, attributesOrder, args = arguments; |
| 8534 | |
| 8535 | function arrayToMap(array) { |
| 8536 | var map = {}, i, l; |
| 8537 | |
| 8538 | for (i = 0, l = array.length; i < l; i++) { |
| 8539 | map[array[i]] = {}; |
| 8540 | } |
| 8541 | |
| 8542 | return map; |
| 8543 | } |
| 8544 | |
| 8545 | children = children || []; |
| 8546 | attributes = attributes || ""; |
| 8547 | |
| 8548 | if (typeof(children) === "string") { |
| 8549 | children = split(children); |
| 8550 | } |
| 8551 | |
| 8552 | // Split string children |
| 8553 | for (i = 3; i < args.length; i++) { |
| 8554 | if (typeof(args[i]) === "string") { |
| 8555 | args[i] = split(args[i]); |
| 8556 | } |
| 8557 | |
| 8558 | children.push.apply(children, args[i]); |
| 8559 | } |
| 8560 | |
| 8561 | name = split(name); |
| 8562 | ni = name.length; |
| 8563 | while (ni--) { |
| 8564 | attributesOrder = [].concat(globalAttributes, split(attributes)); |
| 8565 | schema[name[ni]] = { |
| 8566 | attributes: arrayToMap(attributesOrder), |
| 8567 | attributesOrder: attributesOrder, |
| 8568 | children: arrayToMap(children) |
| 8569 | }; |
| 8570 | } |
| 8571 | } |
| 8572 | |
| 8573 | function addAttrs(name, attributes) { |
| 8574 | var ni, schemaItem, i, l; |
| 8575 | |
| 8576 | name = split(name); |
| 8577 | ni = name.length; |
| 8578 | attributes = split(attributes); |
| 8579 | while (ni--) { |
| 8580 | schemaItem = schema[name[ni]]; |
| 8581 | for (i = 0, l = attributes.length; i < l; i++) { |
| 8582 | schemaItem.attributes[attributes[i]] = {}; |
| 8583 | schemaItem.attributesOrder.push(attributes[i]); |
| 8584 | } |
| 8585 | } |
| 8586 | } |
| 8587 | |
| 8588 | // Use cached schema |
| 8589 | if (mapCache[type]) { |
| 8590 | return mapCache[type]; |
| 8591 | } |
| 8592 | |
| 8593 | // Attributes present on all elements |
| 8594 | globalAttributes = split("id accesskey class dir lang style tabindex title"); |
| 8595 | |
| 8596 | // Event attributes can be opt-in/opt-out |
| 8597 | eventAttributes = split("onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange " + |
| 8598 | "ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended " + |
| 8599 | "onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart " + |
| 8600 | "onmousedown onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange " + |
| 8601 | "onreset onscroll onseeked onseeking onseeking onselect onshow onstalled onsubmit onsuspend ontimeupdate onvolumechange " + |
| 8602 | "onwaiting" |
| 8603 | ); |
| 8604 | |
| 8605 | // Block content elements |
| 8606 | blockContent = split( |
| 8607 | "address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul" |
| 8608 | ); |
| 8609 | |
| 8610 | // Phrasing content elements from the HTML5 spec (inline) |
| 8611 | phrasingContent = split( |
| 8612 | "a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd " + |
| 8613 | "label map noscript object q s samp script select small span strong sub sup " + |
| 8614 | "textarea u var #text #comment" |
| 8615 | ); |
| 8616 | |
| 8617 | // Add HTML5 items to globalAttributes, blockContent, phrasingContent |
| 8618 | if (type != "html4") { |
| 8619 | globalAttributes.push.apply(globalAttributes, split("contenteditable contextmenu draggable dropzone " + |
| 8620 | "hidden spellcheck translate")); |
| 8621 | blockContent.push.apply(blockContent, split("article aside details dialog figure header footer hgroup section nav")); |
| 8622 | phrasingContent.push.apply(phrasingContent, split("audio canvas command datalist mark meter output progress time wbr " + |
| 8623 | "video ruby bdi keygen")); |
| 8624 | } |
| 8625 | |
| 8626 | // Add HTML4 elements unless it's html5-strict |
| 8627 | if (type != "html5-strict") { |
| 8628 | globalAttributes.push("xml:lang"); |
| 8629 | |
| 8630 | html4PhrasingContent = split("acronym applet basefont big font strike tt"); |
| 8631 | phrasingContent.push.apply(phrasingContent, html4PhrasingContent); |
| 8632 | |
| 8633 | each(html4PhrasingContent, function(name) { |
| 8634 | add(name, "", phrasingContent); |
| 8635 | }); |
| 8636 | |
| 8637 | html4BlockContent = split("center dir isindex noframes"); |
| 8638 | blockContent.push.apply(blockContent, html4BlockContent); |
| 8639 | |
| 8640 | // Flow content elements from the HTML5 spec (block+inline) |
| 8641 | flowContent = [].concat(blockContent, phrasingContent); |
| 8642 | |
| 8643 | each(html4BlockContent, function(name) { |
| 8644 | add(name, "", flowContent); |
| 8645 | }); |
| 8646 | } |
| 8647 | |
| 8648 | // Flow content elements from the HTML5 spec (block+inline) |
| 8649 | flowContent = flowContent || [].concat(blockContent, phrasingContent); |
| 8650 | |
| 8651 | // HTML4 base schema TODO: Move HTML5 specific attributes to HTML5 specific if statement |
| 8652 | // Schema items <element name>, <specific attributes>, <children ..> |
| 8653 | add("html", "manifest", "head body"); |
| 8654 | add("head", "", "base command link meta noscript script style title"); |
| 8655 | add("title hr noscript br"); |
| 8656 | add("base", "href target"); |
| 8657 | add("link", "href rel media hreflang type sizes hreflang"); |
| 8658 | add("meta", "name http-equiv content charset"); |
| 8659 | add("style", "media type scoped"); |
| 8660 | add("script", "src async defer type charset"); |
| 8661 | add("body", "onafterprint onbeforeprint onbeforeunload onblur onerror onfocus " + |
| 8662 | "onhashchange onload onmessage onoffline ononline onpagehide onpageshow " + |
| 8663 | "onpopstate onresize onscroll onstorage onunload", flowContent); |
| 8664 | add("address dt dd div caption", "", flowContent); |
| 8665 | add("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn", "", phrasingContent); |
| 8666 | add("blockquote", "cite", flowContent); |
| 8667 | add("ol", "reversed start type", "li"); |
| 8668 | add("ul", "", "li"); |
| 8669 | add("li", "value", flowContent); |
| 8670 | add("dl", "", "dt dd"); |
| 8671 | add("a", "href target rel media hreflang type", phrasingContent); |
| 8672 | add("q", "cite", phrasingContent); |
| 8673 | add("ins del", "cite datetime", flowContent); |
| 8674 | add("img", "src alt usemap ismap width height"); |
| 8675 | add("iframe", "src name width height", flowContent); |
| 8676 | add("embed", "src type width height"); |
| 8677 | add("object", "data type typemustmatch name usemap form width height", flowContent, "param"); |
| 8678 | add("param", "name value"); |
| 8679 | add("map", "name", flowContent, "area"); |
| 8680 | add("area", "alt coords shape href target rel media hreflang type"); |
| 8681 | add("table", "border", "caption colgroup thead tfoot tbody tr" + (type == "html4" ? " col" : "")); |
| 8682 | add("colgroup", "span", "col"); |
| 8683 | add("col", "span"); |
| 8684 | add("tbody thead tfoot", "", "tr"); |
| 8685 | add("tr", "", "td th"); |
| 8686 | add("td", "colspan rowspan headers", flowContent); |
| 8687 | add("th", "colspan rowspan headers scope abbr", flowContent); |
| 8688 | add("form", "accept-charset action autocomplete enctype method name novalidate target", flowContent); |
| 8689 | add("fieldset", "disabled form name", flowContent, "legend"); |
| 8690 | add("label", "form for", phrasingContent); |
| 8691 | add("input", "accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate " + |
| 8692 | "formtarget height list max maxlength min multiple name pattern readonly required size src step type value width" |
| 8693 | ); |
| 8694 | add("button", "disabled form formaction formenctype formmethod formnovalidate formtarget name type value", |
| 8695 | type == "html4" ? flowContent : phrasingContent); |
| 8696 | add("select", "disabled form multiple name required size", "option optgroup"); |
| 8697 | add("optgroup", "disabled label", "option"); |
| 8698 | add("option", "disabled label selected value"); |
| 8699 | add("textarea", "cols dirname disabled form maxlength name readonly required rows wrap"); |
| 8700 | add("menu", "type label", flowContent, "li"); |
| 8701 | add("noscript", "", flowContent); |
| 8702 | |
| 8703 | // Extend with HTML5 elements |
| 8704 | if (type != "html4") { |
| 8705 | add("wbr"); |
| 8706 | add("ruby", "", phrasingContent, "rt rp"); |
| 8707 | add("figcaption", "", flowContent); |
| 8708 | add("mark rt rp summary bdi", "", phrasingContent); |
| 8709 | add("canvas", "width height", flowContent); |
| 8710 | add("video", "src crossorigin poster preload autoplay mediagroup loop " + |
| 8711 | "muted controls width height", flowContent, "track source"); |
| 8712 | add("audio", "src crossorigin preload autoplay mediagroup loop muted controls", flowContent, "track source"); |
| 8713 | add("source", "src type media"); |
| 8714 | add("track", "kind src srclang label default"); |
| 8715 | add("datalist", "", phrasingContent, "option"); |
| 8716 | add("article section nav aside header footer", "", flowContent); |
| 8717 | add("hgroup", "", "h1 h2 h3 h4 h5 h6"); |
| 8718 | add("figure", "", flowContent, "figcaption"); |
| 8719 | add("time", "datetime", phrasingContent); |
| 8720 | add("dialog", "open", flowContent); |
| 8721 | add("command", "type label icon disabled checked radiogroup command"); |
| 8722 | add("output", "for form name", phrasingContent); |
| 8723 | add("progress", "value max", phrasingContent); |
| 8724 | add("meter", "value min max low high optimum", phrasingContent); |
| 8725 | add("details", "open", flowContent, "summary"); |
| 8726 | add("keygen", "autofocus challenge disabled form keytype name"); |
| 8727 | } |
| 8728 | |
| 8729 | // Extend with HTML4 attributes unless it's html5-strict |
| 8730 | if (type != "html5-strict") { |
| 8731 | addAttrs("script", "language xml:space"); |
| 8732 | addAttrs("style", "xml:space"); |
| 8733 | addAttrs("object", "declare classid codebase codetype archive standby align border hspace vspace"); |
| 8734 | addAttrs("param", "valuetype type"); |
| 8735 | addAttrs("a", "charset name rev shape coords"); |
| 8736 | addAttrs("br", "clear"); |
| 8737 | addAttrs("applet", "codebase archive code object alt name width height align hspace vspace"); |
| 8738 | addAttrs("img", "name longdesc align border hspace vspace"); |
| 8739 | addAttrs("iframe", "longdesc frameborder marginwidth marginheight scrolling align"); |
| 8740 | addAttrs("font basefont", "size color face"); |
| 8741 | addAttrs("input", "usemap align"); |
| 8742 | addAttrs("select", "onchange"); |
| 8743 | addAttrs("textarea"); |
| 8744 | addAttrs("h1 h2 h3 h4 h5 h6 div p legend caption", "align"); |
| 8745 | addAttrs("ul", "type compact"); |
| 8746 | addAttrs("li", "type"); |
| 8747 | addAttrs("ol dl menu dir", "compact"); |
| 8748 | addAttrs("pre", "width xml:space"); |
| 8749 | addAttrs("hr", "align noshade size width"); |
| 8750 | addAttrs("isindex", "prompt"); |
| 8751 | addAttrs("table", "summary width frame rules cellspacing cellpadding align bgcolor"); |
| 8752 | addAttrs("col", "width align char charoff valign"); |
| 8753 | addAttrs("colgroup", "width align char charoff valign"); |
| 8754 | addAttrs("thead", "align char charoff valign"); |
| 8755 | addAttrs("tr", "align char charoff valign bgcolor"); |
| 8756 | addAttrs("th", "axis align char charoff valign nowrap bgcolor width height"); |
| 8757 | addAttrs("form", "accept"); |
| 8758 | addAttrs("td", "abbr axis scope align char charoff valign nowrap bgcolor width height"); |
| 8759 | addAttrs("tfoot", "align char charoff valign"); |
| 8760 | addAttrs("tbody", "align char charoff valign"); |
| 8761 | addAttrs("area", "nohref"); |
| 8762 | addAttrs("body", "background bgcolor text link vlink alink"); |
| 8763 | } |
| 8764 | |
| 8765 | // Extend with HTML5 attributes unless it's html4 |
| 8766 | if (type != "html4") { |
| 8767 | addAttrs("input button select textarea", "autofocus"); |
| 8768 | addAttrs("input textarea", "placeholder"); |
| 8769 | addAttrs("a", "download"); |
| 8770 | addAttrs("link script img", "crossorigin"); |
| 8771 | addAttrs("iframe", "srcdoc sandbox seamless allowfullscreen"); |
| 8772 | } |
| 8773 | |
| 8774 | // Special: iframe, ruby, video, audio, label |
| 8775 | |
| 8776 | // Delete children of the same name from it's parent |
| 8777 | // For example: form can't have a child of the name form |
| 8778 | each(split('a form meter progress dfn'), function(name) { |
| 8779 | if (schema[name]) { |
| 8780 | delete schema[name].children[name]; |
| 8781 | } |
| 8782 | }); |
| 8783 | |
| 8784 | // Delete header, footer, sectioning and heading content descendants |
| 8785 | /*each('dt th address', function(name) { |
| 8786 | delete schema[name].children[name]; |
| 8787 | });*/ |
| 8788 | |
| 8789 | // Caption can't have tables |
| 8790 | delete schema.caption.children.table; |
| 8791 | |
| 8792 | // TODO: LI:s can only have value if parent is OL |
| 8793 | |
| 8794 | // TODO: Handle transparent elements |
| 8795 | // a ins del canvas map |
| 8796 | |
| 8797 | mapCache[type] = schema; |
| 8798 | |
| 8799 | return schema; |
| 8800 | } |
| 8801 | |
| 8802 | /** |
| 8803 | * Constructs a new Schema instance. |
| 8804 | * |
| 8805 | * @constructor |
| 8806 | * @method Schema |
| 8807 | * @param {Object} settings Name/value settings object. |
| 8808 | */ |
| 8809 | return function(settings) { |
| 8810 | var self = this, elements = {}, children = {}, patternElements = [], validStyles, schemaItems; |
| 8811 | var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap; |
| 8812 | var blockElementsMap, nonEmptyElementsMap, textBlockElementsMap, customElementsMap = {}, specialElements = {}; |
| 8813 | |
| 8814 | // Creates an lookup table map object for the specified option or the default value |
| 8815 | function createLookupTable(option, default_value, extendWith) { |
| 8816 | var value = settings[option]; |
| 8817 | |
| 8818 | if (!value) { |
| 8819 | // Get cached default map or make it if needed |
| 8820 | value = mapCache[option]; |
| 8821 | |
| 8822 | if (!value) { |
| 8823 | value = makeMap(default_value, ' ', makeMap(default_value.toUpperCase(), ' ')); |
| 8824 | value = extend(value, extendWith); |
| 8825 | |
| 8826 | mapCache[option] = value; |
| 8827 | } |
| 8828 | } else { |
| 8829 | // Create custom map |
| 8830 | value = makeMap(value, ',', makeMap(value.toUpperCase(), ' ')); |
| 8831 | } |
| 8832 | |
| 8833 | return value; |
| 8834 | } |
| 8835 | |
| 8836 | settings = settings || {}; |
| 8837 | schemaItems = compileSchema(settings.schema); |
| 8838 | |
| 8839 | // Allow all elements and attributes if verify_html is set to false |
| 8840 | if (settings.verify_html === false) { |
| 8841 | settings.valid_elements = '*[*]'; |
| 8842 | } |
| 8843 | |
| 8844 | // Build styles list |
| 8845 | if (settings.valid_styles) { |
| 8846 | validStyles = {}; |
| 8847 | |
| 8848 | // Convert styles into a rule list |
| 8849 | each(settings.valid_styles, function(value, key) { |
| 8850 | validStyles[key] = explode(value); |
| 8851 | }); |
| 8852 | } |
| 8853 | |
| 8854 | // Setup map objects |
| 8855 | whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object'); |
| 8856 | selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr'); |
| 8857 | shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link ' + |
| 8858 | 'meta param embed source wbr track'); |
| 8859 | boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + |
| 8860 | 'noshade nowrap readonly selected autoplay loop controls'); |
| 8861 | nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object script', shortEndedElementsMap); |
| 8862 | textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' + |
| 8863 | 'blockquote center dir fieldset header footer article section hgroup aside nav figure'); |
| 8864 | blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' + |
| 8865 | 'th tr td li ol ul caption dl dt dd noscript menu isindex samp option ' + |
| 8866 | 'datalist select optgroup', textBlockElementsMap); |
| 8867 | |
| 8868 | each((settings.special || 'script noscript style textarea').split(' '), function(name) { |
| 8869 | specialElements[name] = new RegExp('<\/' + name + '[^>]*>','gi'); |
| 8870 | }); |
| 8871 | |
| 8872 | // Converts a wildcard expression string to a regexp for example *a will become /.*a/. |
| 8873 | function patternToRegExp(str) { |
| 8874 | return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$'); |
| 8875 | } |
| 8876 | |
| 8877 | // Parses the specified valid_elements string and adds to the current rules |
| 8878 | // This function is a bit hard to read since it's heavily optimized for speed |
| 8879 | function addValidElements(valid_elements) { |
| 8880 | var ei, el, ai, al, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder, |
| 8881 | prefix, outputName, globalAttributes, globalAttributesOrder, key, value, |
| 8882 | elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/, |
| 8883 | attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/, |
| 8884 | hasPatternsRegExp = /[*?+]/; |
| 8885 | |
| 8886 | if (valid_elements) { |
| 8887 | // Split valid elements into an array with rules |
| 8888 | valid_elements = split(valid_elements, ','); |
| 8889 | |
| 8890 | if (elements['@']) { |
| 8891 | globalAttributes = elements['@'].attributes; |
| 8892 | globalAttributesOrder = elements['@'].attributesOrder; |
| 8893 | } |
| 8894 | |
| 8895 | // Loop all rules |
| 8896 | for (ei = 0, el = valid_elements.length; ei < el; ei++) { |
| 8897 | // Parse element rule |
| 8898 | matches = elementRuleRegExp.exec(valid_elements[ei]); |
| 8899 | if (matches) { |
| 8900 | // Setup local names for matches |
| 8901 | prefix = matches[1]; |
| 8902 | elementName = matches[2]; |
| 8903 | outputName = matches[3]; |
| 8904 | attrData = matches[5]; |
| 8905 | |
| 8906 | // Create new attributes and attributesOrder |
| 8907 | attributes = {}; |
| 8908 | attributesOrder = []; |
| 8909 | |
| 8910 | // Create the new element |
| 8911 | element = { |
| 8912 | attributes: attributes, |
| 8913 | attributesOrder: attributesOrder |
| 8914 | }; |
| 8915 | |
| 8916 | // Padd empty elements prefix |
| 8917 | if (prefix === '#') { |
| 8918 | element.paddEmpty = true; |
| 8919 | } |
| 8920 | |
| 8921 | // Remove empty elements prefix |
| 8922 | if (prefix === '-') { |
| 8923 | element.removeEmpty = true; |
| 8924 | } |
| 8925 | |
| 8926 | if (matches[4] === '!') { |
| 8927 | element.removeEmptyAttrs = true; |
| 8928 | } |
| 8929 | |
| 8930 | // Copy attributes from global rule into current rule |
| 8931 | if (globalAttributes) { |
| 8932 | for (key in globalAttributes) { |
| 8933 | attributes[key] = globalAttributes[key]; |
| 8934 | } |
| 8935 | |
| 8936 | attributesOrder.push.apply(attributesOrder, globalAttributesOrder); |
| 8937 | } |
| 8938 | |
| 8939 | // Attributes defined |
| 8940 | if (attrData) { |
| 8941 | attrData = split(attrData, '|'); |
| 8942 | for (ai = 0, al = attrData.length; ai < al; ai++) { |
| 8943 | matches = attrRuleRegExp.exec(attrData[ai]); |
| 8944 | if (matches) { |
| 8945 | attr = {}; |
| 8946 | attrType = matches[1]; |
| 8947 | attrName = matches[2].replace(/::/g, ':'); |
| 8948 | prefix = matches[3]; |
| 8949 | value = matches[4]; |
| 8950 | |
| 8951 | // Required |
| 8952 | if (attrType === '!') { |
| 8953 | element.attributesRequired = element.attributesRequired || []; |
| 8954 | element.attributesRequired.push(attrName); |
| 8955 | attr.required = true; |
| 8956 | } |
| 8957 | |
| 8958 | // Denied from global |
| 8959 | if (attrType === '-') { |
| 8960 | delete attributes[attrName]; |
| 8961 | attributesOrder.splice(inArray(attributesOrder, attrName), 1); |
| 8962 | continue; |
| 8963 | } |
| 8964 | |
| 8965 | // Default value |
| 8966 | if (prefix) { |
| 8967 | // Default value |
| 8968 | if (prefix === '=') { |
| 8969 | element.attributesDefault = element.attributesDefault || []; |
| 8970 | element.attributesDefault.push({name: attrName, value: value}); |
| 8971 | attr.defaultValue = value; |
| 8972 | } |
| 8973 | |
| 8974 | // Forced value |
| 8975 | if (prefix === ':') { |
| 8976 | element.attributesForced = element.attributesForced || []; |
| 8977 | element.attributesForced.push({name: attrName, value: value}); |
| 8978 | attr.forcedValue = value; |
| 8979 | } |
| 8980 | |
| 8981 | // Required values |
| 8982 | if (prefix === '<') { |
| 8983 | attr.validValues = makeMap(value, '?'); |
| 8984 | } |
| 8985 | } |
| 8986 | |
| 8987 | // Check for attribute patterns |
| 8988 | if (hasPatternsRegExp.test(attrName)) { |
| 8989 | element.attributePatterns = element.attributePatterns || []; |
| 8990 | attr.pattern = patternToRegExp(attrName); |
| 8991 | element.attributePatterns.push(attr); |
| 8992 | } else { |
| 8993 | // Add attribute to order list if it doesn't already exist |
| 8994 | if (!attributes[attrName]) { |
| 8995 | attributesOrder.push(attrName); |
| 8996 | } |
| 8997 | |
| 8998 | attributes[attrName] = attr; |
| 8999 | } |
| 9000 | } |
| 9001 | } |
| 9002 | } |
| 9003 | |
| 9004 | // Global rule, store away these for later usage |
| 9005 | if (!globalAttributes && elementName == '@') { |
| 9006 | globalAttributes = attributes; |
| 9007 | globalAttributesOrder = attributesOrder; |
| 9008 | } |
| 9009 | |
| 9010 | // Handle substitute elements such as b/strong |
| 9011 | if (outputName) { |
| 9012 | element.outputName = elementName; |
| 9013 | elements[outputName] = element; |
| 9014 | } |
| 9015 | |
| 9016 | // Add pattern or exact element |
| 9017 | if (hasPatternsRegExp.test(elementName)) { |
| 9018 | element.pattern = patternToRegExp(elementName); |
| 9019 | patternElements.push(element); |
| 9020 | } else { |
| 9021 | elements[elementName] = element; |
| 9022 | } |
| 9023 | } |
| 9024 | } |
| 9025 | } |
| 9026 | } |
| 9027 | |
| 9028 | function setValidElements(valid_elements) { |
| 9029 | elements = {}; |
| 9030 | patternElements = []; |
| 9031 | |
| 9032 | addValidElements(valid_elements); |
| 9033 | |
| 9034 | each(schemaItems, function(element, name) { |
| 9035 | children[name] = element.children; |
| 9036 | }); |
| 9037 | } |
| 9038 | |
| 9039 | // Adds custom non HTML elements to the schema |
| 9040 | function addCustomElements(custom_elements) { |
| 9041 | var customElementRegExp = /^(~)?(.+)$/; |
| 9042 | |
| 9043 | if (custom_elements) { |
| 9044 | each(split(custom_elements, ','), function(rule) { |
| 9045 | var matches = customElementRegExp.exec(rule), |
| 9046 | inline = matches[1] === '~', |
| 9047 | cloneName = inline ? 'span' : 'div', |
| 9048 | name = matches[2]; |
| 9049 | |
| 9050 | children[name] = children[cloneName]; |
| 9051 | customElementsMap[name] = cloneName; |
| 9052 | |
| 9053 | // If it's not marked as inline then add it to valid block elements |
| 9054 | if (!inline) { |
| 9055 | blockElementsMap[name.toUpperCase()] = {}; |
| 9056 | blockElementsMap[name] = {}; |
| 9057 | } |
| 9058 | |
| 9059 | // Add elements clone if needed |
| 9060 | if (!elements[name]) { |
| 9061 | var customRule = elements[cloneName]; |
| 9062 | |
| 9063 | customRule = extend({}, customRule); |
| 9064 | delete customRule.removeEmptyAttrs; |
| 9065 | delete customRule.removeEmpty; |
| 9066 | |
| 9067 | elements[name] = customRule; |
| 9068 | } |
| 9069 | |
| 9070 | // Add custom elements at span/div positions |
| 9071 | each(children, function(element) { |
| 9072 | if (element[cloneName]) { |
| 9073 | element[name] = element[cloneName]; |
| 9074 | } |
| 9075 | }); |
| 9076 | }); |
| 9077 | } |
| 9078 | } |
| 9079 | |
| 9080 | // Adds valid children to the schema object |
| 9081 | function addValidChildren(valid_children) { |
| 9082 | var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/; |
| 9083 | |
| 9084 | if (valid_children) { |
| 9085 | each(split(valid_children, ','), function(rule) { |
| 9086 | var matches = childRuleRegExp.exec(rule), parent, prefix; |
| 9087 | |
| 9088 | if (matches) { |
| 9089 | prefix = matches[1]; |
| 9090 | |
| 9091 | // Add/remove items from default |
| 9092 | if (prefix) { |
| 9093 | parent = children[matches[2]]; |
| 9094 | } else { |
| 9095 | parent = children[matches[2]] = {'#comment': {}}; |
| 9096 | } |
| 9097 | |
| 9098 | parent = children[matches[2]]; |
| 9099 | |
| 9100 | each(split(matches[3], '|'), function(child) { |
| 9101 | if (prefix === '-') { |
| 9102 | delete parent[child]; |
| 9103 | } else { |
| 9104 | parent[child] = {}; |
| 9105 | } |
| 9106 | }); |
| 9107 | } |
| 9108 | }); |
| 9109 | } |
| 9110 | } |
| 9111 | |
| 9112 | function getElementRule(name) { |
| 9113 | var element = elements[name], i; |
| 9114 | |
| 9115 | // Exact match found |
| 9116 | if (element) { |
| 9117 | return element; |
| 9118 | } |
| 9119 | |
| 9120 | // No exact match then try the patterns |
| 9121 | i = patternElements.length; |
| 9122 | while (i--) { |
| 9123 | element = patternElements[i]; |
| 9124 | |
| 9125 | if (element.pattern.test(name)) { |
| 9126 | return element; |
| 9127 | } |
| 9128 | } |
| 9129 | } |
| 9130 | |
| 9131 | if (!settings.valid_elements) { |
| 9132 | // No valid elements defined then clone the elements from the schema spec |
| 9133 | each(schemaItems, function(element, name) { |
| 9134 | elements[name] = { |
| 9135 | attributes: element.attributes, |
| 9136 | attributesOrder: element.attributesOrder |
| 9137 | }; |
| 9138 | |
| 9139 | children[name] = element.children; |
| 9140 | }); |
| 9141 | |
| 9142 | // Switch these on HTML4 |
| 9143 | if (settings.schema != "html5") { |
| 9144 | each(split('strong/b em/i'), function(item) { |
| 9145 | item = split(item, '/'); |
| 9146 | elements[item[1]].outputName = item[0]; |
| 9147 | }); |
| 9148 | } |
| 9149 | |
| 9150 | // Add default alt attribute for images |
| 9151 | elements.img.attributesDefault = [{name: 'alt', value: ''}]; |
| 9152 | |
| 9153 | // Remove these if they are empty by default |
| 9154 | each(split('ol ul sub sup blockquote span font a table tbody tr strong em b i'), function(name) { |
| 9155 | if (elements[name]) { |
| 9156 | elements[name].removeEmpty = true; |
| 9157 | } |
| 9158 | }); |
| 9159 | |
| 9160 | // Padd these by default |
| 9161 | each(split('p h1 h2 h3 h4 h5 h6 th td pre div address caption'), function(name) { |
| 9162 | elements[name].paddEmpty = true; |
| 9163 | }); |
| 9164 | |
| 9165 | // Remove these if they have no attributes |
| 9166 | each(split('span'), function(name) { |
| 9167 | elements[name].removeEmptyAttrs = true; |
| 9168 | }); |
| 9169 | |
| 9170 | // Remove these by default |
| 9171 | // TODO: Reenable in 4.1 |
| 9172 | /*each(split('script style'), function(name) { |
| 9173 | delete elements[name]; |
| 9174 | });*/ |
| 9175 | } else { |
| 9176 | setValidElements(settings.valid_elements); |
| 9177 | } |
| 9178 | |
| 9179 | addCustomElements(settings.custom_elements); |
| 9180 | addValidChildren(settings.valid_children); |
| 9181 | addValidElements(settings.extended_valid_elements); |
| 9182 | |
| 9183 | // Todo: Remove this when we fix list handling to be valid |
| 9184 | addValidChildren('+ol[ul|ol],+ul[ul|ol]'); |
| 9185 | |
| 9186 | // Delete invalid elements |
| 9187 | if (settings.invalid_elements) { |
| 9188 | each(explode(settings.invalid_elements), function(item) { |
| 9189 | if (elements[item]) { |
| 9190 | delete elements[item]; |
| 9191 | } |
| 9192 | }); |
| 9193 | } |
| 9194 | |
| 9195 | // If the user didn't allow span only allow internal spans |
| 9196 | if (!getElementRule('span')) { |
| 9197 | addValidElements('span[!data-mce-type|*]'); |
| 9198 | } |
| 9199 | |
| 9200 | /** |
| 9201 | * Name/value map object with valid parents and children to those parents. |
| 9202 | * |
| 9203 | * @example |
| 9204 | * children = { |
| 9205 | * div:{p:{}, h1:{}} |
| 9206 | * }; |
| 9207 | * @field children |
| 9208 | * @type Object |
| 9209 | */ |
| 9210 | self.children = children; |
| 9211 | |
| 9212 | /** |
| 9213 | * Name/value map object with valid styles for each element. |
| 9214 | * |
| 9215 | * @field styles |
| 9216 | * @type Object |
| 9217 | */ |
| 9218 | self.styles = validStyles; |
| 9219 | |
| 9220 | /** |
| 9221 | * Returns a map with boolean attributes. |
| 9222 | * |
| 9223 | * @method getBoolAttrs |
| 9224 | * @return {Object} Name/value lookup map for boolean attributes. |
| 9225 | */ |
| 9226 | self.getBoolAttrs = function() { |
| 9227 | return boolAttrMap; |
| 9228 | }; |
| 9229 | |
| 9230 | /** |
| 9231 | * Returns a map with block elements. |
| 9232 | * |
| 9233 | * @method getBlockElements |
| 9234 | * @return {Object} Name/value lookup map for block elements. |
| 9235 | */ |
| 9236 | self.getBlockElements = function() { |
| 9237 | return blockElementsMap; |
| 9238 | }; |
| 9239 | |
| 9240 | /** |
| 9241 | * Returns a map with text block elements. Such as: p,h1-h6,div,address |
| 9242 | * |
| 9243 | * @method getTextBlockElements |
| 9244 | * @return {Object} Name/value lookup map for block elements. |
| 9245 | */ |
| 9246 | self.getTextBlockElements = function() { |
| 9247 | return textBlockElementsMap; |
| 9248 | }; |
| 9249 | |
| 9250 | /** |
| 9251 | * Returns a map with short ended elements such as BR or IMG. |
| 9252 | * |
| 9253 | * @method getShortEndedElements |
| 9254 | * @return {Object} Name/value lookup map for short ended elements. |
| 9255 | */ |
| 9256 | self.getShortEndedElements = function() { |
| 9257 | return shortEndedElementsMap; |
| 9258 | }; |
| 9259 | |
| 9260 | /** |
| 9261 | * Returns a map with self closing tags such as <li>. |
| 9262 | * |
| 9263 | * @method getSelfClosingElements |
| 9264 | * @return {Object} Name/value lookup map for self closing tags elements. |
| 9265 | */ |
| 9266 | self.getSelfClosingElements = function() { |
| 9267 | return selfClosingElementsMap; |
| 9268 | }; |
| 9269 | |
| 9270 | /** |
| 9271 | * Returns a map with elements that should be treated as contents regardless if it has text |
| 9272 | * content in them or not such as TD, VIDEO or IMG. |
| 9273 | * |
| 9274 | * @method getNonEmptyElements |
| 9275 | * @return {Object} Name/value lookup map for non empty elements. |
| 9276 | */ |
| 9277 | self.getNonEmptyElements = function() { |
| 9278 | return nonEmptyElementsMap; |
| 9279 | }; |
| 9280 | |
| 9281 | /** |
| 9282 | * Returns a map with elements where white space is to be preserved like PRE or SCRIPT. |
| 9283 | * |
| 9284 | * @method getWhiteSpaceElements |
| 9285 | * @return {Object} Name/value lookup map for white space elements. |
| 9286 | */ |
| 9287 | self.getWhiteSpaceElements = function() { |
| 9288 | return whiteSpaceElementsMap; |
| 9289 | }; |
| 9290 | |
| 9291 | /** |
| 9292 | * Returns a map with special elements. These are elements that needs to be parsed |
| 9293 | * in a special way such as script, style, textarea etc. The map object values |
| 9294 | * are regexps used to find the end of the element. |
| 9295 | * |
| 9296 | * @method getSpecialElements |
| 9297 | * @return {Object} Name/value lookup map for special elements. |
| 9298 | */ |
| 9299 | self.getSpecialElements = function() { |
| 9300 | return specialElements; |
| 9301 | }; |
| 9302 | |
| 9303 | /** |
| 9304 | * Returns true/false if the specified element and it's child is valid or not |
| 9305 | * according to the schema. |
| 9306 | * |
| 9307 | * @method isValidChild |
| 9308 | * @param {String} name Element name to check for. |
| 9309 | * @param {String} child Element child to verify. |
| 9310 | * @return {Boolean} True/false if the element is a valid child of the specified parent. |
| 9311 | */ |
| 9312 | self.isValidChild = function(name, child) { |
| 9313 | var parent = children[name]; |
| 9314 | |
| 9315 | return !!(parent && parent[child]); |
| 9316 | }; |
| 9317 | |
| 9318 | /** |
| 9319 | * Returns true/false if the specified element name and optional attribute is |
| 9320 | * valid according to the schema. |
| 9321 | * |
| 9322 | * @method isValid |
| 9323 | * @param {String} name Name of element to check. |
| 9324 | * @param {String} attr Optional attribute name to check for. |
| 9325 | * @return {Boolean} True/false if the element and attribute is valid. |
| 9326 | */ |
| 9327 | self.isValid = function(name, attr) { |
| 9328 | var attrPatterns, i, rule = getElementRule(name); |
| 9329 | |
| 9330 | // Check if it's a valid element |
| 9331 | if (rule) { |
| 9332 | if (attr) { |
| 9333 | // Check if attribute name exists |
| 9334 | if (rule.attributes[attr]) { |
| 9335 | return true; |
| 9336 | } |
| 9337 | |
| 9338 | // Check if attribute matches a regexp pattern |
| 9339 | attrPatterns = rule.attributePatterns; |
| 9340 | if (attrPatterns) { |
| 9341 | i = attrPatterns.length; |
| 9342 | while (i--) { |
| 9343 | if (attrPatterns[i].pattern.test(name)) { |
| 9344 | return true; |
| 9345 | } |
| 9346 | } |
| 9347 | } |
| 9348 | } else { |
| 9349 | return true; |
| 9350 | } |
| 9351 | } |
| 9352 | |
| 9353 | // No match |
| 9354 | return false; |
| 9355 | }; |
| 9356 | |
| 9357 | /** |
| 9358 | * Returns true/false if the specified element is valid or not |
| 9359 | * according to the schema. |
| 9360 | * |
| 9361 | * @method getElementRule |
| 9362 | * @param {String} name Element name to check for. |
| 9363 | * @return {Object} Element object or undefined if the element isn't valid. |
| 9364 | */ |
| 9365 | self.getElementRule = getElementRule; |
| 9366 | |
| 9367 | /** |
| 9368 | * Returns an map object of all custom elements. |
| 9369 | * |
| 9370 | * @method getCustomElements |
| 9371 | * @return {Object} Name/value map object of all custom elements. |
| 9372 | */ |
| 9373 | self.getCustomElements = function() { |
| 9374 | return customElementsMap; |
| 9375 | }; |
| 9376 | |
| 9377 | /** |
| 9378 | * Parses a valid elements string and adds it to the schema. The valid elements |
| 9379 | format is for example "element[attr=default|otherattr]". |
| 9380 | * Existing rules will be replaced with the ones specified, so this extends the schema. |
| 9381 | * |
| 9382 | * @method addValidElements |
| 9383 | * @param {String} valid_elements String in the valid elements format to be parsed. |
| 9384 | */ |
| 9385 | self.addValidElements = addValidElements; |
| 9386 | |
| 9387 | /** |
| 9388 | * Parses a valid elements string and sets it to the schema. The valid elements |
| 9389 | * format is for example "element[attr=default|otherattr]". |
| 9390 | * Existing rules will be replaced with the ones specified, so this extends the schema. |
| 9391 | * |
| 9392 | * @method setValidElements |
| 9393 | * @param {String} valid_elements String in the valid elements format to be parsed. |
| 9394 | */ |
| 9395 | self.setValidElements = setValidElements; |
| 9396 | |
| 9397 | /** |
| 9398 | * Adds custom non HTML elements to the schema. |
| 9399 | * |
| 9400 | * @method addCustomElements |
| 9401 | * @param {String} custom_elements Comma separated list of custom elements to add. |
| 9402 | */ |
| 9403 | self.addCustomElements = addCustomElements; |
| 9404 | |
| 9405 | /** |
| 9406 | * Parses a valid children string and adds them to the schema structure. The valid children |
| 9407 | * format is for example: "element[child1|child2]". |
| 9408 | * |
| 9409 | * @method addValidChildren |
| 9410 | * @param {String} valid_children Valid children elements string to parse |
| 9411 | */ |
| 9412 | self.addValidChildren = addValidChildren; |
| 9413 | |
| 9414 | self.elements = elements; |
| 9415 | }; |
| 9416 | }); |
| 9417 | |
| 9418 | // Included from: js/tinymce/classes/html/SaxParser.js |
| 9419 | |
| 9420 | /** |
| 9421 | * SaxParser.js |
| 9422 | * |
| 9423 | * Copyright, Moxiecode Systems AB |
| 9424 | * Released under LGPL License. |
| 9425 | * |
| 9426 | * License: http://www.tinymce.com/license |
| 9427 | * Contributing: http://www.tinymce.com/contributing |
| 9428 | */ |
| 9429 | |
| 9430 | /** |
| 9431 | * This class parses HTML code using pure JavaScript and executes various events for each item it finds. It will |
| 9432 | * always execute the events in the right order for tag soup code like <b><p></b></p>. It will also remove elements |
| 9433 | * and attributes that doesn't fit the schema if the validate setting is enabled. |
| 9434 | * |
| 9435 | * @example |
| 9436 | * var parser = new tinymce.html.SaxParser({ |
| 9437 | * validate: true, |
| 9438 | * |
| 9439 | * comment: function(text) { |
| 9440 | * console.log('Comment:', text); |
| 9441 | * }, |
| 9442 | * |
| 9443 | * cdata: function(text) { |
| 9444 | * console.log('CDATA:', text); |
| 9445 | * }, |
| 9446 | * |
| 9447 | * text: function(text, raw) { |
| 9448 | * console.log('Text:', text, 'Raw:', raw); |
| 9449 | * }, |
| 9450 | * |
| 9451 | * start: function(name, attrs, empty) { |
| 9452 | * console.log('Start:', name, attrs, empty); |
| 9453 | * }, |
| 9454 | * |
| 9455 | * end: function(name) { |
| 9456 | * console.log('End:', name); |
| 9457 | * }, |
| 9458 | * |
| 9459 | * pi: function(name, text) { |
| 9460 | * console.log('PI:', name, text); |
| 9461 | * }, |
| 9462 | * |
| 9463 | * doctype: function(text) { |
| 9464 | * console.log('DocType:', text); |
| 9465 | * } |
| 9466 | * }, schema); |
| 9467 | * @class tinymce.html.SaxParser |
| 9468 | * @version 3.4 |
| 9469 | */ |
| 9470 | define("tinymce/html/SaxParser", [ |
| 9471 | "tinymce/html/Schema", |
| 9472 | "tinymce/html/Entities", |
| 9473 | "tinymce/util/Tools" |
| 9474 | ], function(Schema, Entities, Tools) { |
| 9475 | var each = Tools.each; |
| 9476 | |
| 9477 | /** |
| 9478 | * Constructs a new SaxParser instance. |
| 9479 | * |
| 9480 | * @constructor |
| 9481 | * @method SaxParser |
| 9482 | * @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks. |
| 9483 | * @param {tinymce.html.Schema} schema HTML Schema class to use when parsing. |
| 9484 | */ |
| 9485 | return function(settings, schema) { |
| 9486 | var self = this, noop = function() {}; |
| 9487 | |
| 9488 | settings = settings || {}; |
| 9489 | self.schema = schema = schema || new Schema(); |
| 9490 | |
| 9491 | if (settings.fix_self_closing !== false) { |
| 9492 | settings.fix_self_closing = true; |
| 9493 | } |
| 9494 | |
| 9495 | // Add handler functions from settings and setup default handlers |
| 9496 | each('comment cdata text start end pi doctype'.split(' '), function(name) { |
| 9497 | if (name) { |
| 9498 | self[name] = settings[name] || noop; |
| 9499 | } |
| 9500 | }); |
| 9501 | |
| 9502 | /** |
| 9503 | * Parses the specified HTML string and executes the callbacks for each item it finds. |
| 9504 | * |
| 9505 | * @example |
| 9506 | * new SaxParser({...}).parse('<b>text</b>'); |
| 9507 | * @method parse |
| 9508 | * @param {String} html Html string to sax parse. |
| 9509 | */ |
| 9510 | self.parse = function(html) { |
| 9511 | var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name; |
| 9512 | var isInternalElement, removeInternalElements, shortEndedElements, fillAttrsMap, isShortEnded; |
| 9513 | var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns; |
| 9514 | var attributesRequired, attributesDefault, attributesForced; |
| 9515 | var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0; |
| 9516 | var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href'); |
| 9517 | var scriptUriRegExp = /(java|vb)script:/i; |
| 9518 | |
| 9519 | function processEndTag(name) { |
| 9520 | var pos, i; |
| 9521 | |
| 9522 | // Find position of parent of the same type |
| 9523 | pos = stack.length; |
| 9524 | while (pos--) { |
| 9525 | if (stack[pos].name === name) { |
| 9526 | break; |
| 9527 | } |
| 9528 | } |
| 9529 | |
| 9530 | // Found parent |
| 9531 | if (pos >= 0) { |
| 9532 | // Close all the open elements |
| 9533 | for (i = stack.length - 1; i >= pos; i--) { |
| 9534 | name = stack[i]; |
| 9535 | |
| 9536 | if (name.valid) { |
| 9537 | self.end(name.name); |
| 9538 | } |
| 9539 | } |
| 9540 | |
| 9541 | // Remove the open elements from the stack |
| 9542 | stack.length = pos; |
| 9543 | } |
| 9544 | } |
| 9545 | |
| 9546 | function parseAttribute(match, name, value, val2, val3) { |
| 9547 | var attrRule, i, trimRegExp = /[\s\u0000-\u001F]+/g; |
| 9548 | |
| 9549 | name = name.toLowerCase(); |
| 9550 | value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute |
| 9551 | |
| 9552 | // Validate name and value pass through all data- attributes |
| 9553 | if (validate && !isInternalElement && name.indexOf('data-') !== 0) { |
| 9554 | attrRule = validAttributesMap[name]; |
| 9555 | |
| 9556 | // Find rule by pattern matching |
| 9557 | if (!attrRule && validAttributePatterns) { |
| 9558 | i = validAttributePatterns.length; |
| 9559 | while (i--) { |
| 9560 | attrRule = validAttributePatterns[i]; |
| 9561 | if (attrRule.pattern.test(name)) { |
| 9562 | break; |
| 9563 | } |
| 9564 | } |
| 9565 | |
| 9566 | // No rule matched |
| 9567 | if (i === -1) { |
| 9568 | attrRule = null; |
| 9569 | } |
| 9570 | } |
| 9571 | |
| 9572 | // No attribute rule found |
| 9573 | if (!attrRule) { |
| 9574 | return; |
| 9575 | } |
| 9576 | |
| 9577 | // Validate value |
| 9578 | if (attrRule.validValues && !(value in attrRule.validValues)) { |
| 9579 | return; |
| 9580 | } |
| 9581 | } |
| 9582 | |
| 9583 | // Block any javascript: urls |
| 9584 | if (filteredUrlAttrs[name] && !settings.allow_script_urls) { |
| 9585 | var uri = value.replace(trimRegExp, ''); |
| 9586 | |
| 9587 | try { |
| 9588 | // Might throw malformed URI sequence |
| 9589 | uri = decodeURIComponent(uri); |
| 9590 | if (scriptUriRegExp.test(uri)) { |
| 9591 | return; |
| 9592 | } |
| 9593 | } catch (ex) { |
| 9594 | // Fallback to non UTF-8 decoder |
| 9595 | uri = unescape(uri); |
| 9596 | if (scriptUriRegExp.test(uri)) { |
| 9597 | return; |
| 9598 | } |
| 9599 | } |
| 9600 | } |
| 9601 | |
| 9602 | // Add attribute to list and map |
| 9603 | attrList.map[name] = value; |
| 9604 | attrList.push({ |
| 9605 | name: name, |
| 9606 | value: value |
| 9607 | }); |
| 9608 | } |
| 9609 | |
| 9610 | // Precompile RegExps and map objects |
| 9611 | tokenRegExp = new RegExp('<(?:' + |
| 9612 | '(?:!--([\\w\\W]*?)-->)|' + // Comment |
| 9613 | '(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|' + // CDATA |
| 9614 | '(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE |
| 9615 | '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI |
| 9616 | '(?:\\/([^>]+)>)|' + // End element |
| 9617 | '(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element |
| 9618 | ')', 'g'); |
| 9619 | |
| 9620 | attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g; |
| 9621 | |
| 9622 | // Setup lookup tables for empty elements and boolean attributes |
| 9623 | shortEndedElements = schema.getShortEndedElements(); |
| 9624 | selfClosing = settings.self_closing_elements || schema.getSelfClosingElements(); |
| 9625 | fillAttrsMap = schema.getBoolAttrs(); |
| 9626 | validate = settings.validate; |
| 9627 | removeInternalElements = settings.remove_internals; |
| 9628 | fixSelfClosing = settings.fix_self_closing; |
| 9629 | specialElements = schema.getSpecialElements(); |
| 9630 | |
| 9631 | while ((matches = tokenRegExp.exec(html))) { |
| 9632 | // Text |
| 9633 | if (index < matches.index) { |
| 9634 | self.text(decode(html.substr(index, matches.index - index))); |
| 9635 | } |
| 9636 | |
| 9637 | if ((value = matches[6])) { // End element |
| 9638 | value = value.toLowerCase(); |
| 9639 | |
| 9640 | // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements |
| 9641 | if (value.charAt(0) === ':') { |
| 9642 | value = value.substr(1); |
| 9643 | } |
| 9644 | |
| 9645 | processEndTag(value); |
| 9646 | } else if ((value = matches[7])) { // Start element |
| 9647 | value = value.toLowerCase(); |
| 9648 | |
| 9649 | // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements |
| 9650 | if (value.charAt(0) === ':') { |
| 9651 | value = value.substr(1); |
| 9652 | } |
| 9653 | |
| 9654 | isShortEnded = value in shortEndedElements; |
| 9655 | |
| 9656 | // Is self closing tag for example an <li> after an open <li> |
| 9657 | if (fixSelfClosing && selfClosing[value] && stack.length > 0 && stack[stack.length - 1].name === value) { |
| 9658 | processEndTag(value); |
| 9659 | } |
| 9660 | |
| 9661 | // Validate element |
| 9662 | if (!validate || (elementRule = schema.getElementRule(value))) { |
| 9663 | isValidElement = true; |
| 9664 | |
| 9665 | // Grab attributes map and patters when validation is enabled |
| 9666 | if (validate) { |
| 9667 | validAttributesMap = elementRule.attributes; |
| 9668 | validAttributePatterns = elementRule.attributePatterns; |
| 9669 | } |
| 9670 | |
| 9671 | // Parse attributes |
| 9672 | if ((attribsValue = matches[8])) { |
| 9673 | isInternalElement = attribsValue.indexOf('data-mce-type') !== -1; // Check if the element is an internal element |
| 9674 | |
| 9675 | // If the element has internal attributes then remove it if we are told to do so |
| 9676 | if (isInternalElement && removeInternalElements) { |
| 9677 | isValidElement = false; |
| 9678 | } |
| 9679 | |
| 9680 | attrList = []; |
| 9681 | attrList.map = {}; |
| 9682 | |
| 9683 | attribsValue.replace(attrRegExp, parseAttribute); |
| 9684 | } else { |
| 9685 | attrList = []; |
| 9686 | attrList.map = {}; |
| 9687 | } |
| 9688 | |
| 9689 | // Process attributes if validation is enabled |
| 9690 | if (validate && !isInternalElement) { |
| 9691 | attributesRequired = elementRule.attributesRequired; |
| 9692 | attributesDefault = elementRule.attributesDefault; |
| 9693 | attributesForced = elementRule.attributesForced; |
| 9694 | anyAttributesRequired = elementRule.removeEmptyAttrs; |
| 9695 | |
| 9696 | // Check if any attribute exists |
| 9697 | if (anyAttributesRequired && !attrList.length) { |
| 9698 | isValidElement = false; |
| 9699 | } |
| 9700 | |
| 9701 | // Handle forced attributes |
| 9702 | if (attributesForced) { |
| 9703 | i = attributesForced.length; |
| 9704 | while (i--) { |
| 9705 | attr = attributesForced[i]; |
| 9706 | name = attr.name; |
| 9707 | attrValue = attr.value; |
| 9708 | |
| 9709 | if (attrValue === '{$uid}') { |
| 9710 | attrValue = 'mce_' + idCount++; |
| 9711 | } |
| 9712 | |
| 9713 | attrList.map[name] = attrValue; |
| 9714 | attrList.push({name: name, value: attrValue}); |
| 9715 | } |
| 9716 | } |
| 9717 | |
| 9718 | // Handle default attributes |
| 9719 | if (attributesDefault) { |
| 9720 | i = attributesDefault.length; |
| 9721 | while (i--) { |
| 9722 | attr = attributesDefault[i]; |
| 9723 | name = attr.name; |
| 9724 | |
| 9725 | if (!(name in attrList.map)) { |
| 9726 | attrValue = attr.value; |
| 9727 | |
| 9728 | if (attrValue === '{$uid}') { |
| 9729 | attrValue = 'mce_' + idCount++; |
| 9730 | } |
| 9731 | |
| 9732 | attrList.map[name] = attrValue; |
| 9733 | attrList.push({name: name, value: attrValue}); |
| 9734 | } |
| 9735 | } |
| 9736 | } |
| 9737 | |
| 9738 | // Handle required attributes |
| 9739 | if (attributesRequired) { |
| 9740 | i = attributesRequired.length; |
| 9741 | while (i--) { |
| 9742 | if (attributesRequired[i] in attrList.map) { |
| 9743 | break; |
| 9744 | } |
| 9745 | } |
| 9746 | |
| 9747 | // None of the required attributes where found |
| 9748 | if (i === -1) { |
| 9749 | isValidElement = false; |
| 9750 | } |
| 9751 | } |
| 9752 | |
| 9753 | // Invalidate element if it's marked as bogus |
| 9754 | if (attrList.map['data-mce-bogus']) { |
| 9755 | isValidElement = false; |
| 9756 | } |
| 9757 | } |
| 9758 | |
| 9759 | if (isValidElement) { |
| 9760 | self.start(value, attrList, isShortEnded); |
| 9761 | } |
| 9762 | } else { |
| 9763 | isValidElement = false; |
| 9764 | } |
| 9765 | |
| 9766 | // Treat script, noscript and style a bit different since they may include code that looks like elements |
| 9767 | if ((endRegExp = specialElements[value])) { |
| 9768 | endRegExp.lastIndex = index = matches.index + matches[0].length; |
| 9769 | |
| 9770 | if ((matches = endRegExp.exec(html))) { |
| 9771 | if (isValidElement) { |
| 9772 | text = html.substr(index, matches.index - index); |
| 9773 | } |
| 9774 | |
| 9775 | index = matches.index + matches[0].length; |
| 9776 | } else { |
| 9777 | text = html.substr(index); |
| 9778 | index = html.length; |
| 9779 | } |
| 9780 | |
| 9781 | if (isValidElement) { |
| 9782 | if (text.length > 0) { |
| 9783 | self.text(text, true); |
| 9784 | } |
| 9785 | |
| 9786 | self.end(value); |
| 9787 | } |
| 9788 | |
| 9789 | tokenRegExp.lastIndex = index; |
| 9790 | continue; |
| 9791 | } |
| 9792 | |
| 9793 | // Push value on to stack |
| 9794 | if (!isShortEnded) { |
| 9795 | if (!attribsValue || attribsValue.indexOf('/') != attribsValue.length - 1) { |
| 9796 | stack.push({name: value, valid: isValidElement}); |
| 9797 | } else if (isValidElement) { |
| 9798 | self.end(value); |
| 9799 | } |
| 9800 | } |
| 9801 | } else if ((value = matches[1])) { // Comment |
| 9802 | // Padd comment value to avoid browsers from parsing invalid comments as HTML |
| 9803 | if (value.charAt(0) === '>') { |
| 9804 | value = ' ' + value; |
| 9805 | } |
| 9806 | |
| 9807 | if (!settings.allow_conditional_comments && value.substr(0, 3) === '[if') { |
| 9808 | value = ' ' + value; |
| 9809 | } |
| 9810 | |
| 9811 | self.comment(value); |
| 9812 | } else if ((value = matches[2])) { // CDATA |
| 9813 | self.cdata(value); |
| 9814 | } else if ((value = matches[3])) { // DOCTYPE |
| 9815 | self.doctype(value); |
| 9816 | } else if ((value = matches[4])) { // PI |
| 9817 | self.pi(value, matches[5]); |
| 9818 | } |
| 9819 | |
| 9820 | index = matches.index + matches[0].length; |
| 9821 | } |
| 9822 | |
| 9823 | // Text |
| 9824 | if (index < html.length) { |
| 9825 | self.text(decode(html.substr(index))); |
| 9826 | } |
| 9827 | |
| 9828 | // Close any open elements |
| 9829 | for (i = stack.length - 1; i >= 0; i--) { |
| 9830 | value = stack[i]; |
| 9831 | |
| 9832 | if (value.valid) { |
| 9833 | self.end(value.name); |
| 9834 | } |
| 9835 | } |
| 9836 | }; |
| 9837 | }; |
| 9838 | }); |
| 9839 | |
| 9840 | // Included from: js/tinymce/classes/html/DomParser.js |
| 9841 | |
| 9842 | /** |
| 9843 | * DomParser.js |
| 9844 | * |
| 9845 | * Copyright, Moxiecode Systems AB |
| 9846 | * Released under LGPL License. |
| 9847 | * |
| 9848 | * License: http://www.tinymce.com/license |
| 9849 | * Contributing: http://www.tinymce.com/contributing |
| 9850 | */ |
| 9851 | |
| 9852 | /** |
| 9853 | * This class parses HTML code into a DOM like structure of nodes it will remove redundant whitespace and make |
| 9854 | * sure that the node tree is valid according to the specified schema. |
| 9855 | * So for example: <p>a<p>b</p>c</p> will become <p>a</p><p>b</p><p>c</p> |
| 9856 | * |
| 9857 | * @example |
| 9858 | * var parser = new tinymce.html.DomParser({validate: true}, schema); |
| 9859 | * var rootNode = parser.parse('<h1>content</h1>'); |
| 9860 | * |
| 9861 | * @class tinymce.html.DomParser |
| 9862 | * @version 3.4 |
| 9863 | */ |
| 9864 | define("tinymce/html/DomParser", [ |
| 9865 | "tinymce/html/Node", |
| 9866 | "tinymce/html/Schema", |
| 9867 | "tinymce/html/SaxParser", |
| 9868 | "tinymce/util/Tools" |
| 9869 | ], function(Node, Schema, SaxParser, Tools) { |
| 9870 | var makeMap = Tools.makeMap, each = Tools.each, explode = Tools.explode, extend = Tools.extend; |
| 9871 | |
| 9872 | /** |
| 9873 | * Constructs a new DomParser instance. |
| 9874 | * |
| 9875 | * @constructor |
| 9876 | * @method DomParser |
| 9877 | * @param {Object} settings Name/value collection of settings. comment, cdata, text, start and end are callbacks. |
| 9878 | * @param {tinymce.html.Schema} schema HTML Schema class to use when parsing. |
| 9879 | */ |
| 9880 | return function(settings, schema) { |
| 9881 | var self = this, nodeFilters = {}, attributeFilters = [], matchedNodes = {}, matchedAttributes = {}; |
| 9882 | |
| 9883 | settings = settings || {}; |
| 9884 | settings.validate = "validate" in settings ? settings.validate : true; |
| 9885 | settings.root_name = settings.root_name || 'body'; |
| 9886 | self.schema = schema = schema || new Schema(); |
| 9887 | |
| 9888 | function fixInvalidChildren(nodes) { |
| 9889 | var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i; |
| 9890 | var nonEmptyElements, nonSplitableElements, textBlockElements, sibling, nextNode; |
| 9891 | |
| 9892 | nonSplitableElements = makeMap('tr,td,th,tbody,thead,tfoot,table'); |
| 9893 | nonEmptyElements = schema.getNonEmptyElements(); |
| 9894 | textBlockElements = schema.getTextBlockElements(); |
| 9895 | |
| 9896 | for (ni = 0; ni < nodes.length; ni++) { |
| 9897 | node = nodes[ni]; |
| 9898 | |
| 9899 | // Already removed or fixed |
| 9900 | if (!node.parent || node.fixed) { |
| 9901 | continue; |
| 9902 | } |
| 9903 | |
| 9904 | // If the invalid element is a text block and the text block is within a parent LI element |
| 9905 | // Then unwrap the first text block and convert other sibling text blocks to LI elements similar to Word/Open Office |
| 9906 | if (textBlockElements[node.name] && node.parent.name == 'li') { |
| 9907 | // Move sibling text blocks after LI element |
| 9908 | sibling = node.next; |
| 9909 | while (sibling) { |
| 9910 | if (textBlockElements[sibling.name]) { |
| 9911 | sibling.name = 'li'; |
| 9912 | sibling.fixed = true; |
| 9913 | node.parent.insert(sibling, node.parent); |
| 9914 | } else { |
| 9915 | break; |
| 9916 | } |
| 9917 | |
| 9918 | sibling = sibling.next; |
| 9919 | } |
| 9920 | |
| 9921 | // Unwrap current text block |
| 9922 | node.unwrap(node); |
| 9923 | continue; |
| 9924 | } |
| 9925 | |
| 9926 | // Get list of all parent nodes until we find a valid parent to stick the child into |
| 9927 | parents = [node]; |
| 9928 | for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && |
| 9929 | !nonSplitableElements[parent.name]; parent = parent.parent) { |
| 9930 | parents.push(parent); |
| 9931 | } |
| 9932 | |
| 9933 | // Found a suitable parent |
| 9934 | if (parent && parents.length > 1) { |
| 9935 | // Reverse the array since it makes looping easier |
| 9936 | parents.reverse(); |
| 9937 | |
| 9938 | // Clone the related parent and insert that after the moved node |
| 9939 | newParent = currentNode = self.filterNode(parents[0].clone()); |
| 9940 | |
| 9941 | // Start cloning and moving children on the left side of the target node |
| 9942 | for (i = 0; i < parents.length - 1; i++) { |
| 9943 | if (schema.isValidChild(currentNode.name, parents[i].name)) { |
| 9944 | tempNode = self.filterNode(parents[i].clone()); |
| 9945 | currentNode.append(tempNode); |
| 9946 | } else { |
| 9947 | tempNode = currentNode; |
| 9948 | } |
| 9949 | |
| 9950 | for (childNode = parents[i].firstChild; childNode && childNode != parents[i + 1]; ) { |
| 9951 | nextNode = childNode.next; |
| 9952 | tempNode.append(childNode); |
| 9953 | childNode = nextNode; |
| 9954 | } |
| 9955 | |
| 9956 | currentNode = tempNode; |
| 9957 | } |
| 9958 | |
| 9959 | if (!newParent.isEmpty(nonEmptyElements)) { |
| 9960 | parent.insert(newParent, parents[0], true); |
| 9961 | parent.insert(node, newParent); |
| 9962 | } else { |
| 9963 | parent.insert(node, parents[0], true); |
| 9964 | } |
| 9965 | |
| 9966 | // Check if the element is empty by looking through it's contents and special treatment for <p><br /></p> |
| 9967 | parent = parents[0]; |
| 9968 | if (parent.isEmpty(nonEmptyElements) || parent.firstChild === parent.lastChild && parent.firstChild.name === 'br') { |
| 9969 | parent.empty().remove(); |
| 9970 | } |
| 9971 | } else if (node.parent) { |
| 9972 | // If it's an LI try to find a UL/OL for it or wrap it |
| 9973 | if (node.name === 'li') { |
| 9974 | sibling = node.prev; |
| 9975 | if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) { |
| 9976 | sibling.append(node); |
| 9977 | continue; |
| 9978 | } |
| 9979 | |
| 9980 | sibling = node.next; |
| 9981 | if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) { |
| 9982 | sibling.insert(node, sibling.firstChild, true); |
| 9983 | continue; |
| 9984 | } |
| 9985 | |
| 9986 | node.wrap(self.filterNode(new Node('ul', 1))); |
| 9987 | continue; |
| 9988 | } |
| 9989 | |
| 9990 | // Try wrapping the element in a DIV |
| 9991 | if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) { |
| 9992 | node.wrap(self.filterNode(new Node('div', 1))); |
| 9993 | } else { |
| 9994 | // We failed wrapping it, then remove or unwrap it |
| 9995 | if (node.name === 'style' || node.name === 'script') { |
| 9996 | node.empty().remove(); |
| 9997 | } else { |
| 9998 | node.unwrap(); |
| 9999 | } |
| 10000 | } |
| 10001 | } |
| 10002 | } |
| 10003 | } |
| 10004 | |
| 10005 | /** |
| 10006 | * Runs the specified node though the element and attributes filters. |
| 10007 | * |
| 10008 | * @method filterNode |
| 10009 | * @param {tinymce.html.Node} Node the node to run filters on. |
| 10010 | * @return {tinymce.html.Node} The passed in node. |
| 10011 | */ |
| 10012 | self.filterNode = function(node) { |
| 10013 | var i, name, list; |
| 10014 | |
| 10015 | // Run element filters |
| 10016 | if (name in nodeFilters) { |
| 10017 | list = matchedNodes[name]; |
| 10018 | |
| 10019 | if (list) { |
| 10020 | list.push(node); |
| 10021 | } else { |
| 10022 | matchedNodes[name] = [node]; |
| 10023 | } |
| 10024 | } |
| 10025 | |
| 10026 | // Run attribute filters |
| 10027 | i = attributeFilters.length; |
| 10028 | while (i--) { |
| 10029 | name = attributeFilters[i].name; |
| 10030 | |
| 10031 | if (name in node.attributes.map) { |
| 10032 | list = matchedAttributes[name]; |
| 10033 | |
| 10034 | if (list) { |
| 10035 | list.push(node); |
| 10036 | } else { |
| 10037 | matchedAttributes[name] = [node]; |
| 10038 | } |
| 10039 | } |
| 10040 | } |
| 10041 | |
| 10042 | return node; |
| 10043 | }; |
| 10044 | |
| 10045 | /** |
| 10046 | * Adds a node filter function to the parser, the parser will collect the specified nodes by name |
| 10047 | * and then execute the callback ones it has finished parsing the document. |
| 10048 | * |
| 10049 | * @example |
| 10050 | * parser.addNodeFilter('p,h1', function(nodes, name) { |
| 10051 | * for (var i = 0; i < nodes.length; i++) { |
| 10052 | * console.log(nodes[i].name); |
| 10053 | * } |
| 10054 | * }); |
| 10055 | * @method addNodeFilter |
| 10056 | * @method {String} name Comma separated list of nodes to collect. |
| 10057 | * @param {function} callback Callback function to execute once it has collected nodes. |
| 10058 | */ |
| 10059 | self.addNodeFilter = function(name, callback) { |
| 10060 | each(explode(name), function(name) { |
| 10061 | var list = nodeFilters[name]; |
| 10062 | |
| 10063 | if (!list) { |
| 10064 | nodeFilters[name] = list = []; |
| 10065 | } |
| 10066 | |
| 10067 | list.push(callback); |
| 10068 | }); |
| 10069 | }; |
| 10070 | |
| 10071 | /** |
| 10072 | * Adds a attribute filter function to the parser, the parser will collect nodes that has the specified attributes |
| 10073 | * and then execute the callback ones it has finished parsing the document. |
| 10074 | * |
| 10075 | * @example |
| 10076 | * parser.addAttributeFilter('src,href', function(nodes, name) { |
| 10077 | * for (var i = 0; i < nodes.length; i++) { |
| 10078 | * console.log(nodes[i].name); |
| 10079 | * } |
| 10080 | * }); |
| 10081 | * @method addAttributeFilter |
| 10082 | * @method {String} name Comma separated list of nodes to collect. |
| 10083 | * @param {function} callback Callback function to execute once it has collected nodes. |
| 10084 | */ |
| 10085 | self.addAttributeFilter = function(name, callback) { |
| 10086 | each(explode(name), function(name) { |
| 10087 | var i; |
| 10088 | |
| 10089 | for (i = 0; i < attributeFilters.length; i++) { |
| 10090 | if (attributeFilters[i].name === name) { |
| 10091 | attributeFilters[i].callbacks.push(callback); |
| 10092 | return; |
| 10093 | } |
| 10094 | } |
| 10095 | |
| 10096 | attributeFilters.push({name: name, callbacks: [callback]}); |
| 10097 | }); |
| 10098 | }; |
| 10099 | |
| 10100 | /** |
| 10101 | * Parses the specified HTML string into a DOM like node tree and returns the result. |
| 10102 | * |
| 10103 | * @example |
| 10104 | * var rootNode = new DomParser({...}).parse('<b>text</b>'); |
| 10105 | * @method parse |
| 10106 | * @param {String} html Html string to sax parse. |
| 10107 | * @param {Object} args Optional args object that gets passed to all filter functions. |
| 10108 | * @return {tinymce.html.Node} Root node containing the tree. |
| 10109 | */ |
| 10110 | self.parse = function(html, args) { |
| 10111 | var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate; |
| 10112 | var blockElements, startWhiteSpaceRegExp, invalidChildren = [], isInWhiteSpacePreservedElement; |
| 10113 | var endWhiteSpaceRegExp, allWhiteSpaceRegExp, isAllWhiteSpaceRegExp, whiteSpaceElements; |
| 10114 | var children, nonEmptyElements, rootBlockName; |
| 10115 | |
| 10116 | args = args || {}; |
| 10117 | matchedNodes = {}; |
| 10118 | matchedAttributes = {}; |
| 10119 | blockElements = extend(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements()); |
| 10120 | nonEmptyElements = schema.getNonEmptyElements(); |
| 10121 | children = schema.children; |
| 10122 | validate = settings.validate; |
| 10123 | rootBlockName = "forced_root_block" in args ? args.forced_root_block : settings.forced_root_block; |
| 10124 | |
| 10125 | whiteSpaceElements = schema.getWhiteSpaceElements(); |
| 10126 | startWhiteSpaceRegExp = /^[ \t\r\n]+/; |
| 10127 | endWhiteSpaceRegExp = /[ \t\r\n]+$/; |
| 10128 | allWhiteSpaceRegExp = /[ \t\r\n]+/g; |
| 10129 | isAllWhiteSpaceRegExp = /^[ \t\r\n]+$/; |
| 10130 | |
| 10131 | function addRootBlocks() { |
| 10132 | var node = rootNode.firstChild, next, rootBlockNode; |
| 10133 | |
| 10134 | // Removes whitespace at beginning and end of block so: |
| 10135 | // <p> x </p> -> <p>x</p> |
| 10136 | function trim(rootBlockNode) { |
| 10137 | if (rootBlockNode) { |
| 10138 | node = rootBlockNode.firstChild; |
| 10139 | if (node && node.type == 3) { |
| 10140 | node.value = node.value.replace(startWhiteSpaceRegExp, ''); |
| 10141 | } |
| 10142 | |
| 10143 | node = rootBlockNode.lastChild; |
| 10144 | if (node && node.type == 3) { |
| 10145 | node.value = node.value.replace(endWhiteSpaceRegExp, ''); |
| 10146 | } |
| 10147 | } |
| 10148 | } |
| 10149 | |
| 10150 | // Check if rootBlock is valid within rootNode for example if P is valid in H1 if H1 is the contentEditabe root |
| 10151 | if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) { |
| 10152 | return; |
| 10153 | } |
| 10154 | |
| 10155 | while (node) { |
| 10156 | next = node.next; |
| 10157 | |
| 10158 | if (node.type == 3 || (node.type == 1 && node.name !== 'p' && |
| 10159 | !blockElements[node.name] && !node.attr('data-mce-type'))) { |
| 10160 | if (!rootBlockNode) { |
| 10161 | // Create a new root block element |
| 10162 | rootBlockNode = createNode(rootBlockName, 1); |
| 10163 | rootBlockNode.attr(settings.forced_root_block_attrs); |
| 10164 | rootNode.insert(rootBlockNode, node); |
| 10165 | rootBlockNode.append(node); |
| 10166 | } else { |
| 10167 | rootBlockNode.append(node); |
| 10168 | } |
| 10169 | } else { |
| 10170 | trim(rootBlockNode); |
| 10171 | rootBlockNode = null; |
| 10172 | } |
| 10173 | |
| 10174 | node = next; |
| 10175 | } |
| 10176 | |
| 10177 | trim(rootBlockNode); |
| 10178 | } |
| 10179 | |
| 10180 | function createNode(name, type) { |
| 10181 | var node = new Node(name, type), list; |
| 10182 | |
| 10183 | if (name in nodeFilters) { |
| 10184 | list = matchedNodes[name]; |
| 10185 | |
| 10186 | if (list) { |
| 10187 | list.push(node); |
| 10188 | } else { |
| 10189 | matchedNodes[name] = [node]; |
| 10190 | } |
| 10191 | } |
| 10192 | |
| 10193 | return node; |
| 10194 | } |
| 10195 | |
| 10196 | function removeWhitespaceBefore(node) { |
| 10197 | var textNode, textVal, sibling; |
| 10198 | |
| 10199 | for (textNode = node.prev; textNode && textNode.type === 3; ) { |
| 10200 | textVal = textNode.value.replace(endWhiteSpaceRegExp, ''); |
| 10201 | |
| 10202 | if (textVal.length > 0) { |
| 10203 | textNode.value = textVal; |
| 10204 | textNode = textNode.prev; |
| 10205 | } else { |
| 10206 | sibling = textNode.prev; |
| 10207 | textNode.remove(); |
| 10208 | textNode = sibling; |
| 10209 | } |
| 10210 | } |
| 10211 | } |
| 10212 | |
| 10213 | function cloneAndExcludeBlocks(input) { |
| 10214 | var name, output = {}; |
| 10215 | |
| 10216 | for (name in input) { |
| 10217 | if (name !== 'li' && name != 'p') { |
| 10218 | output[name] = input[name]; |
| 10219 | } |
| 10220 | } |
| 10221 | |
| 10222 | return output; |
| 10223 | } |
| 10224 | |
| 10225 | parser = new SaxParser({ |
| 10226 | validate: validate, |
| 10227 | allow_script_urls: settings.allow_script_urls, |
| 10228 | allow_conditional_comments: settings.allow_conditional_comments, |
| 10229 | |
| 10230 | // Exclude P and LI from DOM parsing since it's treated better by the DOM parser |
| 10231 | self_closing_elements: cloneAndExcludeBlocks(schema.getSelfClosingElements()), |
| 10232 | |
| 10233 | cdata: function(text) { |
| 10234 | node.append(createNode('#cdata', 4)).value = text; |
| 10235 | }, |
| 10236 | |
| 10237 | text: function(text, raw) { |
| 10238 | var textNode; |
| 10239 | |
| 10240 | // Trim all redundant whitespace on non white space elements |
| 10241 | if (!isInWhiteSpacePreservedElement) { |
| 10242 | text = text.replace(allWhiteSpaceRegExp, ' '); |
| 10243 | |
| 10244 | if (node.lastChild && blockElements[node.lastChild.name]) { |
| 10245 | text = text.replace(startWhiteSpaceRegExp, ''); |
| 10246 | } |
| 10247 | } |
| 10248 | |
| 10249 | // Do we need to create the node |
| 10250 | if (text.length !== 0) { |
| 10251 | textNode = createNode('#text', 3); |
| 10252 | textNode.raw = !!raw; |
| 10253 | node.append(textNode).value = text; |
| 10254 | } |
| 10255 | }, |
| 10256 | |
| 10257 | comment: function(text) { |
| 10258 | node.append(createNode('#comment', 8)).value = text; |
| 10259 | }, |
| 10260 | |
| 10261 | pi: function(name, text) { |
| 10262 | node.append(createNode(name, 7)).value = text; |
| 10263 | removeWhitespaceBefore(node); |
| 10264 | }, |
| 10265 | |
| 10266 | doctype: function(text) { |
| 10267 | var newNode; |
| 10268 | |
| 10269 | newNode = node.append(createNode('#doctype', 10)); |
| 10270 | newNode.value = text; |
| 10271 | removeWhitespaceBefore(node); |
| 10272 | }, |
| 10273 | |
| 10274 | start: function(name, attrs, empty) { |
| 10275 | var newNode, attrFiltersLen, elementRule, attrName, parent; |
| 10276 | |
| 10277 | elementRule = validate ? schema.getElementRule(name) : {}; |
| 10278 | if (elementRule) { |
| 10279 | newNode = createNode(elementRule.outputName || name, 1); |
| 10280 | newNode.attributes = attrs; |
| 10281 | newNode.shortEnded = empty; |
| 10282 | |
| 10283 | node.append(newNode); |
| 10284 | |
| 10285 | // Check if node is valid child of the parent node is the child is |
| 10286 | // unknown we don't collect it since it's probably a custom element |
| 10287 | parent = children[node.name]; |
| 10288 | if (parent && children[newNode.name] && !parent[newNode.name]) { |
| 10289 | invalidChildren.push(newNode); |
| 10290 | } |
| 10291 | |
| 10292 | attrFiltersLen = attributeFilters.length; |
| 10293 | while (attrFiltersLen--) { |
| 10294 | attrName = attributeFilters[attrFiltersLen].name; |
| 10295 | |
| 10296 | if (attrName in attrs.map) { |
| 10297 | list = matchedAttributes[attrName]; |
| 10298 | |
| 10299 | if (list) { |
| 10300 | list.push(newNode); |
| 10301 | } else { |
| 10302 | matchedAttributes[attrName] = [newNode]; |
| 10303 | } |
| 10304 | } |
| 10305 | } |
| 10306 | |
| 10307 | // Trim whitespace before block |
| 10308 | if (blockElements[name]) { |
| 10309 | removeWhitespaceBefore(newNode); |
| 10310 | } |
| 10311 | |
| 10312 | // Change current node if the element wasn't empty i.e not <br /> or <img /> |
| 10313 | if (!empty) { |
| 10314 | node = newNode; |
| 10315 | } |
| 10316 | |
| 10317 | // Check if we are inside a whitespace preserved element |
| 10318 | if (!isInWhiteSpacePreservedElement && whiteSpaceElements[name]) { |
| 10319 | isInWhiteSpacePreservedElement = true; |
| 10320 | } |
| 10321 | } |
| 10322 | }, |
| 10323 | |
| 10324 | end: function(name) { |
| 10325 | var textNode, elementRule, text, sibling, tempNode; |
| 10326 | |
| 10327 | elementRule = validate ? schema.getElementRule(name) : {}; |
| 10328 | if (elementRule) { |
| 10329 | if (blockElements[name]) { |
| 10330 | if (!isInWhiteSpacePreservedElement) { |
| 10331 | // Trim whitespace of the first node in a block |
| 10332 | textNode = node.firstChild; |
| 10333 | if (textNode && textNode.type === 3) { |
| 10334 | text = textNode.value.replace(startWhiteSpaceRegExp, ''); |
| 10335 | |
| 10336 | // Any characters left after trim or should we remove it |
| 10337 | if (text.length > 0) { |
| 10338 | textNode.value = text; |
| 10339 | textNode = textNode.next; |
| 10340 | } else { |
| 10341 | sibling = textNode.next; |
| 10342 | textNode.remove(); |
| 10343 | textNode = sibling; |
| 10344 | |
| 10345 | // Remove any pure whitespace siblings |
| 10346 | while (textNode && textNode.type === 3) { |
| 10347 | text = textNode.value; |
| 10348 | sibling = textNode.next; |
| 10349 | |
| 10350 | if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) { |
| 10351 | textNode.remove(); |
| 10352 | textNode = sibling; |
| 10353 | } |
| 10354 | |
| 10355 | textNode = sibling; |
| 10356 | } |
| 10357 | } |
| 10358 | } |
| 10359 | |
| 10360 | // Trim whitespace of the last node in a block |
| 10361 | textNode = node.lastChild; |
| 10362 | if (textNode && textNode.type === 3) { |
| 10363 | text = textNode.value.replace(endWhiteSpaceRegExp, ''); |
| 10364 | |
| 10365 | // Any characters left after trim or should we remove it |
| 10366 | if (text.length > 0) { |
| 10367 | textNode.value = text; |
| 10368 | textNode = textNode.prev; |
| 10369 | } else { |
| 10370 | sibling = textNode.prev; |
| 10371 | textNode.remove(); |
| 10372 | textNode = sibling; |
| 10373 | |
| 10374 | // Remove any pure whitespace siblings |
| 10375 | while (textNode && textNode.type === 3) { |
| 10376 | text = textNode.value; |
| 10377 | sibling = textNode.prev; |
| 10378 | |
| 10379 | if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) { |
| 10380 | textNode.remove(); |
| 10381 | textNode = sibling; |
| 10382 | } |
| 10383 | |
| 10384 | textNode = sibling; |
| 10385 | } |
| 10386 | } |
| 10387 | } |
| 10388 | } |
| 10389 | |
| 10390 | // Trim start white space |
| 10391 | // Removed due to: #5424 |
| 10392 | /*textNode = node.prev; |
| 10393 | if (textNode && textNode.type === 3) { |
| 10394 | text = textNode.value.replace(startWhiteSpaceRegExp, ''); |
| 10395 | |
| 10396 | if (text.length > 0) |
| 10397 | textNode.value = text; |
| 10398 | else |
| 10399 | textNode.remove(); |
| 10400 | }*/ |
| 10401 | } |
| 10402 | |
| 10403 | // Check if we exited a whitespace preserved element |
| 10404 | if (isInWhiteSpacePreservedElement && whiteSpaceElements[name]) { |
| 10405 | isInWhiteSpacePreservedElement = false; |
| 10406 | } |
| 10407 | |
| 10408 | // Handle empty nodes |
| 10409 | if (elementRule.removeEmpty || elementRule.paddEmpty) { |
| 10410 | if (node.isEmpty(nonEmptyElements)) { |
| 10411 | if (elementRule.paddEmpty) { |
| 10412 | node.empty().append(new Node('#text', '3')).value = '\u00a0'; |
| 10413 | } else { |
| 10414 | // Leave nodes that have a name like <a name="name"> |
| 10415 | if (!node.attributes.map.name && !node.attributes.map.id) { |
| 10416 | tempNode = node.parent; |
| 10417 | node.empty().remove(); |
| 10418 | node = tempNode; |
| 10419 | return; |
| 10420 | } |
| 10421 | } |
| 10422 | } |
| 10423 | } |
| 10424 | |
| 10425 | node = node.parent; |
| 10426 | } |
| 10427 | } |
| 10428 | }, schema); |
| 10429 | |
| 10430 | rootNode = node = new Node(args.context || settings.root_name, 11); |
| 10431 | |
| 10432 | parser.parse(html); |
| 10433 | |
| 10434 | // Fix invalid children or report invalid children in a contextual parsing |
| 10435 | if (validate && invalidChildren.length) { |
| 10436 | if (!args.context) { |
| 10437 | fixInvalidChildren(invalidChildren); |
| 10438 | } else { |
| 10439 | args.invalid = true; |
| 10440 | } |
| 10441 | } |
| 10442 | |
| 10443 | // Wrap nodes in the root into block elements if the root is body |
| 10444 | if (rootBlockName && (rootNode.name == 'body' || args.isRootContent)) { |
| 10445 | addRootBlocks(); |
| 10446 | } |
| 10447 | |
| 10448 | // Run filters only when the contents is valid |
| 10449 | if (!args.invalid) { |
| 10450 | // Run node filters |
| 10451 | for (name in matchedNodes) { |
| 10452 | list = nodeFilters[name]; |
| 10453 | nodes = matchedNodes[name]; |
| 10454 | |
| 10455 | // Remove already removed children |
| 10456 | fi = nodes.length; |
| 10457 | while (fi--) { |
| 10458 | if (!nodes[fi].parent) { |
| 10459 | nodes.splice(fi, 1); |
| 10460 | } |
| 10461 | } |
| 10462 | |
| 10463 | for (i = 0, l = list.length; i < l; i++) { |
| 10464 | list[i](nodes, name, args); |
| 10465 | } |
| 10466 | } |
| 10467 | |
| 10468 | // Run attribute filters |
| 10469 | for (i = 0, l = attributeFilters.length; i < l; i++) { |
| 10470 | list = attributeFilters[i]; |
| 10471 | |
| 10472 | if (list.name in matchedAttributes) { |
| 10473 | nodes = matchedAttributes[list.name]; |
| 10474 | |
| 10475 | // Remove already removed children |
| 10476 | fi = nodes.length; |
| 10477 | while (fi--) { |
| 10478 | if (!nodes[fi].parent) { |
| 10479 | nodes.splice(fi, 1); |
| 10480 | } |
| 10481 | } |
| 10482 | |
| 10483 | for (fi = 0, fl = list.callbacks.length; fi < fl; fi++) { |
| 10484 | list.callbacks[fi](nodes, list.name, args); |
| 10485 | } |
| 10486 | } |
| 10487 | } |
| 10488 | } |
| 10489 | |
| 10490 | return rootNode; |
| 10491 | }; |
| 10492 | |
| 10493 | // Remove <br> at end of block elements Gecko and WebKit injects BR elements to |
| 10494 | // make it possible to place the caret inside empty blocks. This logic tries to remove |
| 10495 | // these elements and keep br elements that where intended to be there intact |
| 10496 | if (settings.remove_trailing_brs) { |
| 10497 | self.addNodeFilter('br', function(nodes) { |
| 10498 | var i, l = nodes.length, node, blockElements = extend({}, schema.getBlockElements()); |
| 10499 | var nonEmptyElements = schema.getNonEmptyElements(), parent, lastParent, prev, prevName; |
| 10500 | var elementRule, textNode; |
| 10501 | |
| 10502 | // Remove brs from body element as well |
| 10503 | blockElements.body = 1; |
| 10504 | |
| 10505 | // Must loop forwards since it will otherwise remove all brs in <p>a<br><br><br></p> |
| 10506 | for (i = 0; i < l; i++) { |
| 10507 | node = nodes[i]; |
| 10508 | parent = node.parent; |
| 10509 | |
| 10510 | if (blockElements[node.parent.name] && node === parent.lastChild) { |
| 10511 | // Loop all nodes to the left of the current node and check for other BR elements |
| 10512 | // excluding bookmarks since they are invisible |
| 10513 | prev = node.prev; |
| 10514 | while (prev) { |
| 10515 | prevName = prev.name; |
| 10516 | |
| 10517 | // Ignore bookmarks |
| 10518 | if (prevName !== "span" || prev.attr('data-mce-type') !== 'bookmark') { |
| 10519 | // Found a non BR element |
| 10520 | if (prevName !== "br") { |
| 10521 | break; |
| 10522 | } |
| 10523 | |
| 10524 | // Found another br it's a <br><br> structure then don't remove anything |
| 10525 | if (prevName === 'br') { |
| 10526 | node = null; |
| 10527 | break; |
| 10528 | } |
| 10529 | } |
| 10530 | |
| 10531 | prev = prev.prev; |
| 10532 | } |
| 10533 | |
| 10534 | if (node) { |
| 10535 | node.remove(); |
| 10536 | |
| 10537 | // Is the parent to be considered empty after we removed the BR |
| 10538 | if (parent.isEmpty(nonEmptyElements)) { |
| 10539 | elementRule = schema.getElementRule(parent.name); |
| 10540 | |
| 10541 | // Remove or padd the element depending on schema rule |
| 10542 | if (elementRule) { |
| 10543 | if (elementRule.removeEmpty) { |
| 10544 | parent.remove(); |
| 10545 | } else if (elementRule.paddEmpty) { |
| 10546 | parent.empty().append(new Node('#text', 3)).value = '\u00a0'; |
| 10547 | } |
| 10548 | } |
| 10549 | } |
| 10550 | } |
| 10551 | } else { |
| 10552 | // Replaces BR elements inside inline elements like <p><b><i><br></i></b></p> |
| 10553 | // so they become <p><b><i> </i></b></p> |
| 10554 | lastParent = node; |
| 10555 | while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) { |
| 10556 | lastParent = parent; |
| 10557 | |
| 10558 | if (blockElements[parent.name]) { |
| 10559 | break; |
| 10560 | } |
| 10561 | |
| 10562 | parent = parent.parent; |
| 10563 | } |
| 10564 | |
| 10565 | if (lastParent === parent) { |
| 10566 | textNode = new Node('#text', 3); |
| 10567 | textNode.value = '\u00a0'; |
| 10568 | node.replace(textNode); |
| 10569 | } |
| 10570 | } |
| 10571 | } |
| 10572 | }); |
| 10573 | } |
| 10574 | |
| 10575 | // Force anchor names closed, unless the setting "allow_html_in_named_anchor" is explicitly included. |
| 10576 | if (!settings.allow_html_in_named_anchor) { |
| 10577 | self.addAttributeFilter('id,name', function(nodes) { |
| 10578 | var i = nodes.length, sibling, prevSibling, parent, node; |
| 10579 | |
| 10580 | while (i--) { |
| 10581 | node = nodes[i]; |
| 10582 | if (node.name === 'a' && node.firstChild && !node.attr('href')) { |
| 10583 | parent = node.parent; |
| 10584 | |
| 10585 | // Move children after current node |
| 10586 | sibling = node.lastChild; |
| 10587 | do { |
| 10588 | prevSibling = sibling.prev; |
| 10589 | parent.insert(sibling, node); |
| 10590 | sibling = prevSibling; |
| 10591 | } while (sibling); |
| 10592 | } |
| 10593 | } |
| 10594 | }); |
| 10595 | } |
| 10596 | }; |
| 10597 | }); |
| 10598 | |
| 10599 | // Included from: js/tinymce/classes/html/Writer.js |
| 10600 | |
| 10601 | /** |
| 10602 | * Writer.js |
| 10603 | * |
| 10604 | * Copyright, Moxiecode Systems AB |
| 10605 | * Released under LGPL License. |
| 10606 | * |
| 10607 | * License: http://www.tinymce.com/license |
| 10608 | * Contributing: http://www.tinymce.com/contributing |
| 10609 | */ |
| 10610 | |
| 10611 | /** |
| 10612 | * This class is used to write HTML tags out it can be used with the Serializer or the SaxParser. |
| 10613 | * |
| 10614 | * @class tinymce.html.Writer |
| 10615 | * @example |
| 10616 | * var writer = new tinymce.html.Writer({indent: true}); |
| 10617 | * var parser = new tinymce.html.SaxParser(writer).parse('<p><br></p>'); |
| 10618 | * console.log(writer.getContent()); |
| 10619 | * |
| 10620 | * @class tinymce.html.Writer |
| 10621 | * @version 3.4 |
| 10622 | */ |
| 10623 | define("tinymce/html/Writer", [ |
| 10624 | "tinymce/html/Entities", |
| 10625 | "tinymce/util/Tools" |
| 10626 | ], function(Entities, Tools) { |
| 10627 | var makeMap = Tools.makeMap; |
| 10628 | |
| 10629 | /** |
| 10630 | * Constructs a new Writer instance. |
| 10631 | * |
| 10632 | * @constructor |
| 10633 | * @method Writer |
| 10634 | * @param {Object} settings Name/value settings object. |
| 10635 | */ |
| 10636 | return function(settings) { |
| 10637 | var html = [], indent, indentBefore, indentAfter, encode, htmlOutput; |
| 10638 | |
| 10639 | settings = settings || {}; |
| 10640 | indent = settings.indent; |
| 10641 | indentBefore = makeMap(settings.indent_before || ''); |
| 10642 | indentAfter = makeMap(settings.indent_after || ''); |
| 10643 | encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities); |
| 10644 | htmlOutput = settings.element_format == "html"; |
| 10645 | |
| 10646 | return { |
| 10647 | /** |
| 10648 | * Writes the a start element such as <p id="a">. |
| 10649 | * |
| 10650 | * @method start |
| 10651 | * @param {String} name Name of the element. |
| 10652 | * @param {Array} attrs Optional attribute array or undefined if it hasn't any. |
| 10653 | * @param {Boolean} empty Optional empty state if the tag should end like <br />. |
| 10654 | */ |
| 10655 | start: function(name, attrs, empty) { |
| 10656 | var i, l, attr, value; |
| 10657 | |
| 10658 | if (indent && indentBefore[name] && html.length > 0) { |
| 10659 | value = html[html.length - 1]; |
| 10660 | |
| 10661 | if (value.length > 0 && value !== '\n') { |
| 10662 | html.push('\n'); |
| 10663 | } |
| 10664 | } |
| 10665 | |
| 10666 | html.push('<', name); |
| 10667 | |
| 10668 | if (attrs) { |
| 10669 | for (i = 0, l = attrs.length; i < l; i++) { |
| 10670 | attr = attrs[i]; |
| 10671 | html.push(' ', attr.name, '="', encode(attr.value, true), '"'); |
| 10672 | } |
| 10673 | } |
| 10674 | |
| 10675 | if (!empty || htmlOutput) { |
| 10676 | html[html.length] = '>'; |
| 10677 | } else { |
| 10678 | html[html.length] = ' />'; |
| 10679 | } |
| 10680 | |
| 10681 | if (empty && indent && indentAfter[name] && html.length > 0) { |
| 10682 | value = html[html.length - 1]; |
| 10683 | |
| 10684 | if (value.length > 0 && value !== '\n') { |
| 10685 | html.push('\n'); |
| 10686 | } |
| 10687 | } |
| 10688 | }, |
| 10689 | |
| 10690 | /** |
| 10691 | * Writes the a end element such as </p>. |
| 10692 | * |
| 10693 | * @method end |
| 10694 | * @param {String} name Name of the element. |
| 10695 | */ |
| 10696 | end: function(name) { |
| 10697 | var value; |
| 10698 | |
| 10699 | /*if (indent && indentBefore[name] && html.length > 0) { |
| 10700 | value = html[html.length - 1]; |
| 10701 | |
| 10702 | if (value.length > 0 && value !== '\n') |
| 10703 | html.push('\n'); |
| 10704 | }*/ |
| 10705 | |
| 10706 | html.push('</', name, '>'); |
| 10707 | |
| 10708 | if (indent && indentAfter[name] && html.length > 0) { |
| 10709 | value = html[html.length - 1]; |
| 10710 | |
| 10711 | if (value.length > 0 && value !== '\n') { |
| 10712 | html.push('\n'); |
| 10713 | } |
| 10714 | } |
| 10715 | }, |
| 10716 | |
| 10717 | /** |
| 10718 | * Writes a text node. |
| 10719 | * |
| 10720 | * @method text |
| 10721 | * @param {String} text String to write out. |
| 10722 | * @param {Boolean} raw Optional raw state if true the contents wont get encoded. |
| 10723 | */ |
| 10724 | text: function(text, raw) { |
| 10725 | if (text.length > 0) { |
| 10726 | html[html.length] = raw ? text : encode(text); |
| 10727 | } |
| 10728 | }, |
| 10729 | |
| 10730 | /** |
| 10731 | * Writes a cdata node such as <![CDATA[data]]>. |
| 10732 | * |
| 10733 | * @method cdata |
| 10734 | * @param {String} text String to write out inside the cdata. |
| 10735 | */ |
| 10736 | cdata: function(text) { |
| 10737 | html.push('<![CDATA[', text, ']]>'); |
| 10738 | }, |
| 10739 | |
| 10740 | /** |
| 10741 | * Writes a comment node such as <!-- Comment -->. |
| 10742 | * |
| 10743 | * @method cdata |
| 10744 | * @param {String} text String to write out inside the comment. |
| 10745 | */ |
| 10746 | comment: function(text) { |
| 10747 | html.push('<!--', text, '-->'); |
| 10748 | }, |
| 10749 | |
| 10750 | /** |
| 10751 | * Writes a PI node such as <?xml attr="value" ?>. |
| 10752 | * |
| 10753 | * @method pi |
| 10754 | * @param {String} name Name of the pi. |
| 10755 | * @param {String} text String to write out inside the pi. |
| 10756 | */ |
| 10757 | pi: function(name, text) { |
| 10758 | if (text) { |
| 10759 | html.push('<?', name, ' ', text, '?>'); |
| 10760 | } else { |
| 10761 | html.push('<?', name, '?>'); |
| 10762 | } |
| 10763 | |
| 10764 | if (indent) { |
| 10765 | html.push('\n'); |
| 10766 | } |
| 10767 | }, |
| 10768 | |
| 10769 | /** |
| 10770 | * Writes a doctype node such as <!DOCTYPE data>. |
| 10771 | * |
| 10772 | * @method doctype |
| 10773 | * @param {String} text String to write out inside the doctype. |
| 10774 | */ |
| 10775 | doctype: function(text) { |
| 10776 | html.push('<!DOCTYPE', text, '>', indent ? '\n' : ''); |
| 10777 | }, |
| 10778 | |
| 10779 | /** |
| 10780 | * Resets the internal buffer if one wants to reuse the writer. |
| 10781 | * |
| 10782 | * @method reset |
| 10783 | */ |
| 10784 | reset: function() { |
| 10785 | html.length = 0; |
| 10786 | }, |
| 10787 | |
| 10788 | /** |
| 10789 | * Returns the contents that got serialized. |
| 10790 | * |
| 10791 | * @method getContent |
| 10792 | * @return {String} HTML contents that got written down. |
| 10793 | */ |
| 10794 | getContent: function() { |
| 10795 | return html.join('').replace(/\n$/, ''); |
| 10796 | } |
| 10797 | }; |
| 10798 | }; |
| 10799 | }); |
| 10800 | |
| 10801 | // Included from: js/tinymce/classes/html/Serializer.js |
| 10802 | |
| 10803 | /** |
| 10804 | * Serializer.js |
| 10805 | * |
| 10806 | * Copyright, Moxiecode Systems AB |
| 10807 | * Released under LGPL License. |
| 10808 | * |
| 10809 | * License: http://www.tinymce.com/license |
| 10810 | * Contributing: http://www.tinymce.com/contributing |
| 10811 | */ |
| 10812 | |
| 10813 | /** |
| 10814 | * This class is used to serialize down the DOM tree into a string using a Writer instance. |
| 10815 | * |
| 10816 | * |
| 10817 | * @example |
| 10818 | * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>')); |
| 10819 | * @class tinymce.html.Serializer |
| 10820 | * @version 3.4 |
| 10821 | */ |
| 10822 | define("tinymce/html/Serializer", [ |
| 10823 | "tinymce/html/Writer", |
| 10824 | "tinymce/html/Schema" |
| 10825 | ], function(Writer, Schema) { |
| 10826 | /** |
| 10827 | * Constructs a new Serializer instance. |
| 10828 | * |
| 10829 | * @constructor |
| 10830 | * @method Serializer |
| 10831 | * @param {Object} settings Name/value settings object. |
| 10832 | * @param {tinymce.html.Schema} schema Schema instance to use. |
| 10833 | */ |
| 10834 | return function(settings, schema) { |
| 10835 | var self = this, writer = new Writer(settings); |
| 10836 | |
| 10837 | settings = settings || {}; |
| 10838 | settings.validate = "validate" in settings ? settings.validate : true; |
| 10839 | |
| 10840 | self.schema = schema = schema || new Schema(); |
| 10841 | self.writer = writer; |
| 10842 | |
| 10843 | /** |
| 10844 | * Serializes the specified node into a string. |
| 10845 | * |
| 10846 | * @example |
| 10847 | * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>')); |
| 10848 | * @method serialize |
| 10849 | * @param {tinymce.html.Node} node Node instance to serialize. |
| 10850 | * @return {String} String with HTML based on DOM tree. |
| 10851 | */ |
| 10852 | self.serialize = function(node) { |
| 10853 | var handlers, validate; |
| 10854 | |
| 10855 | validate = settings.validate; |
| 10856 | |
| 10857 | handlers = { |
| 10858 | // #text |
| 10859 | 3: function(node) { |
| 10860 | writer.text(node.value, node.raw); |
| 10861 | }, |
| 10862 | |
| 10863 | // #comment |
| 10864 | 8: function(node) { |
| 10865 | writer.comment(node.value); |
| 10866 | }, |
| 10867 | |
| 10868 | // Processing instruction |
| 10869 | 7: function(node) { |
| 10870 | writer.pi(node.name, node.value); |
| 10871 | }, |
| 10872 | |
| 10873 | // Doctype |
| 10874 | 10: function(node) { |
| 10875 | writer.doctype(node.value); |
| 10876 | }, |
| 10877 | |
| 10878 | // CDATA |
| 10879 | 4: function(node) { |
| 10880 | writer.cdata(node.value); |
| 10881 | }, |
| 10882 | |
| 10883 | // Document fragment |
| 10884 | 11: function(node) { |
| 10885 | if ((node = node.firstChild)) { |
| 10886 | do { |
| 10887 | walk(node); |
| 10888 | } while ((node = node.next)); |
| 10889 | } |
| 10890 | } |
| 10891 | }; |
| 10892 | |
| 10893 | writer.reset(); |
| 10894 | |
| 10895 | function walk(node) { |
| 10896 | var handler = handlers[node.type], name, isEmpty, attrs, attrName, attrValue, sortedAttrs, i, l, elementRule; |
| 10897 | |
| 10898 | if (!handler) { |
| 10899 | name = node.name; |
| 10900 | isEmpty = node.shortEnded; |
| 10901 | attrs = node.attributes; |
| 10902 | |
| 10903 | // Sort attributes |
| 10904 | if (validate && attrs && attrs.length > 1) { |
| 10905 | sortedAttrs = []; |
| 10906 | sortedAttrs.map = {}; |
| 10907 | |
| 10908 | elementRule = schema.getElementRule(node.name); |
| 10909 | for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) { |
| 10910 | attrName = elementRule.attributesOrder[i]; |
| 10911 | |
| 10912 | if (attrName in attrs.map) { |
| 10913 | attrValue = attrs.map[attrName]; |
| 10914 | sortedAttrs.map[attrName] = attrValue; |
| 10915 | sortedAttrs.push({name: attrName, value: attrValue}); |
| 10916 | } |
| 10917 | } |
| 10918 | |
| 10919 | for (i = 0, l = attrs.length; i < l; i++) { |
| 10920 | attrName = attrs[i].name; |
| 10921 | |
| 10922 | if (!(attrName in sortedAttrs.map)) { |
| 10923 | attrValue = attrs.map[attrName]; |
| 10924 | sortedAttrs.map[attrName] = attrValue; |
| 10925 | sortedAttrs.push({name: attrName, value: attrValue}); |
| 10926 | } |
| 10927 | } |
| 10928 | |
| 10929 | attrs = sortedAttrs; |
| 10930 | } |
| 10931 | |
| 10932 | writer.start(node.name, attrs, isEmpty); |
| 10933 | |
| 10934 | if (!isEmpty) { |
| 10935 | if ((node = node.firstChild)) { |
| 10936 | do { |
| 10937 | walk(node); |
| 10938 | } while ((node = node.next)); |
| 10939 | } |
| 10940 | |
| 10941 | writer.end(name); |
| 10942 | } |
| 10943 | } else { |
| 10944 | handler(node); |
| 10945 | } |
| 10946 | } |
| 10947 | |
| 10948 | // Serialize element and treat all non elements as fragments |
| 10949 | if (node.type == 1 && !settings.inner) { |
| 10950 | walk(node); |
| 10951 | } else { |
| 10952 | handlers[11](node); |
| 10953 | } |
| 10954 | |
| 10955 | return writer.getContent(); |
| 10956 | }; |
| 10957 | }; |
| 10958 | }); |
| 10959 | |
| 10960 | // Included from: js/tinymce/classes/dom/Serializer.js |
| 10961 | |
| 10962 | /** |
| 10963 | * Serializer.js |
| 10964 | * |
| 10965 | * Copyright, Moxiecode Systems AB |
| 10966 | * Released under LGPL License. |
| 10967 | * |
| 10968 | * License: http://www.tinymce.com/license |
| 10969 | * Contributing: http://www.tinymce.com/contributing |
| 10970 | */ |
| 10971 | |
| 10972 | /** |
| 10973 | * This class is used to serialize DOM trees into a string. Consult the TinyMCE Wiki API for |
| 10974 | * more details and examples on how to use this class. |
| 10975 | * |
| 10976 | * @class tinymce.dom.Serializer |
| 10977 | */ |
| 10978 | define("tinymce/dom/Serializer", [ |
| 10979 | "tinymce/dom/DOMUtils", |
| 10980 | "tinymce/html/DomParser", |
| 10981 | "tinymce/html/Entities", |
| 10982 | "tinymce/html/Serializer", |
| 10983 | "tinymce/html/Node", |
| 10984 | "tinymce/html/Schema", |
| 10985 | "tinymce/Env", |
| 10986 | "tinymce/util/Tools" |
| 10987 | ], function(DOMUtils, DomParser, Entities, Serializer, Node, Schema, Env, Tools) { |
| 10988 | var each = Tools.each, trim = Tools.trim; |
| 10989 | var DOM = DOMUtils.DOM; |
| 10990 | |
| 10991 | /** |
| 10992 | * Constructs a new DOM serializer class. |
| 10993 | * |
| 10994 | * @constructor |
| 10995 | * @method Serializer |
| 10996 | * @param {Object} settings Serializer settings object. |
| 10997 | * @param {tinymce.Editor} editor Optional editor to bind events to and get schema/dom from. |
| 10998 | */ |
| 10999 | return function(settings, editor) { |
| 11000 | var dom, schema, htmlParser; |
| 11001 | |
| 11002 | if (editor) { |
| 11003 | dom = editor.dom; |
| 11004 | schema = editor.schema; |
| 11005 | } |
| 11006 | |
| 11007 | // Default DOM and Schema if they are undefined |
| 11008 | dom = dom || DOM; |
| 11009 | schema = schema || new Schema(settings); |
| 11010 | settings.entity_encoding = settings.entity_encoding || 'named'; |
| 11011 | settings.remove_trailing_brs = "remove_trailing_brs" in settings ? settings.remove_trailing_brs : true; |
| 11012 | |
| 11013 | htmlParser = new DomParser(settings, schema); |
| 11014 | |
| 11015 | // Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed |
| 11016 | htmlParser.addAttributeFilter('src,href,style', function(nodes, name) { |
| 11017 | var i = nodes.length, node, value, internalName = 'data-mce-' + name; |
| 11018 | var urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope, undef; |
| 11019 | |
| 11020 | while (i--) { |
| 11021 | node = nodes[i]; |
| 11022 | |
| 11023 | value = node.attributes.map[internalName]; |
| 11024 | if (value !== undef) { |
| 11025 | // Set external name to internal value and remove internal |
| 11026 | node.attr(name, value.length > 0 ? value : null); |
| 11027 | node.attr(internalName, null); |
| 11028 | } else { |
| 11029 | // No internal attribute found then convert the value we have in the DOM |
| 11030 | value = node.attributes.map[name]; |
| 11031 | |
| 11032 | if (name === "style") { |
| 11033 | value = dom.serializeStyle(dom.parseStyle(value), node.name); |
| 11034 | } else if (urlConverter) { |
| 11035 | value = urlConverter.call(urlConverterScope, value, name, node.name); |
| 11036 | } |
| 11037 | |
| 11038 | node.attr(name, value.length > 0 ? value : null); |
| 11039 | } |
| 11040 | } |
| 11041 | }); |
| 11042 | |
| 11043 | // Remove internal classes mceItem<..> or mceSelected |
| 11044 | htmlParser.addAttributeFilter('class', function(nodes) { |
| 11045 | var i = nodes.length, node, value; |
| 11046 | |
| 11047 | while (i--) { |
| 11048 | node = nodes[i]; |
| 11049 | value = node.attr('class').replace(/(?:^|\s)mce-item-\w+(?!\S)/g, ''); |
| 11050 | node.attr('class', value.length > 0 ? value : null); |
| 11051 | } |
| 11052 | }); |
| 11053 | |
| 11054 | // Remove bookmark elements |
| 11055 | htmlParser.addAttributeFilter('data-mce-type', function(nodes, name, args) { |
| 11056 | var i = nodes.length, node; |
| 11057 | |
| 11058 | while (i--) { |
| 11059 | node = nodes[i]; |
| 11060 | |
| 11061 | if (node.attributes.map['data-mce-type'] === 'bookmark' && !args.cleanup) { |
| 11062 | node.remove(); |
| 11063 | } |
| 11064 | } |
| 11065 | }); |
| 11066 | |
| 11067 | // Remove expando attributes |
| 11068 | htmlParser.addAttributeFilter('data-mce-expando', function(nodes, name) { |
| 11069 | var i = nodes.length; |
| 11070 | |
| 11071 | while (i--) { |
| 11072 | nodes[i].attr(name, null); |
| 11073 | } |
| 11074 | }); |
| 11075 | |
| 11076 | htmlParser.addNodeFilter('noscript', function(nodes) { |
| 11077 | var i = nodes.length, node; |
| 11078 | |
| 11079 | while (i--) { |
| 11080 | node = nodes[i].firstChild; |
| 11081 | |
| 11082 | if (node) { |
| 11083 | node.value = Entities.decode(node.value); |
| 11084 | } |
| 11085 | } |
| 11086 | }); |
| 11087 | |
| 11088 | // Force script into CDATA sections and remove the mce- prefix also add comments around styles |
| 11089 | htmlParser.addNodeFilter('script,style', function(nodes, name) { |
| 11090 | var i = nodes.length, node, value; |
| 11091 | |
| 11092 | function trim(value) { |
| 11093 | /*jshint maxlen:255 */ |
| 11094 | return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n') |
| 11095 | .replace(/^[\r\n]*|[\r\n]*$/g, '') |
| 11096 | .replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '') |
| 11097 | .replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, ''); |
| 11098 | } |
| 11099 | |
| 11100 | while (i--) { |
| 11101 | node = nodes[i]; |
| 11102 | value = node.firstChild ? node.firstChild.value : ''; |
| 11103 | |
| 11104 | if (name === "script") { |
| 11105 | // Remove mce- prefix from script elements and remove default text/javascript mime type (HTML5) |
| 11106 | var type = (node.attr('type') || 'text/javascript').replace(/^mce\-/, ''); |
| 11107 | node.attr('type', type === 'text/javascript' ? null : type); |
| 11108 | |
| 11109 | if (value.length > 0) { |
| 11110 | node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>'; |
| 11111 | } |
| 11112 | } else { |
| 11113 | if (value.length > 0) { |
| 11114 | node.firstChild.value = '<!--\n' + trim(value) + '\n-->'; |
| 11115 | } |
| 11116 | } |
| 11117 | } |
| 11118 | }); |
| 11119 | |
| 11120 | // Convert comments to cdata and handle protected comments |
| 11121 | htmlParser.addNodeFilter('#comment', function(nodes) { |
| 11122 | var i = nodes.length, node; |
| 11123 | |
| 11124 | while (i--) { |
| 11125 | node = nodes[i]; |
| 11126 | |
| 11127 | if (node.value.indexOf('[CDATA[') === 0) { |
| 11128 | node.name = '#cdata'; |
| 11129 | node.type = 4; |
| 11130 | node.value = node.value.replace(/^\[CDATA\[|\]\]$/g, ''); |
| 11131 | } else if (node.value.indexOf('mce:protected ') === 0) { |
| 11132 | node.name = "#text"; |
| 11133 | node.type = 3; |
| 11134 | node.raw = true; |
| 11135 | node.value = unescape(node.value).substr(14); |
| 11136 | } |
| 11137 | } |
| 11138 | }); |
| 11139 | |
| 11140 | htmlParser.addNodeFilter('xml:namespace,input', function(nodes, name) { |
| 11141 | var i = nodes.length, node; |
| 11142 | |
| 11143 | while (i--) { |
| 11144 | node = nodes[i]; |
| 11145 | if (node.type === 7) { |
| 11146 | node.remove(); |
| 11147 | } else if (node.type === 1) { |
| 11148 | if (name === "input" && !("type" in node.attributes.map)) { |
| 11149 | node.attr('type', 'text'); |
| 11150 | } |
| 11151 | } |
| 11152 | } |
| 11153 | }); |
| 11154 | |
| 11155 | // Fix list elements, TODO: Replace this later |
| 11156 | if (settings.fix_list_elements) { |
| 11157 | htmlParser.addNodeFilter('ul,ol', function(nodes) { |
| 11158 | var i = nodes.length, node, parentNode; |
| 11159 | |
| 11160 | while (i--) { |
| 11161 | node = nodes[i]; |
| 11162 | parentNode = node.parent; |
| 11163 | |
| 11164 | if (parentNode.name === 'ul' || parentNode.name === 'ol') { |
| 11165 | if (node.prev && node.prev.name === 'li') { |
| 11166 | node.prev.append(node); |
| 11167 | } |
| 11168 | } |
| 11169 | } |
| 11170 | }); |
| 11171 | } |
| 11172 | |
| 11173 | // Remove internal data attributes |
| 11174 | htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style,data-mce-selected', function(nodes, name) { |
| 11175 | var i = nodes.length; |
| 11176 | |
| 11177 | while (i--) { |
| 11178 | nodes[i].attr(name, null); |
| 11179 | } |
| 11180 | }); |
| 11181 | |
| 11182 | // Return public methods |
| 11183 | return { |
| 11184 | /** |
| 11185 | * Schema instance that was used to when the Serializer was constructed. |
| 11186 | * |
| 11187 | * @field {tinymce.html.Schema} schema |
| 11188 | */ |
| 11189 | schema: schema, |
| 11190 | |
| 11191 | /** |
| 11192 | * Adds a node filter function to the parser used by the serializer, the parser will collect the specified nodes by name |
| 11193 | * and then execute the callback ones it has finished parsing the document. |
| 11194 | * |
| 11195 | * @example |
| 11196 | * parser.addNodeFilter('p,h1', function(nodes, name) { |
| 11197 | * for (var i = 0; i < nodes.length; i++) { |
| 11198 | * console.log(nodes[i].name); |
| 11199 | * } |
| 11200 | * }); |
| 11201 | * @method addNodeFilter |
| 11202 | * @method {String} name Comma separated list of nodes to collect. |
| 11203 | * @param {function} callback Callback function to execute once it has collected nodes. |
| 11204 | */ |
| 11205 | addNodeFilter: htmlParser.addNodeFilter, |
| 11206 | |
| 11207 | /** |
| 11208 | * Adds a attribute filter function to the parser used by the serializer, the parser will |
| 11209 | * collect nodes that has the specified attributes |
| 11210 | * and then execute the callback ones it has finished parsing the document. |
| 11211 | * |
| 11212 | * @example |
| 11213 | * parser.addAttributeFilter('src,href', function(nodes, name) { |
| 11214 | * for (var i = 0; i < nodes.length; i++) { |
| 11215 | * console.log(nodes[i].name); |
| 11216 | * } |
| 11217 | * }); |
| 11218 | * @method addAttributeFilter |
| 11219 | * @method {String} name Comma separated list of nodes to collect. |
| 11220 | * @param {function} callback Callback function to execute once it has collected nodes. |
| 11221 | */ |
| 11222 | addAttributeFilter: htmlParser.addAttributeFilter, |
| 11223 | |
| 11224 | /** |
| 11225 | * Serializes the specified browser DOM node into a HTML string. |
| 11226 | * |
| 11227 | * @method serialize |
| 11228 | * @param {DOMNode} node DOM node to serialize. |
| 11229 | * @param {Object} args Arguments option that gets passed to event handlers. |
| 11230 | */ |
| 11231 | serialize: function(node, args) { |
| 11232 | var self = this, impl, doc, oldDoc, htmlSerializer, content; |
| 11233 | |
| 11234 | // Explorer won't clone contents of script and style and the |
| 11235 | // selected index of select elements are cleared on a clone operation. |
| 11236 | if (Env.ie && dom.select('script,style,select,map').length > 0) { |
| 11237 | content = node.innerHTML; |
| 11238 | node = node.cloneNode(false); |
| 11239 | dom.setHTML(node, content); |
| 11240 | } else { |
| 11241 | node = node.cloneNode(true); |
| 11242 | } |
| 11243 | |
| 11244 | // Nodes needs to be attached to something in WebKit/Opera |
| 11245 | // This fix will make DOM ranges and make Sizzle happy! |
| 11246 | impl = node.ownerDocument.implementation; |
| 11247 | if (impl.createHTMLDocument) { |
| 11248 | // Create an empty HTML document |
| 11249 | doc = impl.createHTMLDocument(""); |
| 11250 | |
| 11251 | // Add the element or it's children if it's a body element to the new document |
| 11252 | each(node.nodeName == 'BODY' ? node.childNodes : [node], function(node) { |
| 11253 | doc.body.appendChild(doc.importNode(node, true)); |
| 11254 | }); |
| 11255 | |
| 11256 | // Grab first child or body element for serialization |
| 11257 | if (node.nodeName != 'BODY') { |
| 11258 | node = doc.body.firstChild; |
| 11259 | } else { |
| 11260 | node = doc.body; |
| 11261 | } |
| 11262 | |
| 11263 | // set the new document in DOMUtils so createElement etc works |
| 11264 | oldDoc = dom.doc; |
| 11265 | dom.doc = doc; |
| 11266 | } |
| 11267 | |
| 11268 | args = args || {}; |
| 11269 | args.format = args.format || 'html'; |
| 11270 | |
| 11271 | // Don't wrap content if we want selected html |
| 11272 | if (args.selection) { |
| 11273 | args.forced_root_block = ''; |
| 11274 | } |
| 11275 | |
| 11276 | // Pre process |
| 11277 | if (!args.no_events) { |
| 11278 | args.node = node; |
| 11279 | self.onPreProcess(args); |
| 11280 | } |
| 11281 | |
| 11282 | // Setup serializer |
| 11283 | htmlSerializer = new Serializer(settings, schema); |
| 11284 | |
| 11285 | // Parse and serialize HTML |
| 11286 | args.content = htmlSerializer.serialize( |
| 11287 | htmlParser.parse(trim(args.getInner ? node.innerHTML : dom.getOuterHTML(node)), args) |
| 11288 | ); |
| 11289 | |
| 11290 | // Replace all BOM characters for now until we can find a better solution |
| 11291 | if (!args.cleanup) { |
| 11292 | args.content = args.content.replace(/\uFEFF/g, ''); |
| 11293 | } |
| 11294 | |
| 11295 | // Post process |
| 11296 | if (!args.no_events) { |
| 11297 | self.onPostProcess(args); |
| 11298 | } |
| 11299 | |
| 11300 | // Restore the old document if it was changed |
| 11301 | if (oldDoc) { |
| 11302 | dom.doc = oldDoc; |
| 11303 | } |
| 11304 | |
| 11305 | args.node = null; |
| 11306 | |
| 11307 | return args.content; |
| 11308 | }, |
| 11309 | |
| 11310 | /** |
| 11311 | * Adds valid elements rules to the serializers schema instance this enables you to specify things |
| 11312 | * like what elements should be outputted and what attributes specific elements might have. |
| 11313 | * Consult the Wiki for more details on this format. |
| 11314 | * |
| 11315 | * @method addRules |
| 11316 | * @param {String} rules Valid elements rules string to add to schema. |
| 11317 | */ |
| 11318 | addRules: function(rules) { |
| 11319 | schema.addValidElements(rules); |
| 11320 | }, |
| 11321 | |
| 11322 | /** |
| 11323 | * Sets the valid elements rules to the serializers schema instance this enables you to specify things |
| 11324 | * like what elements should be outputted and what attributes specific elements might have. |
| 11325 | * Consult the Wiki for more details on this format. |
| 11326 | * |
| 11327 | * @method setRules |
| 11328 | * @param {String} rules Valid elements rules string. |
| 11329 | */ |
| 11330 | setRules: function(rules) { |
| 11331 | schema.setValidElements(rules); |
| 11332 | }, |
| 11333 | |
| 11334 | onPreProcess: function(args) { |
| 11335 | if (editor) { |
| 11336 | editor.fire('PreProcess', args); |
| 11337 | } |
| 11338 | }, |
| 11339 | |
| 11340 | onPostProcess: function(args) { |
| 11341 | if (editor) { |
| 11342 | editor.fire('PostProcess', args); |
| 11343 | } |
| 11344 | } |
| 11345 | }; |
| 11346 | }; |
| 11347 | }); |
| 11348 | |
| 11349 | // Included from: js/tinymce/classes/dom/TridentSelection.js |
| 11350 | |
| 11351 | /** |
| 11352 | * TridentSelection.js |
| 11353 | * |
| 11354 | * Copyright, Moxiecode Systems AB |
| 11355 | * Released under LGPL License. |
| 11356 | * |
| 11357 | * License: http://www.tinymce.com/license |
| 11358 | * Contributing: http://www.tinymce.com/contributing |
| 11359 | */ |
| 11360 | |
| 11361 | /** |
| 11362 | * Selection class for old explorer versions. This one fakes the |
| 11363 | * native selection object available on modern browsers. |
| 11364 | * |
| 11365 | * @class tinymce.dom.TridentSelection |
| 11366 | */ |
| 11367 | define("tinymce/dom/TridentSelection", [], function() { |
| 11368 | function Selection(selection) { |
| 11369 | var self = this, dom = selection.dom, FALSE = false; |
| 11370 | |
| 11371 | function getPosition(rng, start) { |
| 11372 | var checkRng, startIndex = 0, endIndex, inside, |
| 11373 | children, child, offset, index, position = -1, parent; |
| 11374 | |
| 11375 | // Setup test range, collapse it and get the parent |
| 11376 | checkRng = rng.duplicate(); |
| 11377 | checkRng.collapse(start); |
| 11378 | parent = checkRng.parentElement(); |
| 11379 | |
| 11380 | // Check if the selection is within the right document |
| 11381 | if (parent.ownerDocument !== selection.dom.doc) { |
| 11382 | return; |
| 11383 | } |
| 11384 | |
| 11385 | // IE will report non editable elements as it's parent so look for an editable one |
| 11386 | while (parent.contentEditable === "false") { |
| 11387 | parent = parent.parentNode; |
| 11388 | } |
| 11389 | |
| 11390 | // If parent doesn't have any children then return that we are inside the element |
| 11391 | if (!parent.hasChildNodes()) { |
| 11392 | return {node: parent, inside: 1}; |
| 11393 | } |
| 11394 | |
| 11395 | // Setup node list and endIndex |
| 11396 | children = parent.children; |
| 11397 | endIndex = children.length - 1; |
| 11398 | |
| 11399 | // Perform a binary search for the position |
| 11400 | while (startIndex <= endIndex) { |
| 11401 | index = Math.floor((startIndex + endIndex) / 2); |
| 11402 | |
| 11403 | // Move selection to node and compare the ranges |
| 11404 | child = children[index]; |
| 11405 | checkRng.moveToElementText(child); |
| 11406 | position = checkRng.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', rng); |
| 11407 | |
| 11408 | // Before/after or an exact match |
| 11409 | if (position > 0) { |
| 11410 | endIndex = index - 1; |
| 11411 | } else if (position < 0) { |
| 11412 | startIndex = index + 1; |
| 11413 | } else { |
| 11414 | return {node: child}; |
| 11415 | } |
| 11416 | } |
| 11417 | |
| 11418 | // Check if child position is before or we didn't find a position |
| 11419 | if (position < 0) { |
| 11420 | // No element child was found use the parent element and the offset inside that |
| 11421 | if (!child) { |
| 11422 | checkRng.moveToElementText(parent); |
| 11423 | checkRng.collapse(true); |
| 11424 | child = parent; |
| 11425 | inside = true; |
| 11426 | } else { |
| 11427 | checkRng.collapse(false); |
| 11428 | } |
| 11429 | |
| 11430 | // Walk character by character in text node until we hit the selected range endpoint, |
| 11431 | // hit the end of document or parent isn't the right one |
| 11432 | // We need to walk char by char since rng.text or rng.htmlText will trim line endings |
| 11433 | offset = 0; |
| 11434 | while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) { |
| 11435 | if (checkRng.move('character', 1) === 0 || parent != checkRng.parentElement()) { |
| 11436 | break; |
| 11437 | } |
| 11438 | |
| 11439 | offset++; |
| 11440 | } |
| 11441 | } else { |
| 11442 | // Child position is after the selection endpoint |
| 11443 | checkRng.collapse(true); |
| 11444 | |
| 11445 | // Walk character by character in text node until we hit the selected range endpoint, hit |
| 11446 | // the end of document or parent isn't the right one |
| 11447 | offset = 0; |
| 11448 | while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) { |
| 11449 | if (checkRng.move('character', -1) === 0 || parent != checkRng.parentElement()) { |
| 11450 | break; |
| 11451 | } |
| 11452 | |
| 11453 | offset++; |
| 11454 | } |
| 11455 | } |
| 11456 | |
| 11457 | return {node: child, position: position, offset: offset, inside: inside}; |
| 11458 | } |
| 11459 | |
| 11460 | // Returns a W3C DOM compatible range object by using the IE Range API |
| 11461 | function getRange() { |
| 11462 | var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed, tmpRange, element2, bookmark; |
| 11463 | |
| 11464 | // If selection is outside the current document just return an empty range |
| 11465 | element = ieRange.item ? ieRange.item(0) : ieRange.parentElement(); |
| 11466 | if (element.ownerDocument != dom.doc) { |
| 11467 | return domRange; |
| 11468 | } |
| 11469 | |
| 11470 | collapsed = selection.isCollapsed(); |
| 11471 | |
| 11472 | // Handle control selection |
| 11473 | if (ieRange.item) { |
| 11474 | domRange.setStart(element.parentNode, dom.nodeIndex(element)); |
| 11475 | domRange.setEnd(domRange.startContainer, domRange.startOffset + 1); |
| 11476 | |
| 11477 | return domRange; |
| 11478 | } |
| 11479 | |
| 11480 | function findEndPoint(start) { |
| 11481 | var endPoint = getPosition(ieRange, start), container, offset, textNodeOffset = 0, sibling, undef, nodeValue; |
| 11482 | |
| 11483 | container = endPoint.node; |
| 11484 | offset = endPoint.offset; |
| 11485 | |
| 11486 | if (endPoint.inside && !container.hasChildNodes()) { |
| 11487 | domRange[start ? 'setStart' : 'setEnd'](container, 0); |
| 11488 | return; |
| 11489 | } |
| 11490 | |
| 11491 | if (offset === undef) { |
| 11492 | domRange[start ? 'setStartBefore' : 'setEndAfter'](container); |
| 11493 | return; |
| 11494 | } |
| 11495 | |
| 11496 | if (endPoint.position < 0) { |
| 11497 | sibling = endPoint.inside ? container.firstChild : container.nextSibling; |
| 11498 | |
| 11499 | if (!sibling) { |
| 11500 | domRange[start ? 'setStartAfter' : 'setEndAfter'](container); |
| 11501 | return; |
| 11502 | } |
| 11503 | |
| 11504 | if (!offset) { |
| 11505 | if (sibling.nodeType == 3) { |
| 11506 | domRange[start ? 'setStart' : 'setEnd'](sibling, 0); |
| 11507 | } else { |
| 11508 | domRange[start ? 'setStartBefore' : 'setEndBefore'](sibling); |
| 11509 | } |
| 11510 | |
| 11511 | return; |
| 11512 | } |
| 11513 | |
| 11514 | // Find the text node and offset |
| 11515 | while (sibling) { |
| 11516 | nodeValue = sibling.nodeValue; |
| 11517 | textNodeOffset += nodeValue.length; |
| 11518 | |
| 11519 | // We are at or passed the position we where looking for |
| 11520 | if (textNodeOffset >= offset) { |
| 11521 | container = sibling; |
| 11522 | textNodeOffset -= offset; |
| 11523 | textNodeOffset = nodeValue.length - textNodeOffset; |
| 11524 | break; |
| 11525 | } |
| 11526 | |
| 11527 | sibling = sibling.nextSibling; |
| 11528 | } |
| 11529 | } else { |
| 11530 | // Find the text node and offset |
| 11531 | sibling = container.previousSibling; |
| 11532 | |
| 11533 | if (!sibling) { |
| 11534 | return domRange[start ? 'setStartBefore' : 'setEndBefore'](container); |
| 11535 | } |
| 11536 | |
| 11537 | // If there isn't any text to loop then use the first position |
| 11538 | if (!offset) { |
| 11539 | if (container.nodeType == 3) { |
| 11540 | domRange[start ? 'setStart' : 'setEnd'](sibling, container.nodeValue.length); |
| 11541 | } else { |
| 11542 | domRange[start ? 'setStartAfter' : 'setEndAfter'](sibling); |
| 11543 | } |
| 11544 | |
| 11545 | return; |
| 11546 | } |
| 11547 | |
| 11548 | while (sibling) { |
| 11549 | textNodeOffset += sibling.nodeValue.length; |
| 11550 | |
| 11551 | // We are at or passed the position we where looking for |
| 11552 | if (textNodeOffset >= offset) { |
| 11553 | container = sibling; |
| 11554 | textNodeOffset -= offset; |
| 11555 | break; |
| 11556 | } |
| 11557 | |
| 11558 | sibling = sibling.previousSibling; |
| 11559 | } |
| 11560 | } |
| 11561 | |
| 11562 | domRange[start ? 'setStart' : 'setEnd'](container, textNodeOffset); |
| 11563 | } |
| 11564 | |
| 11565 | try { |
| 11566 | // Find start point |
| 11567 | findEndPoint(true); |
| 11568 | |
| 11569 | // Find end point if needed |
| 11570 | if (!collapsed) { |
| 11571 | findEndPoint(); |
| 11572 | } |
| 11573 | } catch (ex) { |
| 11574 | // IE has a nasty bug where text nodes might throw "invalid argument" when you |
| 11575 | // access the nodeValue or other properties of text nodes. This seems to happend when |
| 11576 | // text nodes are split into two nodes by a delete/backspace call. So lets detect it and try to fix it. |
| 11577 | if (ex.number == -2147024809) { |
| 11578 | // Get the current selection |
| 11579 | bookmark = self.getBookmark(2); |
| 11580 | |
| 11581 | // Get start element |
| 11582 | tmpRange = ieRange.duplicate(); |
| 11583 | tmpRange.collapse(true); |
| 11584 | element = tmpRange.parentElement(); |
| 11585 | |
| 11586 | // Get end element |
| 11587 | if (!collapsed) { |
| 11588 | tmpRange = ieRange.duplicate(); |
| 11589 | tmpRange.collapse(false); |
| 11590 | element2 = tmpRange.parentElement(); |
| 11591 | element2.innerHTML = element2.innerHTML; |
| 11592 | } |
| 11593 | |
| 11594 | // Remove the broken elements |
| 11595 | element.innerHTML = element.innerHTML; |
| 11596 | |
| 11597 | // Restore the selection |
| 11598 | self.moveToBookmark(bookmark); |
| 11599 | |
| 11600 | // Since the range has moved we need to re-get it |
| 11601 | ieRange = selection.getRng(); |
| 11602 | |
| 11603 | // Find start point |
| 11604 | findEndPoint(true); |
| 11605 | |
| 11606 | // Find end point if needed |
| 11607 | if (!collapsed) { |
| 11608 | findEndPoint(); |
| 11609 | } |
| 11610 | } else { |
| 11611 | throw ex; // Throw other errors |
| 11612 | } |
| 11613 | } |
| 11614 | |
| 11615 | return domRange; |
| 11616 | } |
| 11617 | |
| 11618 | this.getBookmark = function(type) { |
| 11619 | var rng = selection.getRng(), bookmark = {}; |
| 11620 | |
| 11621 | function getIndexes(node) { |
| 11622 | var parent, root, children, i, indexes = []; |
| 11623 | |
| 11624 | parent = node.parentNode; |
| 11625 | root = dom.getRoot().parentNode; |
| 11626 | |
| 11627 | while (parent != root && parent.nodeType !== 9) { |
| 11628 | children = parent.children; |
| 11629 | |
| 11630 | i = children.length; |
| 11631 | while (i--) { |
| 11632 | if (node === children[i]) { |
| 11633 | indexes.push(i); |
| 11634 | break; |
| 11635 | } |
| 11636 | } |
| 11637 | |
| 11638 | node = parent; |
| 11639 | parent = parent.parentNode; |
| 11640 | } |
| 11641 | |
| 11642 | return indexes; |
| 11643 | } |
| 11644 | |
| 11645 | function getBookmarkEndPoint(start) { |
| 11646 | var position; |
| 11647 | |
| 11648 | position = getPosition(rng, start); |
| 11649 | if (position) { |
| 11650 | return { |
| 11651 | position: position.position, |
| 11652 | offset: position.offset, |
| 11653 | indexes: getIndexes(position.node), |
| 11654 | inside: position.inside |
| 11655 | }; |
| 11656 | } |
| 11657 | } |
| 11658 | |
| 11659 | // Non ubstructive bookmark |
| 11660 | if (type === 2) { |
| 11661 | // Handle text selection |
| 11662 | if (!rng.item) { |
| 11663 | bookmark.start = getBookmarkEndPoint(true); |
| 11664 | |
| 11665 | if (!selection.isCollapsed()) { |
| 11666 | bookmark.end = getBookmarkEndPoint(); |
| 11667 | } |
| 11668 | } else { |
| 11669 | bookmark.start = {ctrl: true, indexes: getIndexes(rng.item(0))}; |
| 11670 | } |
| 11671 | } |
| 11672 | |
| 11673 | return bookmark; |
| 11674 | }; |
| 11675 | |
| 11676 | this.moveToBookmark = function(bookmark) { |
| 11677 | var rng, body = dom.doc.body; |
| 11678 | |
| 11679 | function resolveIndexes(indexes) { |
| 11680 | var node, i, idx, children; |
| 11681 | |
| 11682 | node = dom.getRoot(); |
| 11683 | for (i = indexes.length - 1; i >= 0; i--) { |
| 11684 | children = node.children; |
| 11685 | idx = indexes[i]; |
| 11686 | |
| 11687 | if (idx <= children.length - 1) { |
| 11688 | node = children[idx]; |
| 11689 | } |
| 11690 | } |
| 11691 | |
| 11692 | return node; |
| 11693 | } |
| 11694 | |
| 11695 | function setBookmarkEndPoint(start) { |
| 11696 | var endPoint = bookmark[start ? 'start' : 'end'], moveLeft, moveRng, undef, offset; |
| 11697 | |
| 11698 | if (endPoint) { |
| 11699 | moveLeft = endPoint.position > 0; |
| 11700 | |
| 11701 | moveRng = body.createTextRange(); |
| 11702 | moveRng.moveToElementText(resolveIndexes(endPoint.indexes)); |
| 11703 | |
| 11704 | offset = endPoint.offset; |
| 11705 | if (offset !== undef) { |
| 11706 | moveRng.collapse(endPoint.inside || moveLeft); |
| 11707 | moveRng.moveStart('character', moveLeft ? -offset : offset); |
| 11708 | } else { |
| 11709 | moveRng.collapse(start); |
| 11710 | } |
| 11711 | |
| 11712 | rng.setEndPoint(start ? 'StartToStart' : 'EndToStart', moveRng); |
| 11713 | |
| 11714 | if (start) { |
| 11715 | rng.collapse(true); |
| 11716 | } |
| 11717 | } |
| 11718 | } |
| 11719 | |
| 11720 | if (bookmark.start) { |
| 11721 | if (bookmark.start.ctrl) { |
| 11722 | rng = body.createControlRange(); |
| 11723 | rng.addElement(resolveIndexes(bookmark.start.indexes)); |
| 11724 | rng.select(); |
| 11725 | } else { |
| 11726 | rng = body.createTextRange(); |
| 11727 | setBookmarkEndPoint(true); |
| 11728 | setBookmarkEndPoint(); |
| 11729 | rng.select(); |
| 11730 | } |
| 11731 | } |
| 11732 | }; |
| 11733 | |
| 11734 | this.addRange = function(rng) { |
| 11735 | var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, sibling, |
| 11736 | doc = selection.dom.doc, body = doc.body, nativeRng, ctrlElm; |
| 11737 | |
| 11738 | function setEndPoint(start) { |
| 11739 | var container, offset, marker, tmpRng, nodes; |
| 11740 | |
| 11741 | marker = dom.create('a'); |
| 11742 | container = start ? startContainer : endContainer; |
| 11743 | offset = start ? startOffset : endOffset; |
| 11744 | tmpRng = ieRng.duplicate(); |
| 11745 | |
| 11746 | if (container == doc || container == doc.documentElement) { |
| 11747 | container = body; |
| 11748 | offset = 0; |
| 11749 | } |
| 11750 | |
| 11751 | if (container.nodeType == 3) { |
| 11752 | container.parentNode.insertBefore(marker, container); |
| 11753 | tmpRng.moveToElementText(marker); |
| 11754 | tmpRng.moveStart('character', offset); |
| 11755 | dom.remove(marker); |
| 11756 | ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng); |
| 11757 | } else { |
| 11758 | nodes = container.childNodes; |
| 11759 | |
| 11760 | if (nodes.length) { |
| 11761 | if (offset >= nodes.length) { |
| 11762 | dom.insertAfter(marker, nodes[nodes.length - 1]); |
| 11763 | } else { |
| 11764 | container.insertBefore(marker, nodes[offset]); |
| 11765 | } |
| 11766 | |
| 11767 | tmpRng.moveToElementText(marker); |
| 11768 | } else if (container.canHaveHTML) { |
| 11769 | // Empty node selection for example <div>|</div> |
| 11770 | // Setting innerHTML with a span marker then remove that marker seems to keep empty block elements open |
| 11771 | container.innerHTML = '<span></span>'; |
| 11772 | marker = container.firstChild; |
| 11773 | tmpRng.moveToElementText(marker); |
| 11774 | tmpRng.collapse(FALSE); // Collapse false works better than true for some odd reason |
| 11775 | } |
| 11776 | |
| 11777 | ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng); |
| 11778 | dom.remove(marker); |
| 11779 | } |
| 11780 | } |
| 11781 | |
| 11782 | // Setup some shorter versions |
| 11783 | startContainer = rng.startContainer; |
| 11784 | startOffset = rng.startOffset; |
| 11785 | endContainer = rng.endContainer; |
| 11786 | endOffset = rng.endOffset; |
| 11787 | ieRng = body.createTextRange(); |
| 11788 | |
| 11789 | // If single element selection then try making a control selection out of it |
| 11790 | if (startContainer == endContainer && startContainer.nodeType == 1) { |
| 11791 | // Trick to place the caret inside an empty block element like <p></p> |
| 11792 | if (startOffset == endOffset && !startContainer.hasChildNodes()) { |
| 11793 | if (startContainer.canHaveHTML) { |
| 11794 | // Check if previous sibling is an empty block if it is then we need to render it |
| 11795 | // IE would otherwise move the caret into the sibling instead of the empty startContainer see: #5236 |
| 11796 | // Example this: <p></p><p>|</p> would become this: <p>|</p><p></p> |
| 11797 | sibling = startContainer.previousSibling; |
| 11798 | if (sibling && !sibling.hasChildNodes() && dom.isBlock(sibling)) { |
| 11799 | sibling.innerHTML = ''; |
| 11800 | } else { |
| 11801 | sibling = null; |
| 11802 | } |
| 11803 | |
| 11804 | startContainer.innerHTML = '<span></span><span></span>'; |
| 11805 | ieRng.moveToElementText(startContainer.lastChild); |
| 11806 | ieRng.select(); |
| 11807 | dom.doc.selection.clear(); |
| 11808 | startContainer.innerHTML = ''; |
| 11809 | |
| 11810 | if (sibling) { |
| 11811 | sibling.innerHTML = ''; |
| 11812 | } |
| 11813 | return; |
| 11814 | } else { |
| 11815 | startOffset = dom.nodeIndex(startContainer); |
| 11816 | startContainer = startContainer.parentNode; |
| 11817 | } |
| 11818 | } |
| 11819 | |
| 11820 | if (startOffset == endOffset - 1) { |
| 11821 | try { |
| 11822 | ctrlElm = startContainer.childNodes[startOffset]; |
| 11823 | ctrlRng = body.createControlRange(); |
| 11824 | ctrlRng.addElement(ctrlElm); |
| 11825 | ctrlRng.select(); |
| 11826 | |
| 11827 | // Check if the range produced is on the correct element and is a control range |
| 11828 | // On IE 8 it will select the parent contentEditable container if you select an inner element see: #5398 |
| 11829 | nativeRng = selection.getRng(); |
| 11830 | if (nativeRng.item && ctrlElm === nativeRng.item(0)) { |
| 11831 | return; |
| 11832 | } |
| 11833 | } catch (ex) { |
| 11834 | // Ignore |
| 11835 | } |
| 11836 | } |
| 11837 | } |
| 11838 | |
| 11839 | // Set start/end point of selection |
| 11840 | setEndPoint(true); |
| 11841 | setEndPoint(); |
| 11842 | |
| 11843 | // Select the new range and scroll it into view |
| 11844 | ieRng.select(); |
| 11845 | }; |
| 11846 | |
| 11847 | // Expose range method |
| 11848 | this.getRangeAt = getRange; |
| 11849 | } |
| 11850 | |
| 11851 | return Selection; |
| 11852 | }); |
| 11853 | |
| 11854 | // Included from: js/tinymce/classes/util/VK.js |
| 11855 | |
| 11856 | /** |
| 11857 | * VK.js |
| 11858 | * |
| 11859 | * Copyright, Moxiecode Systems AB |
| 11860 | * Released under LGPL License. |
| 11861 | * |
| 11862 | * License: http://www.tinymce.com/license |
| 11863 | * Contributing: http://www.tinymce.com/contributing |
| 11864 | */ |
| 11865 | |
| 11866 | /** |
| 11867 | * This file exposes a set of the common KeyCodes for use. Please grow it as needed. |
| 11868 | */ |
| 11869 | define("tinymce/util/VK", [ |
| 11870 | "tinymce/Env" |
| 11871 | ], function(Env) { |
| 11872 | return { |
| 11873 | BACKSPACE: 8, |
| 11874 | DELETE: 46, |
| 11875 | DOWN: 40, |
| 11876 | ENTER: 13, |
| 11877 | LEFT: 37, |
| 11878 | RIGHT: 39, |
| 11879 | SPACEBAR: 32, |
| 11880 | TAB: 9, |
| 11881 | UP: 38, |
| 11882 | |
| 11883 | modifierPressed: function(e) { |
| 11884 | return e.shiftKey || e.ctrlKey || e.altKey; |
| 11885 | }, |
| 11886 | |
| 11887 | metaKeyPressed: function(e) { |
| 11888 | // Check if ctrl or meta key is pressed also check if alt is false for Polish users |
| 11889 | return (Env.mac ? e.metaKey : e.ctrlKey) && !e.altKey; |
| 11890 | } |
| 11891 | }; |
| 11892 | }); |
| 11893 | |
| 11894 | // Included from: js/tinymce/classes/dom/ControlSelection.js |
| 11895 | |
| 11896 | /** |
| 11897 | * ControlSelection.js |
| 11898 | * |
| 11899 | * Copyright, Moxiecode Systems AB |
| 11900 | * Released under LGPL License. |
| 11901 | * |
| 11902 | * License: http://www.tinymce.com/license |
| 11903 | * Contributing: http://www.tinymce.com/contributing |
| 11904 | */ |
| 11905 | |
| 11906 | /** |
| 11907 | * This class handles control selection of elements. Controls are elements |
| 11908 | * that can be resized and needs to be selected as a whole. It adds custom resize handles |
| 11909 | * to all browser engines that support properly disabling the built in resize logic. |
| 11910 | * |
| 11911 | * @class tinymce.dom.ControlSelection |
| 11912 | */ |
| 11913 | define("tinymce/dom/ControlSelection", [ |
| 11914 | "tinymce/util/VK", |
| 11915 | "tinymce/util/Tools", |
| 11916 | "tinymce/Env" |
| 11917 | ], function(VK, Tools, Env) { |
| 11918 | return function(selection, editor) { |
| 11919 | var dom = editor.dom, each = Tools.each; |
| 11920 | var selectedElm, selectedElmGhost, resizeHandles, selectedHandle, lastMouseDownEvent; |
| 11921 | var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted; |
| 11922 | var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie && Env.ie < 11; |
| 11923 | |
| 11924 | // Details about each resize handle how to scale etc |
| 11925 | resizeHandles = { |
| 11926 | // Name: x multiplier, y multiplier, delta size x, delta size y |
| 11927 | n: [0.5, 0, 0, -1], |
| 11928 | e: [1, 0.5, 1, 0], |
| 11929 | s: [0.5, 1, 0, 1], |
| 11930 | w: [0, 0.5, -1, 0], |
| 11931 | nw: [0, 0, -1, -1], |
| 11932 | ne: [1, 0, 1, -1], |
| 11933 | se: [1, 1, 1, 1], |
| 11934 | sw: [0, 1, -1, 1] |
| 11935 | }; |
| 11936 | |
| 11937 | // Add CSS for resize handles, cloned element and selected |
| 11938 | var rootClass = '.mce-content-body'; |
| 11939 | editor.contentStyles.push( |
| 11940 | rootClass + ' div.mce-resizehandle {' + |
| 11941 | 'position: absolute;' + |
| 11942 | 'border: 1px solid black;' + |
| 11943 | 'background: #FFF;' + |
| 11944 | 'width: 5px;' + |
| 11945 | 'height: 5px;' + |
| 11946 | 'z-index: 10000' + |
| 11947 | '}' + |
| 11948 | rootClass + ' .mce-resizehandle:hover {' + |
| 11949 | 'background: #000' + |
| 11950 | '}' + |
| 11951 | rootClass + ' img[data-mce-selected], hr[data-mce-selected] {' + |
| 11952 | 'outline: 1px solid black;' + |
| 11953 | 'resize: none' + // Have been talks about implementing this in browsers |
| 11954 | '}' + |
| 11955 | rootClass + ' .mce-clonedresizable {' + |
| 11956 | 'position: absolute;' + |
| 11957 | (Env.gecko ? '' : 'outline: 1px dashed black;') + // Gecko produces trails while resizing |
| 11958 | 'opacity: .5;' + |
| 11959 | 'filter: alpha(opacity=50);' + |
| 11960 | 'z-index: 10000' + |
| 11961 | '}' |
| 11962 | ); |
| 11963 | |
| 11964 | function isResizable(elm) { |
| 11965 | if (editor.settings.object_resizing === false) { |
| 11966 | return false; |
| 11967 | } |
| 11968 | |
| 11969 | if (!/TABLE|IMG|DIV/.test(elm.nodeName)) { |
| 11970 | return false; |
| 11971 | } |
| 11972 | |
| 11973 | if (elm.getAttribute('data-mce-resize') === 'false') { |
| 11974 | return false; |
| 11975 | } |
| 11976 | |
| 11977 | return true; |
| 11978 | } |
| 11979 | |
| 11980 | function resizeGhostElement(e) { |
| 11981 | var deltaX, deltaY; |
| 11982 | |
| 11983 | // Calc new width/height |
| 11984 | deltaX = e.screenX - startX; |
| 11985 | deltaY = e.screenY - startY; |
| 11986 | |
| 11987 | // Calc new size |
| 11988 | width = deltaX * selectedHandle[2] + startW; |
| 11989 | height = deltaY * selectedHandle[3] + startH; |
| 11990 | |
| 11991 | // Never scale down lower than 5 pixels |
| 11992 | width = width < 5 ? 5 : width; |
| 11993 | height = height < 5 ? 5 : height; |
| 11994 | |
| 11995 | // Constrain proportions when modifier key is pressed or if the nw, ne, sw, se corners are moved on an image |
| 11996 | if (VK.modifierPressed(e) || (selectedElm.nodeName == "IMG" && selectedHandle[2] * selectedHandle[3] !== 0)) { |
| 11997 | width = Math.round(height / ratio); |
| 11998 | height = Math.round(width * ratio); |
| 11999 | } |
| 12000 | |
| 12001 | // Update ghost size |
| 12002 | dom.setStyles(selectedElmGhost, { |
| 12003 | width: width, |
| 12004 | height: height |
| 12005 | }); |
| 12006 | |
| 12007 | // Update ghost X position if needed |
| 12008 | if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) { |
| 12009 | dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width)); |
| 12010 | } |
| 12011 | |
| 12012 | // Update ghost Y position if needed |
| 12013 | if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) { |
| 12014 | dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height)); |
| 12015 | } |
| 12016 | |
| 12017 | if (!resizeStarted) { |
| 12018 | editor.fire('ObjectResizeStart', {target: selectedElm, width: startW, height: startH}); |
| 12019 | resizeStarted = true; |
| 12020 | } |
| 12021 | } |
| 12022 | |
| 12023 | function endGhostResize() { |
| 12024 | resizeStarted = false; |
| 12025 | |
| 12026 | function setSizeProp(name, value) { |
| 12027 | if (value) { |
| 12028 | // Resize by using style or attribute |
| 12029 | if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) { |
| 12030 | dom.setStyle(selectedElm, name, value); |
| 12031 | } else { |
| 12032 | dom.setAttrib(selectedElm, name, value); |
| 12033 | } |
| 12034 | } |
| 12035 | } |
| 12036 | |
| 12037 | // Set width/height properties |
| 12038 | setSizeProp('width', width); |
| 12039 | setSizeProp('height', height); |
| 12040 | |
| 12041 | dom.unbind(editableDoc, 'mousemove', resizeGhostElement); |
| 12042 | dom.unbind(editableDoc, 'mouseup', endGhostResize); |
| 12043 | |
| 12044 | if (rootDocument != editableDoc) { |
| 12045 | dom.unbind(rootDocument, 'mousemove', resizeGhostElement); |
| 12046 | dom.unbind(rootDocument, 'mouseup', endGhostResize); |
| 12047 | } |
| 12048 | |
| 12049 | // Remove ghost and update resize handle positions |
| 12050 | dom.remove(selectedElmGhost); |
| 12051 | |
| 12052 | if (!isIE || selectedElm.nodeName == "TABLE") { |
| 12053 | showResizeRect(selectedElm); |
| 12054 | } |
| 12055 | |
| 12056 | editor.fire('ObjectResized', {target: selectedElm, width: width, height: height}); |
| 12057 | editor.nodeChanged(); |
| 12058 | } |
| 12059 | |
| 12060 | function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) { |
| 12061 | var position, targetWidth, targetHeight, e, rect, offsetParent = editor.getBody(); |
| 12062 | |
| 12063 | // Get position and size of target |
| 12064 | position = dom.getPos(targetElm, offsetParent); |
| 12065 | selectedElmX = position.x; |
| 12066 | selectedElmY = position.y; |
| 12067 | rect = targetElm.getBoundingClientRect(); // Fix for Gecko offsetHeight for table with caption |
| 12068 | targetWidth = rect.width || (rect.right - rect.left); |
| 12069 | targetHeight = rect.height || (rect.bottom - rect.top); |
| 12070 | |
| 12071 | // Reset width/height if user selects a new image/table |
| 12072 | if (selectedElm != targetElm) { |
| 12073 | detachResizeStartListener(); |
| 12074 | selectedElm = targetElm; |
| 12075 | width = height = 0; |
| 12076 | } |
| 12077 | |
| 12078 | // Makes it possible to disable resizing |
| 12079 | e = editor.fire('ObjectSelected', {target: targetElm}); |
| 12080 | |
| 12081 | if (isResizable(targetElm) && !e.isDefaultPrevented()) { |
| 12082 | each(resizeHandles, function(handle, name) { |
| 12083 | var handleElm, handlerContainerElm; |
| 12084 | |
| 12085 | function startDrag(e) { |
| 12086 | resizeStarted = true; |
| 12087 | |
| 12088 | startX = e.screenX; |
| 12089 | startY = e.screenY; |
| 12090 | startW = selectedElm.clientWidth; |
| 12091 | startH = selectedElm.clientHeight; |
| 12092 | ratio = startH / startW; |
| 12093 | selectedHandle = handle; |
| 12094 | |
| 12095 | selectedElmGhost = selectedElm.cloneNode(true); |
| 12096 | dom.addClass(selectedElmGhost, 'mce-clonedresizable'); |
| 12097 | selectedElmGhost.contentEditable = false; // Hides IE move layer cursor |
| 12098 | selectedElmGhost.unSelectabe = true; |
| 12099 | dom.setStyles(selectedElmGhost, { |
| 12100 | left: selectedElmX, |
| 12101 | top: selectedElmY, |
| 12102 | margin: 0 |
| 12103 | }); |
| 12104 | |
| 12105 | selectedElmGhost.removeAttribute('data-mce-selected'); |
| 12106 | editor.getBody().appendChild(selectedElmGhost); |
| 12107 | |
| 12108 | dom.bind(editableDoc, 'mousemove', resizeGhostElement); |
| 12109 | dom.bind(editableDoc, 'mouseup', endGhostResize); |
| 12110 | |
| 12111 | if (rootDocument != editableDoc) { |
| 12112 | dom.bind(rootDocument, 'mousemove', resizeGhostElement); |
| 12113 | dom.bind(rootDocument, 'mouseup', endGhostResize); |
| 12114 | } |
| 12115 | } |
| 12116 | |
| 12117 | if (mouseDownHandleName) { |
| 12118 | // Drag started by IE native resizestart |
| 12119 | if (name == mouseDownHandleName) { |
| 12120 | startDrag(mouseDownEvent); |
| 12121 | } |
| 12122 | |
| 12123 | return; |
| 12124 | } |
| 12125 | |
| 12126 | // Get existing or render resize handle |
| 12127 | handleElm = dom.get('mceResizeHandle' + name); |
| 12128 | if (!handleElm) { |
| 12129 | handlerContainerElm = editor.getBody(); |
| 12130 | |
| 12131 | handleElm = dom.add(handlerContainerElm, 'div', { |
| 12132 | id: 'mceResizeHandle' + name, |
| 12133 | 'data-mce-bogus': true, |
| 12134 | 'class': 'mce-resizehandle', |
| 12135 | contentEditable: false, // Hides IE move layer cursor |
| 12136 | unSelectabe: true, |
| 12137 | style: 'cursor:' + name + '-resize; margin:0; padding:0' |
| 12138 | }); |
| 12139 | |
| 12140 | dom.bind(handleElm, 'mousedown', function(e) { |
| 12141 | e.preventDefault(); |
| 12142 | startDrag(e); |
| 12143 | }); |
| 12144 | } else { |
| 12145 | dom.show(handleElm); |
| 12146 | } |
| 12147 | |
| 12148 | /* |
| 12149 | var halfHandleW = handleElm.offsetWidth / 2; |
| 12150 | var halfHandleH = handleElm.offsetHeight / 2; |
| 12151 | |
| 12152 | // Position element |
| 12153 | dom.setStyles(handleElm, { |
| 12154 | left: Math.floor((targetWidth * handle[0] + selectedElmX) - halfHandleW + (handle[2] * halfHandleW)), |
| 12155 | top: Math.floor((targetHeight * handle[1] + selectedElmY) - halfHandleH + (handle[3] * halfHandleH)) |
| 12156 | }); |
| 12157 | */ |
| 12158 | |
| 12159 | // Position element |
| 12160 | dom.setStyles(handleElm, { |
| 12161 | left: (targetWidth * handle[0] + selectedElmX) - (handleElm.offsetWidth / 2), |
| 12162 | top: (targetHeight * handle[1] + selectedElmY) - (handleElm.offsetHeight / 2) |
| 12163 | }); |
| 12164 | }); |
| 12165 | } else { |
| 12166 | hideResizeRect(); |
| 12167 | } |
| 12168 | |
| 12169 | selectedElm.setAttribute('data-mce-selected', '1'); |
| 12170 | } |
| 12171 | |
| 12172 | function hideResizeRect() { |
| 12173 | var name, handleElm; |
| 12174 | |
| 12175 | if (selectedElm) { |
| 12176 | selectedElm.removeAttribute('data-mce-selected'); |
| 12177 | } |
| 12178 | |
| 12179 | for (name in resizeHandles) { |
| 12180 | handleElm = dom.get('mceResizeHandle' + name); |
| 12181 | if (handleElm) { |
| 12182 | dom.unbind(handleElm); |
| 12183 | dom.remove(handleElm); |
| 12184 | } |
| 12185 | } |
| 12186 | } |
| 12187 | |
| 12188 | function updateResizeRect(e) { |
| 12189 | var controlElm; |
| 12190 | |
| 12191 | function isChildOrEqual(node, parent) { |
| 12192 | do { |
| 12193 | if (node === parent) { |
| 12194 | return true; |
| 12195 | } |
| 12196 | } while ((node = node.parentNode)); |
| 12197 | } |
| 12198 | |
| 12199 | // Remove data-mce-selected from all elements since they might have been copied using Ctrl+c/v |
| 12200 | each(dom.select('img[data-mce-selected],hr[data-mce-selected]'), function(img) { |
| 12201 | img.removeAttribute('data-mce-selected'); |
| 12202 | }); |
| 12203 | |
| 12204 | controlElm = e.type == 'mousedown' ? e.target : selection.getNode(); |
| 12205 | controlElm = dom.getParent(controlElm, isIE ? 'table' : 'table,img,hr'); |
| 12206 | |
| 12207 | if (controlElm) { |
| 12208 | disableGeckoResize(); |
| 12209 | |
| 12210 | if (isChildOrEqual(selection.getStart(), controlElm) && isChildOrEqual(selection.getEnd(), controlElm)) { |
| 12211 | if (!isIE || (controlElm != selection.getStart() && selection.getStart().nodeName !== 'IMG')) { |
| 12212 | showResizeRect(controlElm); |
| 12213 | return; |
| 12214 | } |
| 12215 | } |
| 12216 | } |
| 12217 | |
| 12218 | hideResizeRect(); |
| 12219 | } |
| 12220 | |
| 12221 | function attachEvent(elm, name, func) { |
| 12222 | if (elm && elm.attachEvent) { |
| 12223 | elm.attachEvent('on' + name, func); |
| 12224 | } |
| 12225 | } |
| 12226 | |
| 12227 | function detachEvent(elm, name, func) { |
| 12228 | if (elm && elm.detachEvent) { |
| 12229 | elm.detachEvent('on' + name, func); |
| 12230 | } |
| 12231 | } |
| 12232 | |
| 12233 | function resizeNativeStart(e) { |
| 12234 | var target = e.srcElement, pos, name, corner, cornerX, cornerY, relativeX, relativeY; |
| 12235 | |
| 12236 | pos = target.getBoundingClientRect(); |
| 12237 | relativeX = lastMouseDownEvent.clientX - pos.left; |
| 12238 | relativeY = lastMouseDownEvent.clientY - pos.top; |
| 12239 | |
| 12240 | // Figure out what corner we are draging on |
| 12241 | for (name in resizeHandles) { |
| 12242 | corner = resizeHandles[name]; |
| 12243 | |
| 12244 | cornerX = target.offsetWidth * corner[0]; |
| 12245 | cornerY = target.offsetHeight * corner[1]; |
| 12246 | |
| 12247 | if (Math.abs(cornerX - relativeX) < 8 && Math.abs(cornerY - relativeY) < 8) { |
| 12248 | selectedHandle = corner; |
| 12249 | break; |
| 12250 | } |
| 12251 | } |
| 12252 | |
| 12253 | // Remove native selection and let the magic begin |
| 12254 | resizeStarted = true; |
| 12255 | editor.getDoc().selection.empty(); |
| 12256 | showResizeRect(target, name, lastMouseDownEvent); |
| 12257 | } |
| 12258 | |
| 12259 | function nativeControlSelect(e) { |
| 12260 | var target = e.srcElement; |
| 12261 | |
| 12262 | if (target != selectedElm) { |
| 12263 | detachResizeStartListener(); |
| 12264 | |
| 12265 | if (target.id.indexOf('mceResizeHandle') === 0) { |
| 12266 | e.returnValue = false; |
| 12267 | return; |
| 12268 | } |
| 12269 | |
| 12270 | if (target.nodeName == 'IMG' || target.nodeName == 'TABLE') { |
| 12271 | hideResizeRect(); |
| 12272 | selectedElm = target; |
| 12273 | attachEvent(target, 'resizestart', resizeNativeStart); |
| 12274 | } |
| 12275 | } |
| 12276 | } |
| 12277 | |
| 12278 | function detachResizeStartListener() { |
| 12279 | detachEvent(selectedElm, 'resizestart', resizeNativeStart); |
| 12280 | } |
| 12281 | |
| 12282 | function disableGeckoResize() { |
| 12283 | try { |
| 12284 | // Disable object resizing on Gecko |
| 12285 | editor.getDoc().execCommand('enableObjectResizing', false, false); |
| 12286 | } catch (ex) { |
| 12287 | // Ignore |
| 12288 | } |
| 12289 | } |
| 12290 | |
| 12291 | function controlSelect(elm) { |
| 12292 | var ctrlRng; |
| 12293 | |
| 12294 | if (!isIE) { |
| 12295 | return; |
| 12296 | } |
| 12297 | |
| 12298 | ctrlRng = editableDoc.body.createControlRange(); |
| 12299 | |
| 12300 | try { |
| 12301 | ctrlRng.addElement(elm); |
| 12302 | ctrlRng.select(); |
| 12303 | return true; |
| 12304 | } catch (ex) { |
| 12305 | // Ignore since the element can't be control selected for example a P tag |
| 12306 | } |
| 12307 | } |
| 12308 | |
| 12309 | editor.on('init', function() { |
| 12310 | if (isIE) { |
| 12311 | // Hide the resize rect on resize and reselect the image |
| 12312 | editor.on('ObjectResized', function(e) { |
| 12313 | if (e.target.nodeName != 'TABLE') { |
| 12314 | hideResizeRect(); |
| 12315 | controlSelect(e.target); |
| 12316 | } |
| 12317 | }); |
| 12318 | |
| 12319 | attachEvent(editor.getBody(), 'controlselect', nativeControlSelect); |
| 12320 | |
| 12321 | editor.on('mousedown', function(e) { |
| 12322 | lastMouseDownEvent = e; |
| 12323 | }); |
| 12324 | } else { |
| 12325 | disableGeckoResize(); |
| 12326 | |
| 12327 | if (Env.ie >= 11) { |
| 12328 | // TODO: Drag/drop doesn't work |
| 12329 | editor.on('mouseup', function(e) { |
| 12330 | var nodeName = e.target.nodeName; |
| 12331 | |
| 12332 | if (/^(TABLE|IMG|HR)$/.test(nodeName)) { |
| 12333 | editor.selection.select(e.target, nodeName == 'TABLE'); |
| 12334 | editor.nodeChanged(); |
| 12335 | } |
| 12336 | }); |
| 12337 | |
| 12338 | editor.dom.bind(editor.getBody(), 'mscontrolselect', function(e) { |
| 12339 | if (/^(TABLE|IMG|HR)$/.test(e.target.nodeName)) { |
| 12340 | e.preventDefault(); |
| 12341 | } |
| 12342 | }); |
| 12343 | } |
| 12344 | } |
| 12345 | |
| 12346 | editor.on('nodechange mousedown mouseup ResizeEditor', updateResizeRect); |
| 12347 | |
| 12348 | // Update resize rect while typing in a table |
| 12349 | editor.on('keydown keyup', function(e) { |
| 12350 | if (selectedElm && selectedElm.nodeName == "TABLE") { |
| 12351 | updateResizeRect(e); |
| 12352 | } |
| 12353 | }); |
| 12354 | |
| 12355 | // Hide rect on focusout since it would float on top of windows otherwise |
| 12356 | //editor.on('focusout', hideResizeRect); |
| 12357 | }); |
| 12358 | |
| 12359 | function destroy() { |
| 12360 | selectedElm = selectedElmGhost = null; |
| 12361 | |
| 12362 | if (isIE) { |
| 12363 | detachResizeStartListener(); |
| 12364 | detachEvent(editor.getBody(), 'controlselect', nativeControlSelect); |
| 12365 | } |
| 12366 | } |
| 12367 | |
| 12368 | return { |
| 12369 | controlSelect: controlSelect, |
| 12370 | destroy: destroy |
| 12371 | }; |
| 12372 | }; |
| 12373 | }); |
| 12374 | |
| 12375 | // Included from: js/tinymce/classes/dom/Selection.js |
| 12376 | |
| 12377 | /** |
| 12378 | * Selection.js |
| 12379 | * |
| 12380 | * Copyright, Moxiecode Systems AB |
| 12381 | * Released under LGPL License. |
| 12382 | * |
| 12383 | * License: http://www.tinymce.com/license |
| 12384 | * Contributing: http://www.tinymce.com/contributing |
| 12385 | */ |
| 12386 | |
| 12387 | /** |
| 12388 | * This class handles text and control selection it's an crossbrowser utility class. |
| 12389 | * Consult the TinyMCE Wiki API for more details and examples on how to use this class. |
| 12390 | * |
| 12391 | * @class tinymce.dom.Selection |
| 12392 | * @example |
| 12393 | * // Getting the currently selected node for the active editor |
| 12394 | * alert(tinymce.activeEditor.selection.getNode().nodeName); |
| 12395 | */ |
| 12396 | define("tinymce/dom/Selection", [ |
| 12397 | "tinymce/dom/TreeWalker", |
| 12398 | "tinymce/dom/TridentSelection", |
| 12399 | "tinymce/dom/ControlSelection", |
| 12400 | "tinymce/Env", |
| 12401 | "tinymce/util/Tools" |
| 12402 | ], function(TreeWalker, TridentSelection, ControlSelection, Env, Tools) { |
| 12403 | var each = Tools.each, grep = Tools.grep, trim = Tools.trim; |
| 12404 | var isIE = Env.ie, isOpera = Env.opera; |
| 12405 | |
| 12406 | /** |
| 12407 | * Constructs a new selection instance. |
| 12408 | * |
| 12409 | * @constructor |
| 12410 | * @method Selection |
| 12411 | * @param {tinymce.dom.DOMUtils} dom DOMUtils object reference. |
| 12412 | * @param {Window} win Window to bind the selection object to. |
| 12413 | * @param {tinymce.dom.Serializer} serializer DOM serialization class to use for getContent. |
| 12414 | */ |
| 12415 | function Selection(dom, win, serializer, editor) { |
| 12416 | var self = this; |
| 12417 | |
| 12418 | self.dom = dom; |
| 12419 | self.win = win; |
| 12420 | self.serializer = serializer; |
| 12421 | self.editor = editor; |
| 12422 | |
| 12423 | self.controlSelection = new ControlSelection(self, editor); |
| 12424 | |
| 12425 | // No W3C Range support |
| 12426 | if (!self.win.getSelection) { |
| 12427 | self.tridentSel = new TridentSelection(self); |
| 12428 | } |
| 12429 | } |
| 12430 | |
| 12431 | Selection.prototype = { |
| 12432 | /** |
| 12433 | * Move the selection cursor range to the specified node and offset. |
| 12434 | * If there is no node specified it will move it to the first suitable location within the body. |
| 12435 | * |
| 12436 | * @method setCursorLocation |
| 12437 | * @param {Node} node Optional node to put the cursor in. |
| 12438 | * @param {Number} offset Optional offset from the start of the node to put the cursor at. |
| 12439 | */ |
| 12440 | setCursorLocation: function(node, offset) { |
| 12441 | var self = this, rng = self.dom.createRng(); |
| 12442 | |
| 12443 | if (!node) { |
| 12444 | self._moveEndPoint(rng, self.editor.getBody(), true); |
| 12445 | self.setRng(rng); |
| 12446 | } else { |
| 12447 | rng.setStart(node, offset); |
| 12448 | rng.setEnd(node, offset); |
| 12449 | self.setRng(rng); |
| 12450 | self.collapse(false); |
| 12451 | } |
| 12452 | }, |
| 12453 | |
| 12454 | /** |
| 12455 | * Returns the selected contents using the DOM serializer passed in to this class. |
| 12456 | * |
| 12457 | * @method getContent |
| 12458 | * @param {Object} s Optional settings class with for example output format text or html. |
| 12459 | * @return {String} Selected contents in for example HTML format. |
| 12460 | * @example |
| 12461 | * // Alerts the currently selected contents |
| 12462 | * alert(tinymce.activeEditor.selection.getContent()); |
| 12463 | * |
| 12464 | * // Alerts the currently selected contents as plain text |
| 12465 | * alert(tinymce.activeEditor.selection.getContent({format: 'text'})); |
| 12466 | */ |
| 12467 | getContent: function(args) { |
| 12468 | var self = this, rng = self.getRng(), tmpElm = self.dom.create("body"); |
| 12469 | var se = self.getSel(), whiteSpaceBefore, whiteSpaceAfter, fragment; |
| 12470 | |
| 12471 | args = args || {}; |
| 12472 | whiteSpaceBefore = whiteSpaceAfter = ''; |
| 12473 | args.get = true; |
| 12474 | args.format = args.format || 'html'; |
| 12475 | args.selection = true; |
| 12476 | self.editor.fire('BeforeGetContent', args); |
| 12477 | |
| 12478 | if (args.format == 'text') { |
| 12479 | return self.isCollapsed() ? '' : (rng.text || (se.toString ? se.toString() : '')); |
| 12480 | } |
| 12481 | |
| 12482 | if (rng.cloneContents) { |
| 12483 | fragment = rng.cloneContents(); |
| 12484 | |
| 12485 | if (fragment) { |
| 12486 | tmpElm.appendChild(fragment); |
| 12487 | } |
| 12488 | } else if (rng.item !== undefined || rng.htmlText !== undefined) { |
| 12489 | // IE will produce invalid markup if elements are present that |
| 12490 | // it doesn't understand like custom elements or HTML5 elements. |
| 12491 | // Adding a BR in front of the contents and then remoiving it seems to fix it though. |
| 12492 | tmpElm.innerHTML = '<br>' + (rng.item ? rng.item(0).outerHTML : rng.htmlText); |
| 12493 | tmpElm.removeChild(tmpElm.firstChild); |
| 12494 | } else { |
| 12495 | tmpElm.innerHTML = rng.toString(); |
| 12496 | } |
| 12497 | |
| 12498 | // Keep whitespace before and after |
| 12499 | if (/^\s/.test(tmpElm.innerHTML)) { |
| 12500 | whiteSpaceBefore = ' '; |
| 12501 | } |
| 12502 | |
| 12503 | if (/\s+$/.test(tmpElm.innerHTML)) { |
| 12504 | whiteSpaceAfter = ' '; |
| 12505 | } |
| 12506 | |
| 12507 | args.getInner = true; |
| 12508 | |
| 12509 | args.content = self.isCollapsed() ? '' : whiteSpaceBefore + self.serializer.serialize(tmpElm, args) + whiteSpaceAfter; |
| 12510 | self.editor.fire('GetContent', args); |
| 12511 | |
| 12512 | return args.content; |
| 12513 | }, |
| 12514 | |
| 12515 | /** |
| 12516 | * Sets the current selection to the specified content. If any contents is selected it will be replaced |
| 12517 | * with the contents passed in to this function. If there is no selection the contents will be inserted |
| 12518 | * where the caret is placed in the editor/page. |
| 12519 | * |
| 12520 | * @method setContent |
| 12521 | * @param {String} content HTML contents to set could also be other formats depending on settings. |
| 12522 | * @param {Object} args Optional settings object with for example data format. |
| 12523 | * @example |
| 12524 | * // Inserts some HTML contents at the current selection |
| 12525 | * tinymce.activeEditor.selection.setContent('<strong>Some contents</strong>'); |
| 12526 | */ |
| 12527 | setContent: function(content, args) { |
| 12528 | var self = this, rng = self.getRng(), caretNode, doc = self.win.document, frag, temp; |
| 12529 | |
| 12530 | args = args || {format: 'html'}; |
| 12531 | args.set = true; |
| 12532 | args.selection = true; |
| 12533 | content = args.content = content; |
| 12534 | |
| 12535 | // Dispatch before set content event |
| 12536 | if (!args.no_events) { |
| 12537 | self.editor.fire('BeforeSetContent', args); |
| 12538 | } |
| 12539 | |
| 12540 | content = args.content; |
| 12541 | |
| 12542 | if (rng.insertNode) { |
| 12543 | // Make caret marker since insertNode places the caret in the beginning of text after insert |
| 12544 | content += '<span id="__caret">_</span>'; |
| 12545 | |
| 12546 | // Delete and insert new node |
| 12547 | if (rng.startContainer == doc && rng.endContainer == doc) { |
| 12548 | // WebKit will fail if the body is empty since the range is then invalid and it can't insert contents |
| 12549 | doc.body.innerHTML = content; |
| 12550 | } else { |
| 12551 | rng.deleteContents(); |
| 12552 | |
| 12553 | if (doc.body.childNodes.length === 0) { |
| 12554 | doc.body.innerHTML = content; |
| 12555 | } else { |
| 12556 | // createContextualFragment doesn't exists in IE 9 DOMRanges |
| 12557 | if (rng.createContextualFragment) { |
| 12558 | rng.insertNode(rng.createContextualFragment(content)); |
| 12559 | } else { |
| 12560 | // Fake createContextualFragment call in IE 9 |
| 12561 | frag = doc.createDocumentFragment(); |
| 12562 | temp = doc.createElement('div'); |
| 12563 | |
| 12564 | frag.appendChild(temp); |
| 12565 | temp.outerHTML = content; |
| 12566 | |
| 12567 | rng.insertNode(frag); |
| 12568 | } |
| 12569 | } |
| 12570 | } |
| 12571 | |
| 12572 | // Move to caret marker |
| 12573 | caretNode = self.dom.get('__caret'); |
| 12574 | |
| 12575 | // Make sure we wrap it compleatly, Opera fails with a simple select call |
| 12576 | rng = doc.createRange(); |
| 12577 | rng.setStartBefore(caretNode); |
| 12578 | rng.setEndBefore(caretNode); |
| 12579 | self.setRng(rng); |
| 12580 | |
| 12581 | // Remove the caret position |
| 12582 | self.dom.remove('__caret'); |
| 12583 | |
| 12584 | try { |
| 12585 | self.setRng(rng); |
| 12586 | } catch (ex) { |
| 12587 | // Might fail on Opera for some odd reason |
| 12588 | } |
| 12589 | } else { |
| 12590 | if (rng.item) { |
| 12591 | // Delete content and get caret text selection |
| 12592 | doc.execCommand('Delete', false, null); |
| 12593 | rng = self.getRng(); |
| 12594 | } |
| 12595 | |
| 12596 | // Explorer removes spaces from the beginning of pasted contents |
| 12597 | if (/^\s+/.test(content)) { |
| 12598 | rng.pasteHTML('<span id="__mce_tmp">_</span>' + content); |
| 12599 | self.dom.remove('__mce_tmp'); |
| 12600 | } else { |
| 12601 | rng.pasteHTML(content); |
| 12602 | } |
| 12603 | } |
| 12604 | |
| 12605 | // Dispatch set content event |
| 12606 | if (!args.no_events) { |
| 12607 | self.editor.fire('SetContent', args); |
| 12608 | } |
| 12609 | }, |
| 12610 | |
| 12611 | /** |
| 12612 | * Returns the start element of a selection range. If the start is in a text |
| 12613 | * node the parent element will be returned. |
| 12614 | * |
| 12615 | * @method getStart |
| 12616 | * @return {Element} Start element of selection range. |
| 12617 | */ |
| 12618 | getStart: function() { |
| 12619 | var self = this, rng = self.getRng(), startElement, parentElement, checkRng, node; |
| 12620 | |
| 12621 | if (rng.duplicate || rng.item) { |
| 12622 | // Control selection, return first item |
| 12623 | if (rng.item) { |
| 12624 | return rng.item(0); |
| 12625 | } |
| 12626 | |
| 12627 | // Get start element |
| 12628 | checkRng = rng.duplicate(); |
| 12629 | checkRng.collapse(1); |
| 12630 | startElement = checkRng.parentElement(); |
| 12631 | if (startElement.ownerDocument !== self.dom.doc) { |
| 12632 | startElement = self.dom.getRoot(); |
| 12633 | } |
| 12634 | |
| 12635 | // Check if range parent is inside the start element, then return the inner parent element |
| 12636 | // This will fix issues when a single element is selected, IE would otherwise return the wrong start element |
| 12637 | parentElement = node = rng.parentElement(); |
| 12638 | while ((node = node.parentNode)) { |
| 12639 | if (node == startElement) { |
| 12640 | startElement = parentElement; |
| 12641 | break; |
| 12642 | } |
| 12643 | } |
| 12644 | |
| 12645 | return startElement; |
| 12646 | } else { |
| 12647 | startElement = rng.startContainer; |
| 12648 | |
| 12649 | if (startElement.nodeType == 1 && startElement.hasChildNodes()) { |
| 12650 | startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)]; |
| 12651 | } |
| 12652 | |
| 12653 | if (startElement && startElement.nodeType == 3) { |
| 12654 | return startElement.parentNode; |
| 12655 | } |
| 12656 | |
| 12657 | return startElement; |
| 12658 | } |
| 12659 | }, |
| 12660 | |
| 12661 | /** |
| 12662 | * Returns the end element of a selection range. If the end is in a text |
| 12663 | * node the parent element will be returned. |
| 12664 | * |
| 12665 | * @method getEnd |
| 12666 | * @return {Element} End element of selection range. |
| 12667 | */ |
| 12668 | getEnd: function() { |
| 12669 | var self = this, rng = self.getRng(), endElement, endOffset; |
| 12670 | |
| 12671 | if (rng.duplicate || rng.item) { |
| 12672 | if (rng.item) { |
| 12673 | return rng.item(0); |
| 12674 | } |
| 12675 | |
| 12676 | rng = rng.duplicate(); |
| 12677 | rng.collapse(0); |
| 12678 | endElement = rng.parentElement(); |
| 12679 | if (endElement.ownerDocument !== self.dom.doc) { |
| 12680 | endElement = self.dom.getRoot(); |
| 12681 | } |
| 12682 | |
| 12683 | if (endElement && endElement.nodeName == 'BODY') { |
| 12684 | return endElement.lastChild || endElement; |
| 12685 | } |
| 12686 | |
| 12687 | return endElement; |
| 12688 | } else { |
| 12689 | endElement = rng.endContainer; |
| 12690 | endOffset = rng.endOffset; |
| 12691 | |
| 12692 | if (endElement.nodeType == 1 && endElement.hasChildNodes()) { |
| 12693 | endElement = endElement.childNodes[endOffset > 0 ? endOffset - 1 : endOffset]; |
| 12694 | } |
| 12695 | |
| 12696 | if (endElement && endElement.nodeType == 3) { |
| 12697 | return endElement.parentNode; |
| 12698 | } |
| 12699 | |
| 12700 | return endElement; |
| 12701 | } |
| 12702 | }, |
| 12703 | |
| 12704 | /** |
| 12705 | * Returns a bookmark location for the current selection. This bookmark object |
| 12706 | * can then be used to restore the selection after some content modification to the document. |
| 12707 | * |
| 12708 | * @method getBookmark |
| 12709 | * @param {Number} type Optional state if the bookmark should be simple or not. Default is complex. |
| 12710 | * @param {Boolean} normalized Optional state that enables you to get a position that it would be after normalization. |
| 12711 | * @return {Object} Bookmark object, use moveToBookmark with this object to restore the selection. |
| 12712 | * @example |
| 12713 | * // Stores a bookmark of the current selection |
| 12714 | * var bm = tinymce.activeEditor.selection.getBookmark(); |
| 12715 | * |
| 12716 | * tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + 'Some new content'); |
| 12717 | * |
| 12718 | * // Restore the selection bookmark |
| 12719 | * tinymce.activeEditor.selection.moveToBookmark(bm); |
| 12720 | */ |
| 12721 | getBookmark: function(type, normalized) { |
| 12722 | var t = this, dom = t.dom, rng, rng2, id, collapsed, name, element, chr = '', styles; |
| 12723 | |
| 12724 | function findIndex(name, element) { |
| 12725 | var index = 0; |
| 12726 | |
| 12727 | each(dom.select(name), function(node, i) { |
| 12728 | if (node == element) { |
| 12729 | index = i; |
| 12730 | } |
| 12731 | }); |
| 12732 | |
| 12733 | return index; |
| 12734 | } |
| 12735 | |
| 12736 | function normalizeTableCellSelection(rng) { |
| 12737 | function moveEndPoint(start) { |
| 12738 | var container, offset, childNodes, prefix = start ? 'start' : 'end'; |
| 12739 | |
| 12740 | container = rng[prefix + 'Container']; |
| 12741 | offset = rng[prefix + 'Offset']; |
| 12742 | |
| 12743 | if (container.nodeType == 1 && container.nodeName == "TR") { |
| 12744 | childNodes = container.childNodes; |
| 12745 | container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)]; |
| 12746 | if (container) { |
| 12747 | offset = start ? 0 : container.childNodes.length; |
| 12748 | rng['set' + (start ? 'Start' : 'End')](container, offset); |
| 12749 | } |
| 12750 | } |
| 12751 | } |
| 12752 | |
| 12753 | moveEndPoint(true); |
| 12754 | moveEndPoint(); |
| 12755 | |
| 12756 | return rng; |
| 12757 | } |
| 12758 | |
| 12759 | function getLocation() { |
| 12760 | var rng = t.getRng(true), root = dom.getRoot(), bookmark = {}; |
| 12761 | |
| 12762 | function getPoint(rng, start) { |
| 12763 | var container = rng[start ? 'startContainer' : 'endContainer'], |
| 12764 | offset = rng[start ? 'startOffset' : 'endOffset'], point = [], node, childNodes, after = 0; |
| 12765 | |
| 12766 | if (container.nodeType == 3) { |
| 12767 | if (normalized) { |
| 12768 | for (node = container.previousSibling; node && node.nodeType == 3; node = node.previousSibling) { |
| 12769 | offset += node.nodeValue.length; |
| 12770 | } |
| 12771 | } |
| 12772 | |
| 12773 | point.push(offset); |
| 12774 | } else { |
| 12775 | childNodes = container.childNodes; |
| 12776 | |
| 12777 | if (offset >= childNodes.length && childNodes.length) { |
| 12778 | after = 1; |
| 12779 | offset = Math.max(0, childNodes.length - 1); |
| 12780 | } |
| 12781 | |
| 12782 | point.push(t.dom.nodeIndex(childNodes[offset], normalized) + after); |
| 12783 | } |
| 12784 | |
| 12785 | for (; container && container != root; container = container.parentNode) { |
| 12786 | point.push(t.dom.nodeIndex(container, normalized)); |
| 12787 | } |
| 12788 | |
| 12789 | return point; |
| 12790 | } |
| 12791 | |
| 12792 | bookmark.start = getPoint(rng, true); |
| 12793 | |
| 12794 | if (!t.isCollapsed()) { |
| 12795 | bookmark.end = getPoint(rng); |
| 12796 | } |
| 12797 | |
| 12798 | return bookmark; |
| 12799 | } |
| 12800 | |
| 12801 | if (type == 2) { |
| 12802 | element = t.getNode(); |
| 12803 | name = element.nodeName; |
| 12804 | |
| 12805 | if (name == 'IMG') { |
| 12806 | return {name: name, index: findIndex(name, element)}; |
| 12807 | } |
| 12808 | |
| 12809 | if (t.tridentSel) { |
| 12810 | return t.tridentSel.getBookmark(type); |
| 12811 | } |
| 12812 | |
| 12813 | return getLocation(); |
| 12814 | } |
| 12815 | |
| 12816 | // Handle simple range |
| 12817 | if (type) { |
| 12818 | return {rng: t.getRng()}; |
| 12819 | } |
| 12820 | |
| 12821 | rng = t.getRng(); |
| 12822 | id = dom.uniqueId(); |
| 12823 | collapsed = t.isCollapsed(); |
| 12824 | styles = 'overflow:hidden;line-height:0px'; |
| 12825 | |
| 12826 | // Explorer method |
| 12827 | if (rng.duplicate || rng.item) { |
| 12828 | // Text selection |
| 12829 | if (!rng.item) { |
| 12830 | rng2 = rng.duplicate(); |
| 12831 | |
| 12832 | try { |
| 12833 | // Insert start marker |
| 12834 | rng.collapse(); |
| 12835 | rng.pasteHTML('<span data-mce-type="bookmark" id="' + id + '_start" style="' + styles + '">' + chr + '</span>'); |
| 12836 | |
| 12837 | // Insert end marker |
| 12838 | if (!collapsed) { |
| 12839 | rng2.collapse(false); |
| 12840 | |
| 12841 | // Detect the empty space after block elements in IE and move the |
| 12842 | // end back one character <p></p>] becomes <p>]</p> |
| 12843 | rng.moveToElementText(rng2.parentElement()); |
| 12844 | if (rng.compareEndPoints('StartToEnd', rng2) === 0) { |
| 12845 | rng2.move('character', -1); |
| 12846 | } |
| 12847 | |
| 12848 | rng2.pasteHTML('<span data-mce-type="bookmark" id="' + id + '_end" style="' + styles + '">' + chr + '</span>'); |
| 12849 | } |
| 12850 | } catch (ex) { |
| 12851 | // IE might throw unspecified error so lets ignore it |
| 12852 | return null; |
| 12853 | } |
| 12854 | } else { |
| 12855 | // Control selection |
| 12856 | element = rng.item(0); |
| 12857 | name = element.nodeName; |
| 12858 | |
| 12859 | return {name: name, index: findIndex(name, element)}; |
| 12860 | } |
| 12861 | } else { |
| 12862 | element = t.getNode(); |
| 12863 | name = element.nodeName; |
| 12864 | if (name == 'IMG') { |
| 12865 | return {name: name, index: findIndex(name, element)}; |
| 12866 | } |
| 12867 | |
| 12868 | // W3C method |
| 12869 | rng2 = normalizeTableCellSelection(rng.cloneRange()); |
| 12870 | |
| 12871 | // Insert end marker |
| 12872 | if (!collapsed) { |
| 12873 | rng2.collapse(false); |
| 12874 | rng2.insertNode(dom.create('span', {'data-mce-type': "bookmark", id: id + '_end', style: styles}, chr)); |
| 12875 | } |
| 12876 | |
| 12877 | rng = normalizeTableCellSelection(rng); |
| 12878 | rng.collapse(true); |
| 12879 | rng.insertNode(dom.create('span', {'data-mce-type': "bookmark", id: id + '_start', style: styles}, chr)); |
| 12880 | } |
| 12881 | |
| 12882 | t.moveToBookmark({id: id, keep: 1}); |
| 12883 | |
| 12884 | return {id: id}; |
| 12885 | }, |