xheditor-1.1.14-zh-cn.js 95 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293
  1. /*!
  2. * xhEditor - WYSIWYG XHTML Editor
  3. * @requires jQuery v1.4.4
  4. *
  5. * @author Yanis.Wang<yanis.wang@gmail.com>
  6. * @site http://xheditor.com/
  7. * @licence LGPL(http://xheditor.com/license/lgpl.txt)
  8. *
  9. * @Version: 1.1.14 (build 120701)
  10. */
  11. (function($,undefined){
  12. if(window.xheditor)return false;//防止JS重复加载
  13. var agent=navigator.userAgent.toLowerCase();
  14. var bMobile=agent.indexOf('mobile')!==-1,browser=$.browser,browerVer=parseFloat(browser.version),isIE=browser.msie,isMozilla=browser.mozilla,isSafari=browser.safari,isOpera=browser.opera;
  15. var bAir=agent.indexOf(' adobeair/')>-1;
  16. var bIOS5=/OS 5(_\d)+ like Mac OS X/i.test(agent);
  17. $.fn.xheditor=function(options)
  18. {
  19. if(bMobile&&!bIOS5)return false;//手机浏览器不初始化编辑器(IOS5除外)
  20. var arrSuccess=[];
  21. this.each(function(){
  22. if(!$.nodeName(this,'TEXTAREA'))return;
  23. if(options===false)//卸载
  24. {
  25. if(this.xheditor)
  26. {
  27. this.xheditor.remove();
  28. this.xheditor=null;
  29. }
  30. }
  31. else//初始化
  32. {
  33. if(!this.xheditor)
  34. {
  35. var tOptions=/({.*})/.exec($(this).attr('class'));
  36. if(tOptions)
  37. {
  38. try{tOptions=eval('('+tOptions[1]+')');}catch(ex){};
  39. options=$.extend({},tOptions,options );
  40. }
  41. var editor=new xheditor(this,options);
  42. if(editor.init())
  43. {
  44. this.xheditor=editor;
  45. arrSuccess.push(editor);
  46. }
  47. else editor=null;
  48. }
  49. else arrSuccess.push(this.xheditor);
  50. }
  51. });
  52. if(arrSuccess.length===0)arrSuccess=false;
  53. if(arrSuccess.length===1)arrSuccess=arrSuccess[0];
  54. return arrSuccess;
  55. }
  56. var xCount=0,bShowPanel=false,bClickCancel=true,bShowModal=false,bCheckEscInit=false;
  57. var _jPanel,_jShadow,_jCntLine,_jPanelButton;
  58. var jModal,jModalShadow,layerShadow,jOverlay,jHideSelect,onModalRemove;
  59. var editorRoot;
  60. $('script[src*=xheditor]').each(function(){
  61. var s=this.src;
  62. if(s.match(/xheditor[^\/]*\.js/i)){editorRoot=s.replace(/[\?#].*$/, '').replace(/(^|[\/\\])[^\/]*$/, '$1');return false;}
  63. });
  64. if(isIE){
  65. //ie6 缓存背景图片
  66. try{document.execCommand('BackgroundImageCache', false, true );}
  67. catch(e){}
  68. //修正 jquery 1.6,1.7系列在IE6浏览器下造成width="auto"问题的修正
  69. var jqueryVer=$.fn.jquery;
  70. if(jqueryVer&&jqueryVer.match(/^1\.[67]/))$.attrHooks['width']=$.attrHooks['height']=null;
  71. }
  72. var specialKeys={ 27: 'esc', 9: 'tab', 32:'space', 13: 'enter', 8:'backspace', 145: 'scroll',
  73. 20: 'capslock', 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',
  74. 35:'end', 33: 'pageup', 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down',
  75. 112:'f1',113:'f2', 114:'f3', 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8', 120:'f9', 121:'f10', 122:'f11', 123:'f12' };
  76. var itemColors=['#FFFFFF','#CCCCCC','#C0C0C0','#999999','#666666','#333333','#000000','#FFCCCC','#FF6666','#FF0000','#CC0000','#990000','#660000','#330000','#FFCC99','#FF9966','#FF9900','#FF6600','#CC6600','#993300','#663300','#FFFF99','#FFFF66','#FFCC66','#FFCC33','#CC9933','#996633','#663333','#FFFFCC','#FFFF33','#FFFF00','#FFCC00','#999900','#666600','#333300','#99FF99','#66FF99','#33FF33','#33CC00','#009900','#006600','#003300','#99FFFF','#33FFFF','#66CCCC','#00CCCC','#339999','#336666','#003333','#CCFFFF','#66FFFF','#33CCFF','#3366FF','#3333FF','#000099','#000066','#CCCCFF','#9999FF','#6666CC','#6633FF','#6600CC','#333399','#330099','#FFCCFF','#FF99FF','#CC66CC','#CC33CC','#993399','#663366','#330033'];
  77. var arrBlocktag=[{n:'p',t:'普通段落'},{n:'h1',t:'标题1'},{n:'h2',t:'标题2'},{n:'h3',t:'标题3'},{n:'h4',t:'标题4'},{n:'h5',t:'标题5'},{n:'h6',t:'标题6'},{n:'pre',t:'已编排格式'},{n:'address',t:'地址'}];
  78. var arrFontname=[{n:'宋体',c:'SimSun'},{n:'仿宋体',c:'FangSong_GB2312'},{n:'黑体',c:'SimHei'},{n:'楷体',c:'KaiTi_GB2312'},{n:'微软雅黑',c:'Microsoft YaHei'},{n:'Arial'},{n:'Arial Black'},{n:'Comic Sans MS'},{n:'Courier New'},{n:'System'},{n:'Times New Roman'},{n:'Tahoma'},{n:'Verdana'}];
  79. var arrFontsize=[{n:'x-small',s:'10px',t:'极小'},{n:'small',s:'12px',t:'特小'},{n:'medium',s:'16px',t:'小'},{n:'large',s:'18px',t:'中'},{n:'x-large',s:'24px',t:'大'},{n:'xx-large',s:'32px',t:'特大'},{n:'-webkit-xxx-large',s:'48px',t:'极大'}];
  80. var menuAlign=[{s:'左对齐',v:'justifyleft'},{s:'居中',v:'justifycenter'},{s:'右对齐',v:'justifyright'},{s:'两端对齐',v:'justifyfull'}],menuList=[{s:'数字列表',v:'insertOrderedList'},{s:'符号列表',v:'insertUnorderedList'}];
  81. var htmlPastetext='<div><label for="xhePastetextValue">使用键盘快捷键(Ctrl+V)把内容粘贴到方框里,按 确定</label></div><div><textarea id="xhePastetextValue" wrap="soft" spellcheck="false" style="width:300px;height:100px;" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  82. var htmlLink='<div><label for="xheLinkUrl">链接地址: </label><input type="text" id="xheLinkUrl" value="http://" class="xheText" /></div><div><label for="xheLinkTarget">打开方式: </label><select id="xheLinkTarget"><option selected="selected" value="">默认</option><option value="_blank">新窗口</option><option value="_self">当前窗口</option><option value="_parent">父窗口</option></select></div><div style="display:none"><label for="xheLinkText">链接文字: </label><input type="text" id="xheLinkText" value="" class="xheText" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  83. var htmlAnchor='<div><label for="xheAnchorName">锚点名称: </label><input type="text" id="xheAnchorName" value="" class="xheText" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  84. var htmlImg='<div><label for="xheImgUrl">图片文件: </label><input type="text" id="xheImgUrl" value="http://" class="xheText" /></div><div><div><label for="xheImgAlt">替换文本: </label><input type="text" id="xheImgAlt" /></div><div><label for="xheImgAlign">对齐方式: </label><select id="xheImgAlign"><option selected="selected" value="">默认</option><option value="left">左对齐</option><option value="right">右对齐</option><option value="top">顶端</option><option value="middle">居中</option><option value="baseline">基线</option><option value="bottom">底边</option></select></div><div><label for="xheImgWidth">宽  度: </label><input type="text" id="xheImgWidth" style="width:40px;" /> <label for="xheImgHeight">高  度: </label><input type="text" id="xheImgHeight" style="width:40px;" /></div><div><label for="xheImgBorder">边框大小: </label><input type="text" id="xheImgBorder" style="width:40px;" /></div><div><label for="xheImgHspace">水平间距: </label><input type="text" id="xheImgHspace" style="width:40px;" /> <label for="xheImgVspace">垂直间距: </label><input type="text" id="xheImgVspace" style="width:40px;" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  85. var htmlFlash='<div><label for="xheFlashUrl">动画文件: </label><input type="text" id="xheFlashUrl" value="http://" class="xheText" /></div><div><label for="xheFlashWidth">宽  度: </label><input type="text" id="xheFlashWidth" style="width:40px;" value="480" /> <label for="xheFlashHeight">高  度: </label><input type="text" id="xheFlashHeight" style="width:40px;" value="400" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  86. var htmlMedia='<div><label for="xheMediaUrl">媒体文件: </label><input type="text" id="xheMediaUrl" value="http://" class="xheText" /></div><div><label for="xheMediaWidth">宽  度: </label><input type="text" id="xheMediaWidth" style="width:40px;" value="480" /> <label for="xheMediaHeight">高  度: </label><input type="text" id="xheMediaHeight" style="width:40px;" value="400" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  87. var htmlTable='<div><label for="xheTableRows">行  数: </label><input type="text" id="xheTableRows" style="width:40px;" value="3" /> <label for="xheTableColumns">列  数: </label><input type="text" id="xheTableColumns" style="width:40px;" value="2" /></div><div><label for="xheTableHeaders">标题单元: </label><select id="xheTableHeaders"><option selected="selected" value="">无</option><option value="row">第一行</option><option value="col">第一列</option><option value="both">第一行和第一列</option></select></div><div><label for="xheTableWidth">宽  度: </label><input type="text" id="xheTableWidth" style="width:40px;" value="200" /> <label for="xheTableHeight">高  度: </label><input type="text" id="xheTableHeight" style="width:40px;" value="" /></div><div><label for="xheTableBorder">边框大小: </label><input type="text" id="xheTableBorder" style="width:40px;" value="1" /></div><div><label for="xheTableCellSpacing">表格间距: </label><input type="text" id="xheTableCellSpacing" style="width:40px;" value="1" /> <label for="xheTableCellPadding">表格填充: </label><input type="text" id="xheTableCellPadding" style="width:40px;" value="1" /></div><div><label for="xheTableAlign">对齐方式: </label><select id="xheTableAlign"><option selected="selected" value="">默认</option><option value="left">左对齐</option><option value="center">居中</option><option value="right">右对齐</option></select></div><div><label for="xheTableCaption">表格标题: </label><input type="text" id="xheTableCaption" /></div><div style="text-align:right;"><input type="button" id="xheSave" value="确定" /></div>';
  88. var htmlAbout='<div style="font:12px Arial;width:245px;word-wrap:break-word;word-break:break-all;outline:none;" role="dialog" tabindex="-1"><p><span style="font-size:20px;color:#1997DF;">xhEditor</span><br />v1.1.14 (build 120701)</p><p>xhEditor是基于jQuery开发的跨平台轻量可视化XHTML编辑器,基于<a href="http://www.gnu.org/licenses/lgpl.html" target="_blank">LGPL</a>开源协议发布。</p><p>Copyright &copy; <a href="http://xheditor.com/" target="_blank">xhEditor.com</a>. All rights reserved.</p></div>';
  89. var itemEmots={'default':{name:'默认',width:24,height:24,line:7,list:{'smile':'微笑','tongue':'吐舌头','titter':'偷笑','laugh':'大笑','sad':'难过','wronged':'委屈','fastcry':'快哭了','cry':'哭','wail':'大哭','mad':'生气','knock':'敲打','curse':'骂人','crazy':'抓狂','angry':'发火','ohmy':'惊讶','awkward':'尴尬','panic':'惊恐','shy':'害羞','cute':'可怜','envy':'羡慕','proud':'得意','struggle':'奋斗','quiet':'安静','shutup':'闭嘴','doubt':'疑问','despise':'鄙视','sleep':'睡觉','bye':'再见'}}};
  90. var arrTools={Cut:{t:'剪切 (Ctrl+X)'},Copy:{t:'复制 (Ctrl+C)'},Paste:{t:'粘贴 (Ctrl+V)'},Pastetext:{t:'粘贴文本',h:isIE?0:1},Blocktag:{t:'段落标签',h:1},Fontface:{t:'字体',h:1},FontSize:{t:'字体大小',h:1},Bold:{t:'加粗 (Ctrl+B)',s:'Ctrl+B'},Italic:{t:'斜体 (Ctrl+I)',s:'Ctrl+I'},Underline:{t:'下划线 (Ctrl+U)',s:'Ctrl+U'},Strikethrough:{t:'删除线'},FontColor:{t:'字体颜色',h:1},BackColor:{t:'背景颜色',h:1},SelectAll:{t:'全选 (Ctrl+A)'},Removeformat:{t:'删除文字格式'},Align:{t:'对齐',h:1},List:{t:'列表',h:1},Outdent:{t:'减少缩进'},Indent:{t:'增加缩进'},Link:{t:'超链接 (Ctrl+L)',s:'Ctrl+L',h:1},Unlink:{t:'取消超链接'},Anchor:{t:'锚点',h:1},Img:{t:'图片',h:1},Flash:{t:'Flash动画',h:1},Media:{t:'多媒体文件',h:1},Hr:{t:'插入水平线'},Emot:{t:'表情',s:'ctrl+e',h:1},Table:{t:'表格',h:1},Source:{t:'源代码'},Preview:{t:'预览'},Print:{t:'打印 (Ctrl+P)',s:'Ctrl+P'},Fullscreen:{t:'全屏编辑 (Esc)',s:'Esc'},About:{t:'关于 xhEditor'}};
  91. var toolsThemes={
  92. mini:'Bold,Italic,Underline,Strikethrough,|,Align,List,|,Link,Img',
  93. simple:'Blocktag,Fontface,FontSize,Bold,Italic,Underline,Strikethrough,FontColor,BackColor,|,Align,List,Outdent,Indent,|,Link,Img,Emot',
  94. full:'Cut,Copy,Paste,Pastetext,|,Blocktag,Fontface,FontSize,Bold,Italic,Underline,Strikethrough,FontColor,BackColor,SelectAll,Removeformat,|,Align,List,Outdent,Indent,|,Link,Unlink,Anchor,Img,Flash,Media,Hr,Emot,Table,|,Source,Preview,Print,Fullscreen'};
  95. toolsThemes.mfull=toolsThemes.full.replace(/\|(,Align)/i,'/$1');
  96. var arrDbClick={'a':'Link','img':'Img','embed':'Embed'},uploadInputname='filedata';
  97. var arrEntities={'<':'&lt;','>':'&gt;','"':'&quot;','®':'&reg;','©':'&copy;'};//实体
  98. var regEntities=/[<>"®©]/g;
  99. var xheditor=function(textarea,options)
  100. {
  101. var _this=this,_text=textarea,_jText=$(_text),_jForm=_jText.closest('form'),_jTools,_jArea,_win,_jWin,_doc,_jDoc;
  102. var bookmark;
  103. var bInit=false,bSource=false,bFullscreen=false,bCleanPaste=false,outerScroll,bShowBlocktag=false,sLayoutStyle='',ev=null,timer,bDisableHoverExec=false,bQuickHoverExec=false;
  104. var lastPoint=null,lastAngle=null;//鼠标悬停显示
  105. var editorHeight=0;
  106. var settings=_this.settings=$.extend({},xheditor.settings,options );
  107. var plugins=settings.plugins,strPlugins=[];
  108. if(plugins)
  109. {
  110. arrTools=$.extend({},arrTools,plugins);
  111. $.each(plugins,function(n){strPlugins.push(n);});
  112. strPlugins=strPlugins.join(',');
  113. }
  114. if(settings.tools.match(/^\s*(m?full|simple|mini)\s*$/i))
  115. {
  116. var toolsTheme=toolsThemes[$.trim(settings.tools)];
  117. settings.tools=(settings.tools.match(/m?full/i)&&plugins)?toolsTheme.replace('Table','Table,'+strPlugins):toolsTheme;//插件接在full的Table后面
  118. }
  119. //如需删除关于按钮,请往官方网站购买商业授权:http://xheditor.com/service
  120. //在未购买商业授权的情况下私自去除xhEditor的版权信息,您将得不到官方提供的任何技术支持和BUG反馈服务,并且我们将对您保留法律诉讼的权利
  121. //请支持开源项目
  122. if(!settings.tools.match(/(^|,)\s*About\s*(,|$)/i))settings.tools+=',About';
  123. settings.tools=settings.tools.split(',');
  124. if(settings.editorRoot)editorRoot=settings.editorRoot;
  125. if(bAir===false)editorRoot=getLocalUrl(editorRoot,'abs');
  126. if(settings.urlBase)settings.urlBase=getLocalUrl(settings.urlBase,'abs');
  127. //基本控件名
  128. var idCSS='xheCSS_'+settings.skin,idContainer='xhe'+xCount+'_container',idTools='xhe'+xCount+'_Tool',idIframeArea='xhe'+xCount+'_iframearea',idIframe='xhe'+xCount+'_iframe',idFixFFCursor='xhe'+xCount+'_fixffcursor';
  129. var headHTML='',bodyClass='',skinPath=editorRoot+'xheditor_skin/'+settings.skin+'/',arrEmots=itemEmots,urlType=settings.urlType,urlBase=settings.urlBase,emotPath=settings.emotPath,emotPath=emotPath?emotPath:editorRoot+'xheditor_emot/',selEmotGroup='';
  130. arrEmots=$.extend({},arrEmots,settings.emots);
  131. emotPath=getLocalUrl(emotPath,'rel',urlBase?urlBase:null);//返回最短表情路径
  132. bShowBlocktag=settings.showBlocktag;
  133. if(bShowBlocktag)bodyClass+=' showBlocktag';
  134. var arrShortCuts=[];
  135. this.init=function()
  136. {
  137. //加载样式表
  138. if($('#'+idCSS).length===0)$('head').append('<link id="'+idCSS+'" rel="stylesheet" type="text/css" href="'+skinPath+'ui.css" />');
  139. //初始化编辑器
  140. var textareaWidth=_jText.outerWidth(),textareaHeight=_jText.outerHeight();
  141. var editorWidth = settings.width || _text.style.width || (textareaWidth>10?textareaWidth:0);
  142. editorHeight = settings.height || _text.style.height || (textareaHeight>10?textareaHeight:150);//默认高度
  143. if(is(editorWidth,'number'))editorWidth+='px';
  144. if(is(editorHeight,'string'))editorHeight=editorHeight.replace(/[^\d]+/g,'');
  145. //编辑器CSS背景
  146. var editorBackground=settings.background || _text.style.background;
  147. //工具栏内容初始化
  148. var arrToolsHtml=['<span class="xheGStart"/>'],tool,cn,regSeparator=/\||\//i;
  149. $.each(settings.tools,function(i,n)
  150. {
  151. if(n.match(regSeparator))arrToolsHtml.push('<span class="xheGEnd"/>');
  152. if(n==='|')arrToolsHtml.push('<span class="xheSeparator"/>');
  153. else if(n==='/')arrToolsHtml.push('<br />');
  154. else
  155. {
  156. tool=arrTools[n];
  157. if(!tool)return;
  158. if(tool.c)cn=tool.c;
  159. else cn='xheIcon xheBtn'+n;
  160. arrToolsHtml.push('<span><a href="#" title="'+tool.t+'" cmd="'+n+'" class="xheButton xheEnabled" tabindex="-1" role="button"><span class="'+cn+'" unselectable="on" style="font-size:0;color:transparent;text-indent:-999px;">'+tool.t+'</span></a></span>');
  161. if(tool.s)_this.addShortcuts(tool.s,n);
  162. }
  163. if(n.match(regSeparator))arrToolsHtml.push('<span class="xheGStart"/>');
  164. });
  165. arrToolsHtml.push('<span class="xheGEnd"/><br />');
  166. _jText.after($('<input type="text" id="'+idFixFFCursor+'" style="position:absolute;display:none;" /><span id="'+idContainer+'" class="xhe_'+settings.skin+'" style="display:none"><table cellspacing="0" cellpadding="0" class="xheLayout" style="'+(editorWidth!='0px'?'width:'+editorWidth+';':'')+'height:'+editorHeight+'px;" role="presentation"><tr><td id="'+idTools+'" class="xheTool" unselectable="on" style="height:1px;" role="presentation"></td></tr><tr><td id="'+idIframeArea+'" class="xheIframeArea" role="presentation"><iframe frameborder="0" id="'+idIframe+'" src="javascript:;" style="width:100%;"></iframe></td></tr></table></span>'));
  167. _jTools=$('#'+idTools);_jArea=$('#'+idIframeArea);
  168. headHTML='<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><link rel="stylesheet" href="'+skinPath+'iframe.css"/>';
  169. var loadCSS=settings.loadCSS;
  170. if(loadCSS)
  171. {
  172. if(is(loadCSS,'array'))for(var i in loadCSS)headHTML+='<link rel="stylesheet" href="'+loadCSS[i]+'"/>';
  173. else
  174. {
  175. if(loadCSS.match(/\s*<style(\s+[^>]*?)?>[\s\S]+?<\/style>\s*/i))headHTML+=loadCSS;
  176. else headHTML+='<link rel="stylesheet" href="'+loadCSS+'"/>';
  177. }
  178. }
  179. var iframeHTML='<html><head>'+headHTML+'<title>可视化编辑器,alt+1到9键,切换到工具区,tab键,选择按钮,esc键,返回编辑 '+(settings.readTip?settings.readTip:'')+'</title>';
  180. if(editorBackground)iframeHTML+='<style>html{background:'+editorBackground+';}</style>';
  181. iframeHTML+='</head><body spellcheck="0" class="editMode'+bodyClass+'"></body></html>';
  182. _this.win=_win=$('#'+idIframe)[0].contentWindow;
  183. _jWin=$(_win);
  184. try{
  185. this.doc=_doc = _win.document;_jDoc=$(_doc);
  186. _doc.open();
  187. _doc.write(iframeHTML);
  188. _doc.close();
  189. if(isIE)_doc.body.contentEditable='true';
  190. else _doc.designMode = 'On';
  191. }catch(e){}
  192. setTimeout(setOpts,300);
  193. _this.setSource();
  194. _win.setInterval=null;//针对jquery 1.3无法操作iframe window问题的hack
  195. //添加工具栏
  196. _jTools.append(arrToolsHtml.join('')).bind('mousedown contextmenu',returnFalse).click(function(event)
  197. {
  198. var jButton=$(event.target).closest('a');
  199. if(jButton.is('.xheEnabled'))
  200. {
  201. clearTimeout(timer);//取消悬停执行
  202. _jTools.find('a').attr('tabindex','-1');//无障碍支持
  203. ev=event;
  204. _this.exec(jButton.attr('cmd'));
  205. }
  206. return false;
  207. });
  208. _jTools.find('.xheButton').hover(function(event){//鼠标悬停执行
  209. var jButton=$(this),delay=settings.hoverExecDelay;
  210. var tAngle=lastAngle;lastAngle=null;
  211. if(delay===-1||bDisableHoverExec||!jButton.is('.xheEnabled'))return false;
  212. if(tAngle&&tAngle>10)//检测误操作
  213. {
  214. bDisableHoverExec=true;
  215. setTimeout(function(){bDisableHoverExec=false;},100);
  216. return false;
  217. }
  218. var cmd=jButton.attr('cmd'),bHover=arrTools[cmd].h===1;
  219. if(!bHover)
  220. {
  221. _this.hidePanel();//移到非悬停按钮上隐藏面板
  222. return false;
  223. }
  224. if(bQuickHoverExec)delay=0;
  225. if(delay>=0)timer=setTimeout(function(){
  226. ev=event;
  227. lastPoint={x:ev.clientX,y:ev.clientY};
  228. _this.exec(cmd);
  229. },delay);
  230. },function(event){lastPoint=null;if(timer)clearTimeout(timer);}).mousemove(function(event){
  231. if(lastPoint)
  232. {
  233. var diff={x:event.clientX-lastPoint.x,y:event.clientY-lastPoint.y};
  234. if(Math.abs(diff.x)>1||Math.abs(diff.y)>1)
  235. {
  236. if(diff.x>0&&diff.y>0)
  237. {
  238. var tAngle=Math.round(Math.atan(diff.y/diff.x)/0.017453293);
  239. if(lastAngle)lastAngle=(lastAngle+tAngle)/2
  240. else lastAngle=tAngle;
  241. }
  242. else lastAngle=null;
  243. lastPoint={x:event.clientX,y:event.clientY};
  244. }
  245. }
  246. });
  247. //初始化面板
  248. _jPanel=$('#xhePanel');
  249. _jShadow=$('#xheShadow');
  250. _jCntLine=$('#xheCntLine');
  251. if(_jPanel.length===0)
  252. {
  253. _jPanel=$('<div id="xhePanel"></div>').mousedown(function(ev){ev.stopPropagation()});
  254. _jShadow=$('<div id="xheShadow"></div>');
  255. _jCntLine=$('<div id="xheCntLine"></div>');
  256. setTimeout(function(){
  257. $(document.body).append(_jPanel).append(_jShadow).append(_jCntLine);
  258. },10);
  259. }
  260. //切换显示区域
  261. $('#'+idContainer).show();
  262. _jText.hide();
  263. _jArea.css('height',editorHeight-_jTools.outerHeight());
  264. if(isIE&browerVer<8)setTimeout(function(){_jArea.css('height',editorHeight-_jTools.outerHeight());},1);
  265. //绑定内核事件
  266. _jText.focus(_this.focus);
  267. _jForm.submit(saveResult).bind('reset', loadReset);//绑定表单的提交和重置事件
  268. if(settings.submitID)$('#'+settings.submitID).mousedown(saveResult);//自定义绑定submit按钮
  269. $(window).bind('unload beforeunload',saveResult).bind('resize',fixFullHeight);
  270. $(document).mousedown(clickCancelPanel);
  271. if(!bCheckEscInit){$(document).keydown(checkEsc);bCheckEscInit=true;}
  272. _jWin.focus(function(){if(settings.focus)settings.focus();}).blur(function(){if(settings.blur)settings.blur();});
  273. if(isSafari)_jWin.click(fixAppleSel);
  274. _jDoc.mousedown(clickCancelPanel).keydown(checkShortcuts).keypress(forcePtag).dblclick(checkDblClick).bind('mousedown click',function(ev){_jText.trigger(ev.type);});
  275. if(isIE)
  276. {
  277. //IE控件上Backspace会导致页面后退
  278. _jDoc.keydown(function(ev){var rng=_this.getRng();if(ev.which===8&&rng.item){$(rng.item(0)).remove();return false;}});
  279. //修正IE拖动img大小不更新width和height属性值的问题
  280. function fixResize(ev)
  281. {
  282. var jImg=$(ev.target),v;
  283. if(v=jImg.css('width'))jImg.css('width','').attr('width',v.replace(/[^0-9%]+/g, ''));
  284. if(v=jImg.css('height'))jImg.css('height','').attr('height',v.replace(/[^0-9%]+/g, ''));
  285. }
  286. _jDoc.bind('controlselect',function(ev){
  287. ev=ev.target;if(!$.nodeName(ev,'IMG'))return;
  288. $(ev).unbind('resizeend',fixResize).bind('resizeend',fixResize);
  289. });
  290. }
  291. //无障碍支持
  292. _jDoc.keydown(function(e){
  293. var which=e.which;
  294. if(e.altKey&&which>=49&&which<=57){
  295. _jTools.find('a').attr('tabindex','0');
  296. _jTools.find('.xheGStart').eq(which-49).next().find('a').focus();
  297. _doc.title='\uFEFF\uFEFF';
  298. return false;
  299. }
  300. }).click(function(){
  301. _jTools.find('a').attr('tabindex','-1');
  302. });
  303. _jTools.keydown(function(e){
  304. var which=e.which;
  305. if(which==27){
  306. _jTools.find('a').attr('tabindex','-1');
  307. _this.focus();
  308. }
  309. else if(e.altKey&&which>=49&&which<=57){
  310. _jTools.find('.xheGStart').eq(which-49).next().find('a').focus();
  311. return false;
  312. }
  313. });
  314. var jBody=$(_doc.documentElement);
  315. //自动清理粘贴内容
  316. if(isOpera)jBody.bind('keydown',function(e){if(e.ctrlKey&&e.which===86)cleanPaste();});
  317. else jBody.bind(isIE?'beforepaste':'paste',cleanPaste);
  318. //禁用编辑区域的浏览器默认右键菜单
  319. if(settings.disableContextmenu)jBody.bind('contextmenu',returnFalse);
  320. //HTML5编辑区域直接拖放上传
  321. if(settings.html5Upload)jBody.bind('dragenter dragover',function(ev){var types;if((types=ev.originalEvent.dataTransfer.types)&&$.inArray('Files', types)!==-1)return false;}).bind('drop',function(ev){
  322. var dataTransfer=ev.originalEvent.dataTransfer,fileList;
  323. if(dataTransfer&&(fileList=dataTransfer.files)&&fileList.length>0){
  324. var i,cmd,arrCmd=['Link','Img','Flash','Media'],arrExt=[],strExt;
  325. for(i in arrCmd){
  326. cmd=arrCmd[i];
  327. if(settings['up'+cmd+'Url']&&settings['up'+cmd+'Url'].match(/^[^!].*/i))arrExt.push(cmd+':,'+settings['up'+cmd+'Ext']);//允许上传
  328. }
  329. if(arrExt.length===0)return false;//禁止上传
  330. else strExt=arrExt.join(',');
  331. function getCmd(fileList){
  332. var match,fileExt,cmd;
  333. for(i=0;i<fileList.length;i++){
  334. fileExt=fileList[i].name.replace(/.+\./,'');
  335. if(match=strExt.match(new RegExp('(\\w+):[^:]*,'+fileExt+'(?:,|$)','i'))){
  336. if(!cmd)cmd=match[1];
  337. else if(cmd!==match[1])return 2;
  338. }
  339. else return 1;
  340. }
  341. return cmd;
  342. }
  343. cmd=getCmd(fileList);
  344. if(cmd===1)alert('上传文件的扩展名必需为:'+strExt.replace(/\w+:,/g,''));
  345. else if(cmd===2)alert('每次只能拖放上传同一类型文件');
  346. else if(cmd){
  347. _this.startUpload(fileList,settings['up'+cmd+'Url'],'*',function(arrMsg){
  348. var arrUrl=[],msg,onUpload=settings.onUpload;
  349. if(onUpload)onUpload(arrMsg);//用户上传回调
  350. for(var i=0,c=arrMsg.length;i<c;i++){
  351. msg=arrMsg[i];
  352. url=is(msg,'string')?msg:msg.url;
  353. if(url.substr(0,1)==='!')url=url.substr(1);
  354. arrUrl.push(url);
  355. }
  356. _this.exec(cmd);
  357. $('#xhe'+cmd+'Url').val(arrUrl.join(' '));
  358. $('#xheSave').click();
  359. });
  360. }
  361. return false;
  362. }
  363. });
  364. //添加用户快捷键
  365. var shortcuts=settings.shortcuts;
  366. if(shortcuts)$.each(shortcuts,function(key,func){_this.addShortcuts(key,func);});
  367. xCount++;
  368. bInit=true;
  369. if(settings.fullscreen)_this.toggleFullscreen();
  370. else if(settings.sourceMode)setTimeout(_this.toggleSource,20);
  371. return true;
  372. }
  373. this.remove=function()
  374. {
  375. _this.hidePanel();
  376. saveResult();//卸载前同步最新内容到textarea
  377. //取消绑定事件
  378. _jText.unbind('focus',_this.focus);
  379. _jForm.unbind('submit',saveResult).unbind('reset', loadReset);
  380. if(settings.submitID)$('#'+settings.submitID).unbind('mousedown',saveResult);
  381. $(window).unbind('unload beforeunload',saveResult).unbind('resize',fixFullHeight);
  382. $(document).unbind('mousedown',clickCancelPanel);
  383. $('#'+idContainer).remove();
  384. $('#'+idFixFFCursor).remove();
  385. _jText.show();
  386. bInit=false;
  387. }
  388. this.saveBookmark=function(){
  389. if(!bSource){
  390. _this.focus();
  391. var rng=_this.getRng();
  392. rng=rng.cloneRange?rng.cloneRange():rng;
  393. bookmark={'top':_jWin.scrollTop(),'rng':rng};
  394. }
  395. }
  396. this.loadBookmark=function()
  397. {
  398. if(bSource||!bookmark)return;
  399. _this.focus();
  400. var rng=bookmark.rng;
  401. if(isIE)rng.select();
  402. else
  403. {
  404. var sel=_this.getSel();
  405. sel.removeAllRanges();
  406. sel.addRange(rng);
  407. }
  408. _jWin.scrollTop(bookmark.top);
  409. bookmark=null;
  410. }
  411. this.focus=function()
  412. {
  413. if(!bSource)_win.focus();
  414. else $('#sourceCode',_doc).focus();
  415. if(isIE){
  416. var rng=_this.getRng();
  417. if(rng.parentElement&&rng.parentElement().ownerDocument!==_doc)_this.setTextCursor();//修正IE初始焦点问题
  418. }
  419. return false;
  420. }
  421. this.setTextCursor=function(bLast)
  422. {
  423. var rng=_this.getRng(true),cursorNode=_doc.body;
  424. if(isIE)rng.moveToElementText(cursorNode);
  425. else{
  426. var chileName=bLast?'lastChild':'firstChild';
  427. while(cursorNode.nodeType!=3&&cursorNode[chileName]){cursorNode=cursorNode[chileName];}
  428. rng.selectNode(cursorNode);
  429. }
  430. rng.collapse(bLast?false:true);
  431. if(isIE)rng.select();
  432. else{var sel=_this.getSel();sel.removeAllRanges();sel.addRange(rng);}
  433. }
  434. this.getSel=function()
  435. {
  436. return _doc.selection ? _doc.selection : _win.getSelection();
  437. }
  438. this.getRng=function(bNew)
  439. {
  440. var sel,rng;
  441. try{
  442. if(!bNew){
  443. sel=_this.getSel();
  444. rng = sel.createRange ? sel.createRange() : sel.rangeCount > 0?sel.getRangeAt(0):null;
  445. }
  446. if(!rng)rng = _doc.body.createTextRange?_doc.body.createTextRange():_doc.createRange();
  447. }catch (ex){}
  448. return rng;
  449. }
  450. this.getParent=function(tag)
  451. {
  452. var rng=_this.getRng(),p;
  453. if(!isIE)
  454. {
  455. p = rng.commonAncestorContainer;
  456. if(!rng.collapsed)if(rng.startContainer === rng.endContainer&&rng.startOffset - rng.endOffset < 2&&rng.startContainer.hasChildNodes())p = rng.startContainer.childNodes[rng.startOffset];
  457. }
  458. else p=rng.item?rng.item(0):rng.parentElement();
  459. tag=tag?tag:'*';p=$(p);
  460. if(!p.is(tag))p=$(p).closest(tag);
  461. return p;
  462. }
  463. this.getSelect=function(format)
  464. {
  465. var sel=_this.getSel(),rng=_this.getRng(),isCollapsed=true;
  466. if (!rng || rng.item)isCollapsed=false
  467. else isCollapsed=!sel || rng.boundingWidth === 0 || rng.collapsed;
  468. if(format==='text')return isCollapsed ? '' : (rng.text || (sel.toString ? sel.toString() : ''));
  469. var sHtml;
  470. if(rng.cloneContents)
  471. {
  472. var tmp=$('<div></div>'),c;
  473. c = rng.cloneContents();
  474. if(c)tmp.append(c);
  475. sHtml=tmp.html();
  476. }
  477. else if(is(rng.item))sHtml=rng.item(0).outerHTML;
  478. else if(is(rng.htmlText))sHtml=rng.htmlText;
  479. else sHtml=rng.toString();
  480. if(isCollapsed)sHtml='';
  481. sHtml=_this.processHTML(sHtml,'read');
  482. sHtml=_this.cleanHTML(sHtml);
  483. sHtml=_this.formatXHTML(sHtml);
  484. return sHtml;
  485. }
  486. this.pasteHTML=function(sHtml,bStart)
  487. {
  488. if(bSource)return false;
  489. _this.focus();
  490. sHtml=_this.processHTML(sHtml,'write');
  491. var sel=_this.getSel(),rng=_this.getRng();
  492. if(bStart!==undefined)//非覆盖式插入
  493. {
  494. if(rng.item)
  495. {
  496. var item=rng.item(0);
  497. rng=_this.getRng(true);
  498. rng.moveToElementText(item);
  499. rng.select();
  500. }
  501. rng.collapse(bStart);
  502. }
  503. sHtml+='<'+(isIE?'img':'span')+' id="_xhe_temp" width="0" height="0" />';
  504. if(rng.insertNode)
  505. {
  506. if($(rng.startContainer).closest('style,script').length>0)return false;//防止粘贴在style和script内部
  507. rng.deleteContents();
  508. rng.insertNode(rng.createContextualFragment(sHtml));
  509. }
  510. else
  511. {
  512. if(sel.type.toLowerCase()==='control'){sel.clear();rng=_this.getRng();};
  513. rng.pasteHTML(sHtml);
  514. }
  515. var jTemp=$('#_xhe_temp',_doc),temp=jTemp[0];
  516. if(isIE)
  517. {
  518. rng.moveToElementText(temp);
  519. rng.select();
  520. }
  521. else
  522. {
  523. rng.selectNode(temp);
  524. sel.removeAllRanges();
  525. sel.addRange(rng);
  526. }
  527. jTemp.remove();
  528. }
  529. this.pasteText=function(text,bStart)
  530. {
  531. if(!text)text='';
  532. text=_this.domEncode(text);
  533. text = text.replace(/\r?\n/g, '<br />');
  534. _this.pasteHTML(text,bStart);
  535. }
  536. this.appendHTML=function(sHtml)
  537. {
  538. if(bSource)return false;
  539. _this.focus();
  540. sHtml=_this.processHTML(sHtml,'write');
  541. $(_doc.body).append(sHtml);
  542. _this.setTextCursor(true);
  543. }
  544. this.domEncode=function(text)
  545. {
  546. return text.replace(regEntities,function(c){return arrEntities[c];});
  547. }
  548. this.setSource=function(sHtml)
  549. {
  550. bookmark=null;
  551. if(typeof sHtml!=='string'&&sHtml!=='')sHtml=_text.value;
  552. if(bSource)$('#sourceCode',_doc).val(sHtml);
  553. else
  554. {
  555. if(settings.beforeSetSource)sHtml=settings.beforeSetSource(sHtml);
  556. sHtml=_this.cleanHTML(sHtml);
  557. sHtml=_this.formatXHTML(sHtml);
  558. sHtml=_this.processHTML(sHtml,'write');
  559. if(isIE){//修正IE会删除可视内容前的script,style,<!--
  560. _doc.body.innerHTML='<img id="_xhe_temp" width="0" height="0" />'+sHtml;//修正IE会删除&符号后面代码的问题
  561. $('#_xhe_temp',_doc).remove();
  562. }
  563. else _doc.body.innerHTML=sHtml;
  564. }
  565. }
  566. this.processHTML=function(sHtml,mode)
  567. {
  568. var appleClass=' class="Apple-style-span"';
  569. if(mode==='write')
  570. {//write
  571. sHtml=sHtml.replace(/(<(\/?)(\w+))((?:\s+[\w\-:]+\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))*)\s*((\/?)>)/g,function(all,left,end1,tag,attr,right,end2){
  572. tag=tag.toLowerCase();
  573. if(isMozilla){
  574. if(tag==='strong')tag='b';
  575. else if(tag==='em')tag='i';
  576. }
  577. else if(isSafari){
  578. if(tag==='strong'){tag='span';if(!end1)attr+=appleClass+' style="font-weight: bold;"';}
  579. else if(tag==='em'){tag='span';if(!end1)attr+=appleClass+' style="font-style: italic;"';}
  580. else if(tag==='u'){tag='span';if(!end1)attr+=appleClass+' style="text-decoration: underline;"';}
  581. else if(tag==='strike'){tag='span';if(!end1)attr+=appleClass+' style="text-decoration: line-through;"';}
  582. }
  583. var emot,addClass='';
  584. if(tag==='del')tag='strike';//编辑状态统一转为strike
  585. else if(tag==='img'){
  586. //恢复emot
  587. attr=attr.replace(/\s+emot\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/i,function(all,v){
  588. emot=v.match(/^(["']?)(.*)\1/)[2];
  589. emot=emot.split(',');
  590. if(!emot[1]){emot[1]=emot[0];emot[0]=''}
  591. if(emot[0]==='default')emot[0]='';
  592. return settings.emotMark?all:'';
  593. });
  594. }
  595. else if(tag==='a'){
  596. if(!attr.match(/ href=[^ ]/i)&&attr.match(/ name=[^ ]/i))addClass+=' xhe-anchor';
  597. if(end2)right='></a>';
  598. }
  599. else if(tag==='table'&&!end1){
  600. var tb=attr.match(/\s+border\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/i);
  601. if(!tb||tb[1].match(/^(["']?)\s*0\s*\1$/))addClass+=' xhe-border';
  602. }
  603. var bAppleClass;
  604. //处理属性
  605. attr=attr.replace(/\s+([\w\-:]+)\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/g,function(all,n,v){
  606. n=n.toLowerCase();
  607. v=v.match(/^(["']?)(.*)\1/)[2];
  608. aft='';//尾部增加属性
  609. if(isIE&&n.match(/^(disabled|checked|readonly|selected)$/)&&v.match(/^(false|0)$/i))return '';
  610. //恢复emot
  611. if(tag==='img'&&emot&&n==='src')return '';
  612. //保存属性值:src,href
  613. if(n.match(/^(src|href)$/)){
  614. aft=' _xhe_'+n+'="'+v+'"';
  615. if(urlBase)v=getLocalUrl(v,'abs',urlBase);
  616. }
  617. //添加class
  618. if(addClass&&n==='class'){
  619. v+=' '+addClass;
  620. addClass='';
  621. }
  622. //处理Safari style值
  623. if(isSafari&&n==='style'){
  624. if(tag==='span'&&v.match(/(^|;)\s*(font-family|font-size|color|background-color)\s*:\s*[^;]+\s*(;|$)/i))bAppleClass=true;
  625. }
  626. return ' '+n+'="'+v+'"'+aft;
  627. });
  628. //恢复emot
  629. if(emot){
  630. var url=emotPath+(emot[0]?emot[0]:'default')+'/'+emot[1]+'.gif';
  631. attr+=' src="'+url+'" _xhe_src="'+url+'"';
  632. }
  633. if(bAppleClass)attr+=appleClass;
  634. if(addClass)attr+=' class="'+addClass+'"';
  635. return '<'+end1+tag+attr+right;
  636. });
  637. if(isIE)sHtml = sHtml.replace(/&apos;/ig, '&#39;');
  638. if(!isSafari)
  639. {
  640. //style转font
  641. function style2font(all,tag,left,style,right,content)
  642. {
  643. var attrs='',f,s1,s2,c;
  644. f=style.match(/font-family\s*:\s*([^;"]+)/i);
  645. if(f)attrs+=' face="'+f[1]+'"';
  646. s1=style.match(/font-size\s*:\s*([^;"]+)/i);
  647. if(s1)
  648. {
  649. s1=s1[1].toLowerCase();
  650. for(var j=0;j<arrFontsize.length;j++)if(s1===arrFontsize[j].n||s1===arrFontsize[j].s){s2=j+1;break;}
  651. if(s2)
  652. {
  653. attrs+=' size="'+s2+'"';
  654. style=style.replace(/(^|;)(\s*font-size\s*:\s*[^;"]+;?)+/ig,'$1');
  655. }
  656. }
  657. c=style.match(/(?:^|[\s;])color\s*:\s*([^;"]+)/i);
  658. if(c)
  659. {
  660. var rgb;
  661. if(rgb=c[1].match(/\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i)){
  662. c[1]='#';
  663. for(var i=1;i<=3;i++){
  664. c[1]+=('0'+(rgb[i]-0).toString(16)).slice(-2);
  665. }
  666. }
  667. c[1]=c[1].replace(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i,'#$1$1$2$2$3$3');
  668. attrs+=' color="'+c[1]+'"';
  669. }
  670. style=style.replace(/(^|;)(\s*(font-family|color)\s*:\s*[^;"]+;?)+/ig,'$1');
  671. if(attrs!=='')
  672. {
  673. if(style)attrs+=' style="'+style+'"';
  674. return '<font'+(left?left:'')+attrs+(right?right:'')+'>'+content+"</font>";
  675. }
  676. else return all;
  677. }
  678. sHtml = sHtml.replace(/<(span)(\s+[^>]*?)?\s+style\s*=\s*"((?:[^"]*?;)?\s*(?:font-family|font-size|color)\s*:[^"]*)"( [^>]*)?>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?<\/\1>)*?)<\/\1>/ig,style2font);//第3层
  679. sHtml = sHtml.replace(/<(span)(\s+[^>]*?)?\s+style\s*=\s*"((?:[^"]*?;)?\s*(?:font-family|font-size|color)\s*:[^"]*)"( [^>]*)?>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?)<\/\1>/ig,style2font);//第2层
  680. sHtml = sHtml.replace(/<(span)(\s+[^>]*?)?\s+style\s*=\s*"((?:[^"]*?;)?\s*(?:font-family|font-size|color)\s*:[^"]*)"( [^>]*)?>(((?!<\1(\s+[^>]*?)?>)[\s\S])*?)<\/\1>/ig,style2font);//最里层
  681. }
  682. //表格单元格处理
  683. sHtml = sHtml.replace(/<(td|th)(\s+[^>]*?)?>(\s|&nbsp;)*<\/\1>/ig,'<$1$2>'+(isIE?'':'<br />')+'</$1>');
  684. }
  685. else
  686. {//read
  687. if(isSafari)
  688. {
  689. //转换apple的style为strong,em等
  690. var arrAppleSpan=[{r:/font-weight\s*:\s*bold;?/ig,t:'strong'},{r:/font-style\s*:\s*italic;?/ig,t:'em'},{r:/text-decoration\s*:\s*underline;?/ig,t:'u'},{r:/text-decoration\s*:\s*line-through;?/ig,t:'strike'}];
  691. function replaceAppleSpan(all,tag,attr1,attr2,content)
  692. {
  693. var attr=(attr1?attr1:'')+(attr2?attr2:'');
  694. var arrPre=[],arrAft=[];
  695. var regApple,tagApple;
  696. for(var i=0;i<arrAppleSpan.length;i++)
  697. {
  698. regApple=arrAppleSpan[i].r;
  699. tagApple=arrAppleSpan[i].t;
  700. attr=attr.replace(regApple,function(){
  701. arrPre.push("<"+tagApple+">");
  702. arrAft.push("</"+tagApple+">");
  703. return '';
  704. });
  705. }
  706. attr=attr.replace(/\s+style\s*=\s*"\s*"/i,'');
  707. return (attr?'<span'+attr+'>':'')+arrPre.join('')+content+arrAft.join('')+(attr?'</span>':'');
  708. }
  709. for(var i=0;i<2;i++){
  710. sHtml = sHtml.replace(/<(span)(\s+[^>]*?)?\s+class\s*=\s*"Apple-style-span"(\s+[^>]*?)?>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?<\/\1>)*?)<\/\1>/ig,replaceAppleSpan);//第3层
  711. sHtml = sHtml.replace(/<(span)(\s+[^>]*?)?\s+class\s*=\s*"Apple-style-span"(\s+[^>]*?)?>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?)<\/\1>/ig,replaceAppleSpan);//第2层
  712. sHtml = sHtml.replace(/<(span)(\s+[^>]*?)?\s+class\s*=\s*"Apple-style-span"(\s+[^>]*?)?>(((?!<\1(\s+[^>]*?)?>)[\s\S])*?)<\/\1>/ig,replaceAppleSpan);//最里层
  713. }
  714. }
  715. sHtml=sHtml.replace(/(<(\w+))((?:\s+[\w\-:]+\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))*)\s*(\/?>)/g,function(all,left,tag,attr,right){
  716. tag=tag.toLowerCase();
  717. //恢复属性值src,href
  718. var saveValue;
  719. attr=attr.replace(/\s+_xhe_(?:src|href)\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/i,function(all,v){saveValue=v.match(/^(["']?)(.*)\1/)[2];return '';});
  720. if(saveValue&&urlType)saveValue=getLocalUrl(saveValue,urlType,urlBase);
  721. attr=attr.replace(/\s+([\w\-:]+)\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/g,function(all,n,v){
  722. n=n.toLowerCase();
  723. v=v.match(/^(["']?)(.*)\1/)[2].replace(/"/g,"'");
  724. if(n==='class'){//清理class属性
  725. if(v.match(/^["']?(apple|webkit)/i))return '';
  726. v=v.replace(/\s?xhe-[a-z]+/ig,'');
  727. if(v==='')return '';
  728. }
  729. else if(n.match(/^((_xhe_|_moz_|_webkit_)|jquery\d+)/i))return '';//清理临时属性
  730. else if(saveValue&&n.match(/^(src|href)$/i))return ' '+n+'="'+saveValue+'"';//恢复属性值src,href
  731. else if(n==='style'){//转换font-size的keyword到px单位
  732. v=v.replace(/(^|;)\s*(font-size)\s*:\s*([a-z-]+)\s*(;|$)/i,function(all,left,n,v,right){
  733. var t,s;
  734. for(var i=0;i<arrFontsize.length;i++)
  735. {
  736. t=arrFontsize[i];
  737. if(v===t.n){s=t.s;break;}
  738. }
  739. return left+n+':'+s+right;
  740. });
  741. }
  742. return ' '+n+'="'+v+'"';
  743. });
  744. //img强制加alt
  745. if(tag==='img'&&!attr.match(/\s+alt\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/i))attr+=' alt=""';
  746. return left+attr+right;
  747. });
  748. //表格单元格处理
  749. sHtml = sHtml.replace(/(<(td|th)(?:\s+[^>]*?)?>)\s*([\s\S]*?)(<br(\s*\/)?>)?\s*<\/\2>/ig,function(all,left,tag,content){return left+(content?content:'&nbsp;')+'</'+tag+'>';});
  750. //修正浏览器在空内容情况下多出来的代码
  751. sHtml=sHtml.replace(/^\s*(?:<(p|div)(?:\s+[^>]*?)?>)?\s*(<span(?:\s+[^>]*?)?>\s*<\/span>|<br(?:\s+[^>]*?)?>|&nbsp;)*\s*(?:<\/\1>)?\s*$/i, '');
  752. }
  753. //写和读innerHTML前pre中<br>转\r\n
  754. sHtml=sHtml.replace(/(<pre(?:\s+[^>]*?)?>)([\s\S]+?)(<\/pre>)/gi,function(all,left,code,right){
  755. return left+code.replace(/<br\s*\/?>/ig,'\r\n')+right;
  756. });
  757. return sHtml;
  758. }
  759. this.getSource=function(bFormat)
  760. {
  761. var sHtml,beforeGetSource=settings.beforeGetSource;
  762. if(bSource)
  763. {
  764. sHtml=$('#sourceCode',_doc).val();
  765. if(!beforeGetSource)sHtml=_this.formatXHTML(sHtml,false);
  766. }
  767. else
  768. {
  769. sHtml=_this.processHTML(_doc.body.innerHTML,'read');
  770. sHtml=_this.cleanHTML(sHtml);
  771. sHtml=_this.formatXHTML(sHtml,bFormat);
  772. if(beforeGetSource)sHtml=beforeGetSource(sHtml);
  773. }
  774. _text.value=sHtml;
  775. return sHtml;
  776. }
  777. this.cleanWord=function(sHtml)
  778. {
  779. var cleanPaste=settings.cleanPaste;
  780. if(cleanPaste>0&&cleanPaste<3&&/mso(-|normal)|WordDocument|<table\s+[^>]*?x:str|\s+class\s*=\s*"?xl[67]\d"/i.test(sHtml))
  781. {
  782. //区块标签清理
  783. sHtml = sHtml.replace(/<!--[\s\S]*?-->|<!(--)?\[[\s\S]+?\](--)?>|<style(\s+[^>]*?)?>[\s\S]*?<\/style>/ig, '');
  784. sHtml = sHtml.replace(/\r?\n/ig, '');
  785. //保留Word图片占位
  786. if(isIE){
  787. sHtml = sHtml.replace(/<v:shapetype(\s+[^>]*)?>[\s\S]*<\/v:shapetype>/ig,'');
  788. sHtml = sHtml.replace(/<v:shape(\s+[^>]+)?>[\s\S]*?<v:imagedata(\s+[^>]+)?>\s*<\/v:imagedata>[\s\S]*?<\/v:shape>/ig,function(all,attr1,attr2){
  789. var match;
  790. match = attr2.match(/\s+src\s*=\s*("[^"]+"|'[^']+'|[^>\s]+)/i);
  791. if(match){
  792. match = match[1].match(/^(["']?)(.*)\1/)[2];
  793. var sImg ='<img src="'+editorRoot+'xheditor_skin/blank.gif'+'" _xhe_temp="true" class="wordImage"';
  794. match = attr1.match(/\s+style\s*=\s*("[^"]+"|'[^']+'|[^>\s]+)/i);
  795. if(match){
  796. match = match[1].match(/^(["']?)(.*)\1/)[2];
  797. sImg += ' style="' + match + '"';
  798. }
  799. sImg += ' />';
  800. return sImg;
  801. }
  802. return '';
  803. });
  804. }
  805. else{
  806. sHtml = sHtml.replace(/<img( [^<>]*(v:shapes|msohtmlclip)[^<>]*)\/?>/ig,function(all,attr){
  807. var match,str = '<img src="'+editorRoot+'xheditor_skin/blank.gif'+'" _xhe_temp="true" class="wordImage"';
  808. match = attr.match(/ width\s*=\s*"([^"]+)"/i);
  809. if(match)str += ' width="'+match[1]+'"';
  810. match = attr.match(/ height\s*=\s*"([^"]+)"/i);
  811. if(match)str += ' height="'+match[1]+'"';
  812. return str + ' />';
  813. });
  814. }
  815. sHtml=sHtml.replace(/(<(\/?)([\w\-:]+))((?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))?)*)\s*(\/?>)/g,function(all,left,end,tag,attr,right){
  816. tag=tag.toLowerCase();
  817. if((tag.match(/^(link)$/)&&attr.match(/file:\/\//i))||tag.match(/:/)||(tag==='span'&&cleanPaste===2))return '';
  818. if(!end){
  819. attr=attr.replace(/\s([\w\-:]+)(?:\s*=\s*("[^"]*"|'[^']*'|[^>\s]+))?/ig,function(all,n,v){
  820. n=n.toLowerCase();
  821. if(/:/.test(n))return '';
  822. v=v.match(/^(["']?)(.*)\1/)[2];
  823. if(cleanPaste===1){//简单清理
  824. switch(tag){
  825. case 'p':
  826. if(n === 'style'){
  827. v=v.replace(/"|&quot;/ig,"'").replace(/\s*([^:]+)\s*:\s*(.*?)(;|$)/ig,function(all,n,v){
  828. return /^(text-align)$/i.test(n)?(n+':'+v+';'):'';
  829. }).replace(/^\s+|\s+$/g,'');
  830. return v?(' '+n+'="'+v+'"'):'';
  831. }
  832. break;
  833. case 'span':
  834. if(n === 'style'){
  835. v=v.replace(/"|&quot;/ig,"'").replace(/\s*([^:]+)\s*:\s*(.*?)(;|$)/ig,function(all,n,v){
  836. return /^(color|background|font-size|font-family)$/i.test(n)?(n+':'+v+';'):'';
  837. }).replace(/^\s+|\s+$/g,'');
  838. return v?(' '+n+'="'+v+'"'):'';
  839. }
  840. break;
  841. case 'table':
  842. if(n.match(/^(cellspacing|cellpadding|border|width)$/i))return all;
  843. break;
  844. case 'td':
  845. if(n.match(/^(rowspan|colspan)$/i))return all;
  846. if(n === 'style'){
  847. v=v.replace(/"|&quot;/ig,"'").replace(/\s*([^:]+)\s*:\s*(.*?)(;|$)/ig,function(all,n,v){
  848. return /^(width|height)$/i.test(n)?(n+':'+v+';'):'';
  849. }).replace(/^\s+|\s+$/g,'');
  850. return v?(' '+n+'="'+v+'"'):'';
  851. }
  852. break;
  853. case 'a':
  854. if(n.match(/^(href)$/i))return all;
  855. break;
  856. case 'font':
  857. case 'img':
  858. return all;
  859. break;
  860. }
  861. }
  862. else if(cleanPaste===2){
  863. switch(tag){
  864. case 'td':
  865. if(n.match(/^(rowspan|colspan)$/i))return all;
  866. break;
  867. case 'img':
  868. return all;
  869. }
  870. }
  871. return '';
  872. });
  873. }
  874. return left+attr+right;
  875. });
  876. //空内容的标签
  877. for(var i=0;i<3;i++)sHtml = sHtml.replace( /<([^\s>]+)(\s+[^>]*)?>\s*<\/\1>/g,'');
  878. //无属性的无意义标签
  879. function cleanEmptyTag(all,tag,content){
  880. return content;
  881. }
  882. for(var i=0;i<3;i++)sHtml = sHtml.replace(/<(span|a)>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?<\/\1>)*?)<\/\1>/ig,cleanEmptyTag);//第3层
  883. for(var i=0;i<3;i++)sHtml = sHtml.replace(/<(span|a)>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?)<\/\1>/ig,cleanEmptyTag);//第2层
  884. for(var i=0;i<3;i++)sHtml = sHtml.replace(/<(span|a)>(((?!<\1(\s+[^>]*?)?>)[\s\S])*?)<\/\1>/ig,cleanEmptyTag);//最里层
  885. //合并多个font
  886. for(var i=0;i<3;i++)sHtml = sHtml.replace(/<font(\s+[^>]+)><font(\s+[^>]+)>/ig,function(all,attr1,attr2){
  887. return '<font'+attr1+attr2+'>';
  888. });
  889. //清除表格间隙里的空格等特殊字符
  890. sHtml=sHtml.replace(/(<(\/?)(tr|td)(?:\s+[^>]+)?>)[^<>]+/ig,function(all,left,end,tag){
  891. if(!end&&/^td$/i.test(tag))return all;
  892. else return left;
  893. });
  894. }
  895. return sHtml;
  896. }
  897. this.cleanHTML=function(sHtml)
  898. {
  899. sHtml = sHtml.replace(/<!?\/?(DOCTYPE|html|body|meta)(\s+[^>]*?)?>/ig, '');
  900. var arrHeadSave;sHtml = sHtml.replace(/<head(?:\s+[^>]*?)?>([\s\S]*?)<\/head>/i, function(all,content){arrHeadSave=content.match(/<(script|style)(\s+[^>]*?)?>[\s\S]*?<\/\1>/ig);return '';});
  901. if(arrHeadSave)sHtml=arrHeadSave.join('')+sHtml;
  902. sHtml = sHtml.replace(/<\??xml(:\w+)?(\s+[^>]*?)?>([\s\S]*?<\/xml>)?/ig, '');
  903. if(!settings.internalScript)sHtml = sHtml.replace(/<script(\s+[^>]*?)?>[\s\S]*?<\/script>/ig, '');
  904. if(!settings.internalStyle)sHtml = sHtml.replace(/<style(\s+[^>]*?)?>[\s\S]*?<\/style>/ig, '');
  905. if(!settings.linkTag||!settings.inlineScript||!settings.inlineStyle)sHtml=sHtml.replace(/(<(\w+))((?:\s+[\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))*)\s*(\/?>)/ig,function(all,left,tag,attr,right){
  906. if(!settings.linkTag&&tag.toLowerCase()==='link')return '';
  907. if(!settings.inlineScript)attr=attr.replace(/\s+on(?:click|dblclick|mouse(down|up|move|over|out|enter|leave|wheel)|key(down|press|up)|change|select|submit|reset|blur|focus|load|unload)\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/ig,'');
  908. if(!settings.inlineStyle)attr=attr.replace(/\s+(style|class)\s*=\s*("[^"]*"|'[^']*'|[^>\s]+)/ig,'');
  909. return left+attr+right;
  910. });
  911. sHtml=sHtml.replace(/<\/(strong|b|u|strike|em|i)>((?:\s|<br\/?>|&nbsp;)*?)<\1(\s+[^>]*?)?>/ig,'$2');//连续相同标签
  912. return sHtml;
  913. }
  914. this.formatXHTML=function(sHtml,bFormat){
  915. var emptyTags = makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");//HTML 4.01
  916. var blockTags = makeMap("address,applet,blockquote,button,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,table,tbody,td,tfoot,th,thead,tr,ul,script");//HTML 4.01
  917. var inlineTags = makeMap("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");//HTML 4.01
  918. var closeSelfTags = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
  919. var fillAttrsTags = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
  920. var cdataTags = makeMap("script,style");
  921. var tagReplac={'b':'strong','i':'em','s':'del','strike':'del'};
  922. var regTag=/<(?:\/([^\s>]+)|!([^>]*?)|([\w\-:]+)((?:"[^"]*"|'[^']*'|[^"'<>])*)\s*(\/?))>/g;
  923. var regAttr = /\s*([\w\-:]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s]+)))?/g;
  924. var results=[],stack=[];
  925. stack.last = function(){return this[ this.length - 1 ];};
  926. var match,tagIndex,nextIndex=0,tagName,tagCDATA,arrCDATA,text;
  927. var lvl=-1,lastTag='body',lastTagStart,stopFormat=false;
  928. while(match=regTag.exec(sHtml)){
  929. tagIndex = match.index;
  930. if(tagIndex>nextIndex){//保存前面的文本或者CDATA
  931. text=sHtml.substring(nextIndex,tagIndex);
  932. if(tagCDATA)arrCDATA.push(text);
  933. else onText(text);
  934. }
  935. nextIndex = regTag.lastIndex;
  936. if(tagName=match[1]){//结束标签
  937. tagName=processTag(tagName);
  938. if(tagCDATA&&tagName===tagCDATA){//结束标签前输出CDATA
  939. onCDATA(arrCDATA.join(''));
  940. tagCDATA=null;
  941. arrCDATA=null;
  942. }
  943. if(!tagCDATA){
  944. onEndTag(tagName);
  945. continue;
  946. }
  947. }
  948. if(tagCDATA)arrCDATA.push(match[0]);
  949. else{
  950. if(tagName=match[3]){//开始标签
  951. tagName=processTag(tagName);
  952. onStartTag(tagName,match[4],match[5]);
  953. if(cdataTags[tagName]){
  954. tagCDATA=tagName;
  955. arrCDATA=[];
  956. }
  957. }
  958. else if(match[2])onComment(match[0]);//注释标签
  959. }
  960. }
  961. if(sHtml.length>nextIndex)onText(sHtml.substring(nextIndex,sHtml.length ));//结尾文本
  962. onEndTag();//封闭未结束的标签
  963. sHtml=results.join('');
  964. results=null;
  965. function makeMap(str)
  966. {
  967. var obj = {}, items = str.split(",");
  968. for ( var i = 0; i < items.length; i++ )obj[ items[i] ] = true;
  969. return obj;
  970. }
  971. function processTag(tagName)
  972. {
  973. tagName=tagName.toLowerCase();
  974. var tag=tagReplac[tagName];
  975. return tag?tag:tagName;
  976. }
  977. function onStartTag(tagName,rest,unary)
  978. {
  979. if(blockTags[tagName])while(stack.last()&&inlineTags[stack.last()])onEndTag(stack.last());//块标签
  980. if(closeSelfTags[tagName]&&stack.last()===tagName)onEndTag(tagName);//自封闭标签
  981. unary = emptyTags[ tagName ] || !!unary;
  982. if (!unary)stack.push(tagName);
  983. var all=Array();
  984. all.push('<' + tagName);
  985. rest.replace(regAttr, function(match, name)
  986. {
  987. name=name.toLowerCase();
  988. var value = arguments[2] ? arguments[2] :
  989. arguments[3] ? arguments[3] :
  990. arguments[4] ? arguments[4] :
  991. fillAttrsTags[name] ? name : "";
  992. all.push(' '+name+'="'+value.replace(/"/g,"'")+'"');
  993. });
  994. all.push((unary ? " /" : "") + ">");
  995. addHtmlFrag(all.join(''),tagName,true);
  996. if(tagName==='pre')stopFormat=true;
  997. }
  998. function onEndTag(tagName)
  999. {
  1000. if(!tagName)var pos=0;//清空栈
  1001. else for(var pos=stack.length-1;pos>=0;pos--)if(stack[pos]===tagName)break;//向上寻找匹配的开始标签
  1002. if(pos>=0)
  1003. {
  1004. for(var i=stack.length-1;i>=pos;i--)addHtmlFrag("</" + stack[i] + ">",stack[i]);
  1005. stack.length=pos;
  1006. }
  1007. if(tagName==='pre'){
  1008. stopFormat=false;
  1009. lvl--;
  1010. }
  1011. }
  1012. function onText(text){
  1013. addHtmlFrag(_this.domEncode(text));
  1014. }
  1015. function onCDATA(text){
  1016. results.push(text.replace(/^[\s\r\n]+|[\s\r\n]+$/g,''));
  1017. }
  1018. function onComment(text){
  1019. results.push(text);
  1020. }
  1021. function addHtmlFrag(html,tagName,bStart)
  1022. {
  1023. if(!stopFormat)html=html.replace(/(\t*\r?\n\t*)+/g,'');//清理换行符和相邻的制表符
  1024. if(!stopFormat&&bFormat===true)
  1025. {
  1026. if(html.match(/^\s*$/)){//不格式化空内容的标签
  1027. results.push(html);
  1028. return;
  1029. }
  1030. var bBlock=blockTags[tagName],tag=bBlock?tagName:'';
  1031. if(bBlock)
  1032. {
  1033. if(bStart)lvl++;//块开始
  1034. if(lastTag==='')lvl--;//补文本结束
  1035. }
  1036. else if(lastTag)lvl++;//文本开始
  1037. if(tag!==lastTag||bBlock)addIndent();
  1038. results.push(html);
  1039. if(tagName==='br')addIndent();//回车强制换行
  1040. if(bBlock&&(emptyTags[tagName]||!bStart))lvl--;//块结束
  1041. lastTag=bBlock?tagName:'';lastTagStart=bStart;
  1042. }
  1043. else results.push(html);
  1044. }
  1045. function addIndent(){results.push('\r\n');if(lvl>0){var tabs=lvl;while(tabs--)results.push("\t");}}
  1046. //font转style
  1047. function font2style(all,tag,attrs,content)
  1048. {
  1049. if(!attrs)return content;
  1050. var styles='',f,s,c,style;
  1051. attrs=attrs.replace(/ face\s*=\s*"\s*([^"]*)\s*"/i,function(all,v){
  1052. if(v)styles+='font-family:'+v+';';
  1053. return '';
  1054. });
  1055. attrs=attrs.replace(/ size\s*=\s*"\s*(\d+)\s*"/i,function(all,v){
  1056. styles+='font-size:'+arrFontsize[(v>7?7:(v<1?1:v))-1].s+';';
  1057. return '';
  1058. });
  1059. attrs=attrs.replace(/ color\s*=\s*"\s*([^"]*)\s*"/i,function(all,v){
  1060. if(v)styles+='color:'+v+';';
  1061. return '';
  1062. });
  1063. attrs=attrs.replace(/ style\s*=\s*"\s*([^"]*)\s*"/i,function(all,v){
  1064. if(v)styles+=v;
  1065. return '';
  1066. });
  1067. attrs+=' style="'+styles+'"';
  1068. return attrs?('<span'+attrs+'>'+content+'</span>'):content;
  1069. }
  1070. sHtml = sHtml.replace(/<(font)(\s+[^>]*?)?>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?<\/\1>)*?)<\/\1>/ig,font2style);//第3层
  1071. sHtml = sHtml.replace(/<(font)(\s+[^>]*?)?>(((?!<\1(\s+[^>]*?)?>)[\s\S]|<\1(\s+[^>]*?)?>((?!<\1(\s+[^>]*?)?>)[\s\S])*?<\/\1>)*?)<\/\1>/ig,font2style);//第2层
  1072. sHtml = sHtml.replace(/<(font)(\s+[^>]*?)?>(((?!<\1(\s+[^>]*?)?>)[\s\S])*?)<\/\1>/ig,font2style);//最里层
  1073. sHtml = sHtml.replace(/^(\s*\r?\n)+|(\s*\r?\n)+$/g,'');//清理首尾换行
  1074. return sHtml;
  1075. }
  1076. this.toggleShowBlocktag=function(state)
  1077. {
  1078. if(bShowBlocktag===state)return;
  1079. bShowBlocktag=!bShowBlocktag;
  1080. var _jBody=$(_doc.body);
  1081. if(bShowBlocktag)
  1082. {
  1083. bodyClass+=' showBlocktag';
  1084. _jBody.addClass('showBlocktag');
  1085. }
  1086. else
  1087. {
  1088. bodyClass=bodyClass.replace(' showBlocktag','');
  1089. _jBody.removeClass('showBlocktag');
  1090. }
  1091. }
  1092. this.toggleSource=function(state)
  1093. {
  1094. if(bSource===state)return;
  1095. _jTools.find('[cmd=Source]').toggleClass('xheEnabled').toggleClass('xheActive');
  1096. var _body=_doc.body,jBody=$(_body),sHtml;
  1097. var sourceCode,cursorMark='<span id="_xhe_cursor"></span>',cursorPos=0;
  1098. var txtSourceTitle='';
  1099. if(!bSource)
  1100. {//转为源代码模式
  1101. _this.pasteHTML(cursorMark,true);//标记当前位置
  1102. sHtml=_this.getSource(true);
  1103. cursorPos=sHtml.indexOf(cursorMark);
  1104. if(!isOpera)cursorPos=sHtml.substring(0,cursorPos).replace(/\r/g,'').length;//修正非opera光标定位点
  1105. sHtml=sHtml.replace(/(\r?\n\s*|)<span id="_xhe_cursor"><\/span>(\s*\r?\n|)/,function(all,left,right){
  1106. return left&&right?'\r\n':left+right;//只有定位符的空行删除当前行
  1107. });
  1108. if(isIE)_body.contentEditable='false';
  1109. else _doc.designMode = 'Off';
  1110. jBody.attr('scroll','no').attr('class','sourceMode').html('<textarea id="sourceCode" wrap="soft" spellcheck="false" style="width:100%;height:100%" />');
  1111. sourceCode=$('#sourceCode',jBody).blur(_this.getSource)[0];
  1112. txtSourceTitle='可视化编辑';
  1113. }
  1114. else
  1115. {//转为编辑模式
  1116. sHtml=_this.getSource();
  1117. jBody.html('').removeAttr('scroll').attr('class','editMode'+bodyClass);
  1118. if(isIE)_body.contentEditable='true';
  1119. else _doc.designMode = 'On';
  1120. if(isMozilla)
  1121. {
  1122. _this._exec("inserthtml","-");//修正firefox源代码切换回来无法删除文字的问题
  1123. $('#'+idFixFFCursor).show().focus().hide();//临时修正Firefox 3.6光标丢失问题
  1124. }
  1125. txtSourceTitle='源代码';
  1126. }
  1127. bSource=!bSource;
  1128. _this.setSource(sHtml);
  1129. _this.focus();
  1130. if(bSource)//光标定位源码
  1131. {
  1132. if(sourceCode.setSelectionRange)sourceCode.setSelectionRange(cursorPos, cursorPos);
  1133. else
  1134. {
  1135. var rng = sourceCode.createTextRange();
  1136. rng.move("character",cursorPos);
  1137. rng.select();
  1138. }
  1139. }
  1140. else _this.setTextCursor();//定位最前面
  1141. _jTools.find('[cmd=Source]').attr('title',txtSourceTitle).find('span').text(txtSourceTitle);
  1142. _jTools.find('[cmd=Source],[cmd=Preview]').toggleClass('xheEnabled');
  1143. _jTools.find('.xheButton').not('[cmd=Source],[cmd=Fullscreen],[cmd=About]').toggleClass('xheEnabled').attr('aria-disabled',bSource?true:false);//无障碍支持
  1144. setTimeout(setOpts,300);
  1145. }
  1146. this.showPreview=function()
  1147. {
  1148. var beforeSetSource=settings.beforeSetSource,sContent=_this.getSource();
  1149. if(beforeSetSource)sContent=beforeSetSource(sContent);
  1150. var sHTML='<html><head>'+headHTML+'<title>预览</title>'+(urlBase?'<base href="'+urlBase+'"/>':'')+'</head><body>' + sContent + '</body></html>';
  1151. var screen=window.screen,oWindow=window.open('', 'xhePreview', 'toolbar=yes,location=no,status=yes,menubar=yes,scrollbars=yes,resizable=yes,width='+Math.round(screen.width*0.9)+',height='+Math.round(screen.height*0.8)+',left='+Math.round(screen.width*0.05)),oDoc=oWindow.document;
  1152. oDoc.open();
  1153. oDoc.write(sHTML);
  1154. oDoc.close();
  1155. oWindow.focus();
  1156. }
  1157. this.toggleFullscreen=function(state)
  1158. {
  1159. if(bFullscreen===state)return;
  1160. var jLayout=$('#'+idContainer).find('.xheLayout'),jContainer=$('#'+idContainer),browserVer=jQuery.browser.version,isIE67=(isIE&&(browserVer==6||browserVer==7));
  1161. if(bFullscreen)
  1162. {//取消全屏
  1163. if(isIE67)_jText.after(jContainer);
  1164. jLayout.attr('style',sLayoutStyle);
  1165. _jArea.height(editorHeight-_jTools.outerHeight());
  1166. $(window).scrollTop(outerScroll);
  1167. setTimeout(function(){$(window).scrollTop(outerScroll);},10);//Firefox需要延迟设置
  1168. }
  1169. else
  1170. {//显示全屏
  1171. if(isIE67)$('body').append(jContainer);
  1172. outerScroll=$(window).scrollTop();
  1173. sLayoutStyle=jLayout.attr('style');
  1174. jLayout.removeAttr('style');
  1175. _jArea.height('100%');
  1176. setTimeout(fixFullHeight,100);
  1177. }
  1178. if(isMozilla)//临时修正Firefox 3.6源代码光标丢失问题
  1179. {
  1180. $('#'+idFixFFCursor).show().focus().hide();
  1181. setTimeout(_this.focus,1);
  1182. }
  1183. else if(isIE67)_this.setTextCursor();
  1184. bFullscreen=!bFullscreen;
  1185. jContainer.toggleClass('xhe_Fullscreen');
  1186. $('html').toggleClass('xhe_Fullfix');
  1187. _jTools.find('[cmd=Fullscreen]').toggleClass('xheActive');
  1188. setTimeout(setOpts,300);
  1189. }
  1190. this.showMenu=function(menuitems,callback)
  1191. {
  1192. var jMenu=$('<div class="xheMenu"></div>'),menuSize=menuitems.length,arrItem=[];
  1193. $.each(menuitems,function(n,v){
  1194. if(v.s==='-'){
  1195. arrItem.push('<div class="xheMenuSeparator"></div>');
  1196. }else{
  1197. arrItem.push('<a href="javascript:void(\''+v.v+'\')" title="'+(v.t?v.t:v.s)+'" v="'+v.v+'" role="option" aria-setsize="'+menuSize+'" aria-posinset="'+(n+1)+'" tabindex="0">'+v.s+'</a>');
  1198. }
  1199. });
  1200. jMenu.append(arrItem.join(''));
  1201. jMenu.click(function(ev){
  1202. ev=ev.target;
  1203. if($.nodeName(ev,'DIV'))return;
  1204. _this.loadBookmark();
  1205. callback($(ev).closest('a').attr('v'));
  1206. _this.hidePanel();
  1207. return false;
  1208. }).mousedown(returnFalse);
  1209. _this.saveBookmark();
  1210. _this.showPanel(jMenu);
  1211. }
  1212. this.showColor=function(callback)
  1213. {
  1214. var jColor=$('<div class="xheColor"></div>'),arrItem=[],colorSize=itemColors.length,count=0;
  1215. $.each(itemColors,function(n,v)
  1216. {
  1217. if(count%7===0)arrItem.push((count>0?'</div>':'')+'<div>');
  1218. arrItem.push('<a href="javascript:void(\''+v+'\')" xhev="'+v+'" title="'+v+'" style="background:'+v+'" role="option" aria-setsize="'+colorSize+'" aria-posinset="'+(count+1)+'"></a>');
  1219. count++;
  1220. });
  1221. arrItem.push('</div>');
  1222. jColor.append(arrItem.join(''));
  1223. jColor.click(function(ev){
  1224. ev=ev.target;
  1225. if(!$.nodeName(ev,'A'))return;
  1226. _this.loadBookmark();
  1227. callback($(ev).attr('xhev'));
  1228. _this.hidePanel();
  1229. return false;
  1230. }).mousedown(returnFalse);
  1231. _this.saveBookmark();
  1232. _this.showPanel(jColor);
  1233. }
  1234. this.showPastetext=function()
  1235. {
  1236. var jPastetext=$(htmlPastetext),jValue=$('#xhePastetextValue',jPastetext),jSave=$('#xheSave',jPastetext);
  1237. jSave.click(function(){
  1238. _this.loadBookmark();
  1239. var sValue=jValue.val();
  1240. if(sValue)_this.pasteText(sValue);
  1241. _this.hidePanel();
  1242. return false;
  1243. });
  1244. _this.saveBookmark();
  1245. _this.showDialog(jPastetext);
  1246. }
  1247. this.showLink=function()
  1248. {
  1249. var htmlTemp=htmlLink,$arrAnchor=_jDoc.find('a[name]').not('[href]'),haveAnchor=$arrAnchor.length>0;
  1250. if(haveAnchor){//页内有锚点
  1251. var arrAnchorOptions=[];
  1252. $arrAnchor.each(function(){
  1253. var name=$(this).attr('name');
  1254. arrAnchorOptions.push('<option value="#'+name+'">'+name+'</option>');
  1255. });
  1256. htmlTemp=htmlTemp.replace(/(<div><label for="xheLinkTarget)/,'<div><label for="xheLinkAnchor">页内锚点: </label><select id="xheLinkAnchor"><option value="">未选择</option>'+arrAnchorOptions.join('')+'</select></div>$1');
  1257. }
  1258. var jLink=$(htmlTemp),jParent=_this.getParent('a'),jText=$('#xheLinkText',jLink),jUrl=$('#xheLinkUrl',jLink),jTarget=$('#xheLinkTarget',jLink),jSave=$('#xheSave',jLink),selHtml=_this.getSelect();
  1259. if(haveAnchor){
  1260. jLink.find('#xheLinkAnchor').change(function(){
  1261. var anchor=$(this).val();
  1262. if(anchor!='')jUrl.val(anchor);
  1263. });
  1264. }
  1265. if(jParent.length===1)
  1266. {
  1267. if(!jParent.attr('href')){//锚点
  1268. ev=null;
  1269. return _this.exec('Anchor');
  1270. }
  1271. jUrl.val(xheAttr(jParent,'href'));
  1272. jTarget.attr('value',jParent.attr('target'));
  1273. }
  1274. else if(selHtml==='')jText.val(settings.defLinkText).closest('div').show();
  1275. if(settings.upLinkUrl)_this.uploadInit(jUrl,settings.upLinkUrl,settings.upLinkExt);
  1276. jSave.click(function(){
  1277. _this.loadBookmark();
  1278. var url=jUrl.val();
  1279. if(url===''||jParent.length===0)_this._exec('unlink');
  1280. if(url!==''&&url!=='http://')
  1281. {
  1282. var aUrl=url.split(' '),sTarget=jTarget.val(),sText=jText.val();
  1283. if(aUrl.length>1)
  1284. {//批量插入
  1285. _this._exec('unlink');//批量前删除当前链接并重新获取选择内容
  1286. selHtml=_this.getSelect();
  1287. var sTemplate='<a href="xhe_tmpurl"',sLink,arrLink=[];
  1288. if(sTarget!=='')sTemplate+=' target="'+sTarget+'"';
  1289. sTemplate+='>xhe_tmptext</a>';
  1290. sText=(selHtml!==''?selHtml:(sText?sText:url));
  1291. for(var i=0,c=aUrl.length;i<c;i++)
  1292. {
  1293. url=aUrl[i];
  1294. if(url!=='')
  1295. {
  1296. url=url.split('||');
  1297. sLink=sTemplate;
  1298. sLink=sLink.replace('xhe_tmpurl',url[0]);
  1299. sLink=sLink.replace('xhe_tmptext',url[1]?url[1]:sText);
  1300. arrLink.push(sLink);
  1301. }
  1302. }
  1303. _this.pasteHTML(arrLink.join('&nbsp;'));
  1304. }
  1305. else
  1306. {//单url模式
  1307. url=aUrl[0].split('||');
  1308. if(!sText)sText=url[0];
  1309. sText=url[1]?url[1]:(selHtml!=='')?'':sText?sText:url[0];
  1310. if(jParent.length===0)
  1311. {
  1312. if(sText)_this.pasteHTML('<a href="#xhe_tmpurl">'+sText+'</a>');
  1313. else _this._exec('createlink','#xhe_tmpurl');
  1314. jParent=$('a[href$="#xhe_tmpurl"]',_doc);
  1315. }
  1316. else if(sText&&!isSafari)jParent.text(sText);//safari改写文本会导致光标丢失
  1317. xheAttr(jParent,'href',url[0]);
  1318. if(sTarget!=='')jParent.attr('target',sTarget);
  1319. else jParent.removeAttr('target');
  1320. }
  1321. }
  1322. _this.hidePanel();
  1323. return false;
  1324. });
  1325. _this.saveBookmark();
  1326. _this.showDialog(jLink);
  1327. }
  1328. this.showAnchor=function(){
  1329. var jAnchor=$(htmlAnchor),jParent=_this.getParent('a'),jName=$('#xheAnchorName',jAnchor),jSave=$('#xheSave',jAnchor);
  1330. if(jParent.length===1){
  1331. if(jParent.attr('href')){//超链接
  1332. ev=null;
  1333. return _this.exec('Link');
  1334. }
  1335. jName.val(jParent.attr('name'));
  1336. }
  1337. jSave.click(function(){
  1338. _this.loadBookmark();
  1339. var name=jName.val();
  1340. if(name){
  1341. if(jParent.length===0)_this.pasteHTML('<a name="'+name+'"></a>');
  1342. else jParent.attr('name',name);
  1343. }
  1344. else if(jParent.length===1)jParent.remove();
  1345. _this.hidePanel();
  1346. return false;
  1347. });
  1348. _this.saveBookmark();
  1349. _this.showDialog(jAnchor);
  1350. }
  1351. this.showImg=function()
  1352. {
  1353. var jImg=$(htmlImg),jParent=_this.getParent('img'),jUrl=$('#xheImgUrl',jImg),jAlt=$('#xheImgAlt',jImg),jAlign=$('#xheImgAlign',jImg),jWidth=$('#xheImgWidth',jImg),jHeight=$('#xheImgHeight',jImg),jBorder=$('#xheImgBorder',jImg),jVspace=$('#xheImgVspace',jImg),jHspace=$('#xheImgHspace',jImg),jSave=$('#xheSave',jImg);
  1354. if(jParent.length===1)
  1355. {
  1356. jUrl.val(xheAttr(jParent,'src'));
  1357. jAlt.val(jParent.attr('alt'));
  1358. jAlign.val(jParent.attr('align'));
  1359. jWidth.val(jParent.attr('width'));
  1360. jHeight.val(jParent.attr('height'));
  1361. jBorder.val(jParent.attr('border'));
  1362. var vspace=jParent.attr('vspace'),hspace=jParent.attr('hspace');
  1363. jVspace.val(vspace<=0?'':vspace);
  1364. jHspace.val(hspace<=0?'':hspace);
  1365. }
  1366. if(settings.upImgUrl)_this.uploadInit(jUrl,settings.upImgUrl,settings.upImgExt);
  1367. jSave.click(function(){
  1368. _this.loadBookmark();
  1369. var url=jUrl.val();
  1370. if(url!==''&&url!=='http://')
  1371. {
  1372. var aUrl=url.split(' '),sAlt=jAlt.val(),sAlign=jAlign.val(),sWidth=jWidth.val(),sHeight=jHeight.val(),sBorder=jBorder.val(),sVspace=jVspace.val(),sHspace=jHspace.val();;
  1373. if(aUrl.length>1)
  1374. {//批量插入
  1375. var sTemplate='<img src="xhe_tmpurl"',sImg,arrImg=[];
  1376. if(sAlt!=='')sTemplate+=' alt="'+sAlt+'"';
  1377. if(sAlign!=='')sTemplate+=' align="'+sAlign+'"';
  1378. if(sWidth!=='')sTemplate+=' width="'+sWidth+'"';
  1379. if(sHeight!=='')sTemplate+=' height="'+sHeight+'"';
  1380. if(sBorder!=='')sTemplate+=' border="'+sBorder+'"';
  1381. if(sVspace!=='')sTemplate+=' vspace="'+sVspace+'"';
  1382. if(sHspace!=='')sTemplate+=' hspace="'+sHspace+'"';
  1383. sTemplate+=' />';
  1384. for(var i in aUrl)
  1385. {
  1386. url=aUrl[i];
  1387. if(url!=='')
  1388. {
  1389. url=url.split('||');
  1390. sImg=sTemplate;
  1391. sImg=sImg.replace('xhe_tmpurl',url[0]);
  1392. if(url[1])sImg='<a href="'+url[1]+'" target="_blank">'+sImg+'</a>'
  1393. arrImg.push(sImg);
  1394. }
  1395. }
  1396. _this.pasteHTML(arrImg.join('&nbsp;'));
  1397. }
  1398. else if(aUrl.length===1)
  1399. {//单URL模式
  1400. url=aUrl[0];
  1401. if(url!=='')
  1402. {
  1403. url=url.split('||');
  1404. if(jParent.length===0)
  1405. {
  1406. _this.pasteHTML('<img src="'+url[0]+'#xhe_tmpurl" />');
  1407. jParent=$('img[src$="#xhe_tmpurl"]',_doc);
  1408. }
  1409. xheAttr(jParent,'src',url[0]);
  1410. if(sAlt!=='')jParent.attr('alt',sAlt);
  1411. if(sAlign!=='')jParent.attr('align',sAlign);
  1412. else jParent.removeAttr('align');
  1413. if(sWidth!=='')jParent.attr('width',sWidth);
  1414. else jParent.removeAttr('width');
  1415. if(sHeight!=='')jParent.attr('height',sHeight);
  1416. else jParent.removeAttr('height');
  1417. if(sBorder!=='')jParent.attr('border',sBorder);
  1418. else jParent.removeAttr('border');
  1419. if(sVspace!=='')jParent.attr('vspace',sVspace);
  1420. else jParent.removeAttr('vspace');
  1421. if(sHspace!=='')jParent.attr('hspace',sHspace);
  1422. else jParent.removeAttr('hspace');
  1423. if(url[1])
  1424. {
  1425. var jLink=jParent.parent('a');
  1426. if(jLink.length===0)
  1427. {
  1428. jParent.wrap('<a></a>');
  1429. jLink=jParent.parent('a');
  1430. }
  1431. xheAttr(jLink,'href',url[1]);
  1432. jLink.attr('target','_blank');
  1433. }
  1434. }
  1435. }
  1436. }
  1437. else if(jParent.length===1)jParent.remove();
  1438. _this.hidePanel();
  1439. return false;
  1440. });
  1441. _this.saveBookmark();
  1442. _this.showDialog(jImg);
  1443. }
  1444. this.showEmbed=function(sType,sHtml,sMime,sClsID,sBaseAttrs,sUploadUrl,sUploadExt)
  1445. {
  1446. var jEmbed=$(sHtml),jParent=_this.getParent('embed[type="'+sMime+'"],embed[classid="'+sClsID+'"]'),jUrl=$('#xhe'+sType+'Url',jEmbed),jWidth=$('#xhe'+sType+'Width',jEmbed),jHeight=$('#xhe'+sType+'Height',jEmbed),jSave=$('#xheSave',jEmbed);
  1447. if(sUploadUrl)_this.uploadInit(jUrl,sUploadUrl,sUploadExt);
  1448. if(jParent.length===1)
  1449. {
  1450. jUrl.val(xheAttr(jParent,'src'));
  1451. jWidth.val(jParent.attr('width'));
  1452. jHeight.val(jParent.attr('height'));
  1453. }
  1454. jSave.click(function(){
  1455. _this.loadBookmark();
  1456. var url=jUrl.val();
  1457. if(url!==''&&url!=='http://')
  1458. {
  1459. var w=jWidth.val(),h=jHeight.val(),reg=/^\d+%?$/;
  1460. if(!reg.test(w))w=412;if(!reg.test(h))h=300;
  1461. var sBaseCode='<embed type="'+sMime+'" classid="'+sClsID+'" src="xhe_tmpurl"'+sBaseAttrs;
  1462. var aUrl=url.split(' ');
  1463. if(aUrl.length>1)
  1464. {//批量插入
  1465. var sTemplate=sBaseCode+'',sEmbed,arrEmbed=[];
  1466. sTemplate+=' width="xhe_width" height="xhe_height" />';
  1467. for(var i in aUrl)
  1468. {
  1469. url=aUrl[i].split('||');
  1470. sEmbed=sTemplate;
  1471. sEmbed=sEmbed.replace('xhe_tmpurl',url[0])
  1472. sEmbed=sEmbed.replace('xhe_width',url[1]?url[1]:w)
  1473. sEmbed=sEmbed.replace('xhe_height',url[2]?url[2]:h)
  1474. if(url!=='')arrEmbed.push(sEmbed);
  1475. }
  1476. _this.pasteHTML(arrEmbed.join('&nbsp;'));
  1477. }
  1478. else if(aUrl.length===1)
  1479. {//单URL模式
  1480. url=aUrl[0].split('||');
  1481. if(jParent.length===0)
  1482. {
  1483. _this.pasteHTML(sBaseCode.replace('xhe_tmpurl',url[0]+'#xhe_tmpurl')+' />');
  1484. jParent=$('embed[src$="#xhe_tmpurl"]',_doc);
  1485. }
  1486. xheAttr(jParent,'src',url[0]);
  1487. jParent.attr('width',url[1]?url[1]:w);
  1488. jParent.attr('height',url[2]?url[2]:h);
  1489. }
  1490. }
  1491. else if(jParent.length===1)jParent.remove();
  1492. _this.hidePanel();
  1493. return false;
  1494. });
  1495. _this.saveBookmark();
  1496. _this.showDialog(jEmbed);
  1497. }
  1498. this.showEmot=function(group)
  1499. {
  1500. var jEmot=$('<div class="xheEmot"></div>');
  1501. group=group?group:(selEmotGroup?selEmotGroup:'default');
  1502. var arrEmot=arrEmots[group];
  1503. var sEmotPath=emotPath+group+'/',n=0,arrList=[],jList='';
  1504. var ew=arrEmot.width,eh=arrEmot.height,line=arrEmot.line,count=arrEmot.count,list=arrEmot.list;
  1505. if(count)
  1506. {
  1507. for(var i=1;i<=count;i++)
  1508. {
  1509. n++;
  1510. arrList.push('<a href="javascript:void(\''+i+'\')" style="background-image:url('+sEmotPath+i+'.gif);" emot="'+group+','+i+'" xhev="" title="'+i+'" role="option">&nbsp;</a>');
  1511. if(n%line===0)arrList.push('<br />');
  1512. }
  1513. }
  1514. else
  1515. {
  1516. $.each(list,function(id,title)
  1517. {
  1518. n++;
  1519. arrList.push('<a href="javascript:void(\''+title+'\')" style="background-image:url('+sEmotPath+id+'.gif);" emot="'+group+','+id+'" title="'+title+'" xhev="'+title+'" role="option">&nbsp;</a>');
  1520. if(n%line===0)arrList.push('<br />');
  1521. });
  1522. }
  1523. var w=line*(ew+12),h=Math.ceil(n/line)*(eh+12),mh=w*0.75;
  1524. if(h<=mh)mh='';
  1525. jList=$('<style>'+(mh?'.xheEmot div{width:'+(w+20)+'px;height:'+mh+'px;}':'')+'.xheEmot div a{width:'+ew+'px;height:'+eh+'px;}</style><div>'+arrList.join('')+'</div>').click(function(ev){ev=ev.target;var jA=$(ev);if(!$.nodeName(ev,'A'))return;_this.loadBookmark();_this.pasteHTML('<img emot="'+jA.attr('emot')+'" alt="'+jA.attr('xhev')+'">');_this.hidePanel();return false;}).mousedown(returnFalse);
  1526. jEmot.append(jList);
  1527. var gcount=0,arrGroup=['<ul role="tablist">'],jGroup;//表情分类
  1528. $.each(arrEmots,function(g,v){
  1529. gcount++;
  1530. arrGroup.push('<li'+(group===g?' class="cur"':'')+' role="presentation"><a href="javascript:void(\''+v.name+'\')" group="'+g+'" role="tab" tabindex="0">'+v.name+'</a></li>');
  1531. });
  1532. if(gcount>1)
  1533. {
  1534. arrGroup.push('</ul><br style="clear:both;" />');
  1535. jGroup=$(arrGroup.join('')).click(function(ev){selEmotGroup=$(ev.target).attr('group');_this.exec('Emot');return false;}).mousedown(returnFalse);
  1536. jEmot.append(jGroup);
  1537. }
  1538. _this.saveBookmark();
  1539. _this.showPanel(jEmot);
  1540. }
  1541. this.showTable=function()
  1542. {
  1543. var jTable=$(htmlTable),jRows=$('#xheTableRows',jTable),jColumns=$('#xheTableColumns',jTable),jHeaders=$('#xheTableHeaders',jTable),jWidth=$('#xheTableWidth',jTable),jHeight=$('#xheTableHeight',jTable),jBorder=$('#xheTableBorder',jTable),jCellSpacing=$('#xheTableCellSpacing',jTable),jCellPadding=$('#xheTableCellPadding',jTable),jAlign=$('#xheTableAlign',jTable),jCaption=$('#xheTableCaption',jTable),jSave=$('#xheSave',jTable);
  1544. jSave.click(function(){
  1545. _this.loadBookmark();
  1546. var sCaption=jCaption.val(),sBorder=jBorder.val(),sRows=jRows.val(),sCols=jColumns.val(),sHeaders=jHeaders.val(),sWidth=jWidth.val(),sHeight=jHeight.val(),sCellSpacing=jCellSpacing.val(),sCellPadding=jCellPadding.val(),sAlign=jAlign.val();
  1547. var i,j,htmlTable='<table'+(sBorder!==''?' border="'+sBorder+'"':'')+(sWidth!==''?' width="'+sWidth+'"':'')+(sHeight!==''?' height="'+sHeight+'"':'')+(sCellSpacing!==''?' cellspacing="'+sCellSpacing+'"':'')+(sCellPadding!==''?' cellpadding="'+sCellPadding+'"':'')+(sAlign!==''?' align="'+sAlign+'"':'')+'>';
  1548. if(sCaption!=='')htmlTable+='<caption>'+sCaption+'</caption>';
  1549. if(sHeaders==='row'||sHeaders==='both')
  1550. {
  1551. htmlTable+='<tr>';
  1552. for(i=0;i<sCols;i++)htmlTable+='<th scope="col"></th>';
  1553. htmlTable+='</tr>';
  1554. sRows--;
  1555. }
  1556. htmlTable+='<tbody>';
  1557. for(i=0;i<sRows;i++)
  1558. {
  1559. htmlTable+='<tr>';
  1560. for(j=0;j<sCols;j++)
  1561. {
  1562. if(j===0&&(sHeaders==='col'||sHeaders==='both'))htmlTable+='<th scope="row"></th>';
  1563. else htmlTable+='<td></td>';
  1564. }
  1565. htmlTable+='</tr>';
  1566. }
  1567. htmlTable+='</tbody></table>';
  1568. _this.pasteHTML(htmlTable);
  1569. _this.hidePanel();
  1570. return false;
  1571. });
  1572. _this.saveBookmark();
  1573. _this.showDialog(jTable);
  1574. }
  1575. this.showAbout=function()
  1576. {
  1577. var jAbout=$(htmlAbout);
  1578. jAbout.find('p').attr('role','presentation');//无障碍支持
  1579. _this.showDialog(jAbout,true);
  1580. setTimeout(function(){jAbout.focus();},100);
  1581. }
  1582. this.addShortcuts=function(key,cmd)
  1583. {
  1584. key=key.toLowerCase();
  1585. if(arrShortCuts[key]===undefined)arrShortCuts[key]=Array();
  1586. arrShortCuts[key].push(cmd);
  1587. }
  1588. this.delShortcuts=function(key){delete arrShortCuts[key];}
  1589. this.uploadInit=function(jText,toUrl,upext)
  1590. {
  1591. var jUpload=$('<span class="xheUpload"><input type="text" style="visibility:hidden;" tabindex="-1" /><input type="button" value="'+settings.upBtnText+'" class="xheBtn" tabindex="-1" /></span>'),jUpBtn=$('.xheBtn',jUpload);
  1592. var bHtml5Upload=settings.html5Upload,upMultiple=bHtml5Upload?settings.upMultiple:1;
  1593. jText.after(jUpload);jUpBtn.before(jText);
  1594. toUrl=toUrl.replace(/{editorRoot}/ig,editorRoot);
  1595. if(toUrl.substr(0,1)==='!')//自定义上传管理页
  1596. {
  1597. jUpBtn.click(function(){_this.showIframeModal('上传文件',toUrl.substr(1),setUploadMsg,null,null);});
  1598. }
  1599. else
  1600. {//系统默认ajax上传
  1601. jUpload.append('<input type="file"'+(upMultiple>1?' multiple=""':'')+' class="xheFile" size="13" name="'+uploadInputname+'" tabindex="-1" />');
  1602. var jFile=$('.xheFile',jUpload),arrMsg;
  1603. jFile.change(function(){arrMsg=[];_this.startUpload(jFile[0],toUrl,upext,setUploadMsg);});
  1604. setTimeout(function(){//拖放上传
  1605. jText.closest('.xheDialog').bind('dragenter dragover',returnFalse).bind('drop',function(ev){
  1606. var dataTransfer=ev.originalEvent.dataTransfer,fileList;
  1607. if(bHtml5Upload&&dataTransfer&&(fileList=dataTransfer.files)&&fileList.length>0)_this.startUpload(fileList,toUrl,upext,setUploadMsg);
  1608. return false;
  1609. });
  1610. },10);
  1611. }
  1612. function setUploadMsg(arrMsg)
  1613. {
  1614. if(is(arrMsg,'string'))arrMsg=[arrMsg];//允许单URL传递
  1615. var bImmediate=false,i,count=arrMsg.length,msg,url,arrUrl=[],onUpload=settings.onUpload;
  1616. if(onUpload)onUpload(arrMsg);//用户上传回调
  1617. for(i=0;i<count;i++)
  1618. {
  1619. msg=arrMsg[i];
  1620. url=is(msg,'string')?msg:msg.url;
  1621. if(url.substr(0,1)==='!'){bImmediate=true;url=url.substr(1);}
  1622. arrUrl.push(url);
  1623. }
  1624. jText.val(arrUrl.join(' '));
  1625. if(bImmediate)jText.closest('.xheDialog').find('#xheSave').click();
  1626. }
  1627. }
  1628. this.startUpload=function(fromFiles,toUrl,limitExt,onUploadComplete)
  1629. {
  1630. var arrMsg=[],bHtml5Upload=settings.html5Upload,upMultiple=bHtml5Upload?settings.upMultiple:1;
  1631. var upload,fileList,filename,jUploadTip=$('<div style="padding:22px 0;text-align:center;line-height:30px;">文件上传中,请稍候……<br /></div>'),sLoading='<img src="'+skinPath+'img/loading.gif">';
  1632. if(isOpera||!bHtml5Upload||(fromFiles.nodeType&&!((fileList=fromFiles.files)&&fileList[0].name)))
  1633. {
  1634. if(!checkFileExt(fromFiles.value,limitExt))return;
  1635. jUploadTip.append(sLoading);
  1636. upload=new _this.html4Upload(fromFiles,toUrl,onUploadCallback);
  1637. }
  1638. else
  1639. {
  1640. if(!fileList)fileList=fromFiles;//拖放文件列表
  1641. var i,len=fileList.length;
  1642. if(len>upMultiple){
  1643. alert('请不要一次上传超过'+upMultiple+'个文件');
  1644. return;
  1645. }
  1646. for(i=0;i<len;i++)if(!checkFileExt(fileList[i].name,limitExt))return;
  1647. var jProgress=$('<div class="xheProgress"><div><span>0%</span></div></div>');
  1648. jUploadTip.append(jProgress);
  1649. upload=new _this.html5Upload(uploadInputname,fileList,toUrl,onUploadCallback,function(ev){
  1650. if(ev.loaded>=0)
  1651. {
  1652. var sPercent=Math.round((ev.loaded * 100) / ev.total)+'%';
  1653. $('div',jProgress).css('width',sPercent);
  1654. $('span',jProgress).text(sPercent+' ( '+formatBytes(ev.loaded)+' / '+formatBytes(ev.total)+' )');
  1655. }
  1656. else jProgress.replaceWith(sLoading);//不支持进度
  1657. });
  1658. }
  1659. _this.showModal('文件上传中(Esc取消上传)',jUploadTip,320,150);
  1660. upload.start();
  1661. function onUploadCallback(sText,bFinish)
  1662. {
  1663. var data=Object,bOK=false;
  1664. try{data=eval('('+sText+')');}catch(ex){};
  1665. if(data.err===undefined||data.msg===undefined)alert(toUrl+' 上传接口发生错误!\r\n\r\n返回的错误内容为: \r\n\r\n'+sText);
  1666. else
  1667. {
  1668. if(data.err)alert(data.err);
  1669. else
  1670. {
  1671. arrMsg.push(data.msg);
  1672. bOK=true;//继续下一个文件上传
  1673. }
  1674. }
  1675. if(!bOK||bFinish)_this.removeModal();
  1676. if(bFinish&&bOK)onUploadComplete(arrMsg);//全部上传完成
  1677. return bOK;
  1678. }
  1679. }
  1680. this.html4Upload=function(fromfile,toUrl,callback)
  1681. {
  1682. var uid = new Date().getTime(),idIO='jUploadFrame'+uid,_this=this;
  1683. var jIO=$('<iframe name="'+idIO+'" class="xheHideArea" />').appendTo('body');
  1684. var jForm=$('<form action="'+toUrl+'" target="'+idIO+'" method="post" enctype="multipart/form-data" class="xheHideArea"></form>').appendTo('body');
  1685. var jOldFile = $(fromfile),jNewFile = jOldFile.clone().attr('disabled','true');
  1686. jOldFile.before(jNewFile).appendTo(jForm);
  1687. this.remove=function()
  1688. {
  1689. if(_this!==null)
  1690. {
  1691. jNewFile.before(jOldFile).remove();
  1692. jIO.remove();jForm.remove();
  1693. _this=null;
  1694. }
  1695. }
  1696. this.onLoad=function(){
  1697. var ifmDoc=jIO[0].contentWindow.document,result=$(ifmDoc.body).text();
  1698. ifmDoc.write('');
  1699. _this.remove();
  1700. callback(result,true);
  1701. }
  1702. this.start=function(){jForm.submit();jIO.load(_this.onLoad);}
  1703. return this;
  1704. }
  1705. this.html5Upload=function(inputname,fromFiles,toUrl,callback,onProgress)
  1706. {
  1707. var xhr,i=0,count=fromFiles.length,allLoaded=0,allSize=0,_this=this;
  1708. for(var j=0;j<count;j++)allSize+=fromFiles[j].size;
  1709. this.remove=function(){if(xhr){xhr.abort();xhr=null;}}
  1710. this.uploadNext=function(sText)
  1711. {
  1712. if(sText)//当前文件上传完成
  1713. {
  1714. allLoaded+=fromFiles[i-1].size;
  1715. returnProgress(0);
  1716. }
  1717. if((!sText||(sText&&callback(sText,i===count)===true))&&i<count)postFile(fromFiles[i++],toUrl,_this.uploadNext,function(loaded){returnProgress(loaded);});
  1718. }
  1719. this.start=function(){_this.uploadNext();}
  1720. function postFile(fromfile,toUrl,callback,onProgress)
  1721. {
  1722. xhr = new XMLHttpRequest(),upload=xhr.upload;
  1723. xhr.onreadystatechange=function(){
  1724. if(xhr.readyState===4)callback(xhr.responseText);
  1725. };
  1726. if(upload)upload.onprogress=function(ev){
  1727. onProgress(ev.loaded);
  1728. };
  1729. else onProgress(-1);//不支持进度
  1730. xhr.open("POST", toUrl);
  1731. xhr.setRequestHeader('Content-Type', 'application/octet-stream');
  1732. xhr.setRequestHeader('Content-Disposition', 'attachment; name="'+encodeURIComponent(inputname)+'"; filename="'+encodeURIComponent(fromfile.name)+'"');
  1733. if(xhr.sendAsBinary&&fromfile.getAsBinary)xhr.sendAsBinary(fromfile.getAsBinary());
  1734. else xhr.send(fromfile);
  1735. }
  1736. function returnProgress(loaded){
  1737. if(onProgress)onProgress({'loaded':allLoaded+loaded,'total':allSize});
  1738. }
  1739. }
  1740. this.showIframeModal=function(title,url,callback,w,h,onRemove)
  1741. {
  1742. var jContent=$('<iframe frameborder="0" src="'+url.replace(/{editorRoot}/ig,editorRoot)+(/\?/.test(url)?'&':'?')+'parenthost='+location.host+'" style="width:100%;height:100%;display:none;" /><div class="xheModalIfmWait"></div>'),jIframe=jContent.eq(0),jWait=jContent.eq(1);
  1743. _this.showModal(title,jContent,w,h,onRemove);
  1744. var modalWin=jIframe[0].contentWindow,result;
  1745. initModalWin();
  1746. jIframe.load(function(){
  1747. initModalWin();//初始化接口
  1748. if(result){//跨域,取返回值
  1749. var bResult=true;
  1750. try{
  1751. result=eval('('+unescape(result)+')');
  1752. }
  1753. catch(e){
  1754. bResult=false;
  1755. }
  1756. if(bResult)return callbackModal(result);
  1757. }
  1758. if(jWait.is(':visible')){//显示内页
  1759. jIframe.show().focus();
  1760. jWait.remove();
  1761. }
  1762. });
  1763. //初始化接口
  1764. function initModalWin(){
  1765. try{
  1766. modalWin.callback=callbackModal;
  1767. modalWin.unloadme=_this.removeModal;
  1768. $(modalWin.document).keydown(checkEsc);
  1769. result=modalWin.name;
  1770. }
  1771. catch(ex){}
  1772. }
  1773. //模式窗口回调
  1774. function callbackModal(v){
  1775. modalWin.document.write('');
  1776. _this.removeModal();
  1777. if(v!=null)callback(v);
  1778. }
  1779. }
  1780. this.showModal=function(title,content,w,h,onRemove)
  1781. {
  1782. if(bShowModal)return false;//只能弹出一个模式窗口
  1783. _this.panelState=bShowPanel;
  1784. bShowPanel=false;//防止按钮面板被关闭
  1785. layerShadow=settings.layerShadow;
  1786. w=w?w:settings.modalWidth;h=h?h:settings.modalHeight;
  1787. jModal=$('<div class="xheModal" style="width:'+(w-1)+'px;height:'+h+'px;margin-left:-'+Math.ceil(w/2)+'px;'+(isIE&&browerVer<7.0?'':'margin-top:-'+Math.ceil(h/2)+'px')+'">'+(settings.modalTitle?'<div class="xheModalTitle"><span class="xheModalClose" title="关闭 (Esc)" tabindex="0" role="button"></span>'+title+'</div>':'')+'<div class="xheModalContent"></div></div>').appendTo('body');
  1788. jOverlay=$('<div class="xheModalOverlay"></div>').appendTo('body');
  1789. if(layerShadow>0)jModalShadow=$('<div class="xheModalShadow" style="width:'+jModal.outerWidth()+'px;height:'+jModal.outerHeight()+'px;margin-left:-'+(Math.ceil(w/2)-layerShadow-2)+'px;'+(isIE&&browerVer<7.0?'':'margin-top:-'+(Math.ceil(h/2)-layerShadow-2)+'px')+'"></div>').appendTo('body');
  1790. $('.xheModalContent',jModal).css('height',h-(settings.modalTitle?$('.xheModalTitle').outerHeight():0)).html(content);
  1791. if(isIE&&browerVer===6.0)jHideSelect=$('select:visible').css('visibility','hidden');//隐藏覆盖的select
  1792. $('.xheModalClose',jModal).click(_this.removeModal);
  1793. jOverlay.show();
  1794. if(layerShadow>0)jModalShadow.show();
  1795. jModal.show();
  1796. setTimeout(function(){jModal.find('a,input[type=text],textarea').filter(':visible').filter(function(){return $(this).css('visibility')!=='hidden';}).eq(0).focus();},10);//定位首个可见输入表单项,延迟解决opera无法设置焦点
  1797. bShowModal=true;
  1798. onModalRemove=onRemove;
  1799. }
  1800. this.removeModal=function(){
  1801. if(jHideSelect)jHideSelect.css('visibility','visible');
  1802. jModal.html('').remove();
  1803. if(layerShadow>0)jModalShadow.remove();
  1804. jOverlay.remove();
  1805. if(onModalRemove)onModalRemove();
  1806. bShowModal=false;
  1807. bShowPanel=_this.panelState;
  1808. };
  1809. this.showDialog=function(content,bNoFocus)
  1810. {
  1811. var jDialog=$('<div class="xheDialog"></div>'),jContent=$(content),jSave=$('#xheSave',jContent);
  1812. if(jSave.length===1)
  1813. {
  1814. jContent.find('input[type=text],select').keypress(function(ev){if(ev.which===13){jSave.click();return false;}});
  1815. jContent.find('textarea').keydown(function(ev){if(ev.ctrlKey&&ev.which===13){jSave.click();return false;}});
  1816. jSave.after(' <input type="button" id="xheCancel" value="取消" />');
  1817. $('#xheCancel',jContent).click(_this.hidePanel);
  1818. if(!settings.clickCancelDialog)
  1819. {
  1820. bClickCancel=false;//关闭点击隐藏
  1821. var jFixCancel=$('<div class="xheFixCancel"></div>').appendTo('body').mousedown(returnFalse);
  1822. var xy=_jArea.offset();
  1823. jFixCancel.css({'left':xy.left,'top':xy.top,width:_jArea.outerWidth(),height:_jArea.outerHeight()})
  1824. }
  1825. jDialog.mousedown(function(){bDisableHoverExec=true;})//点击对话框禁止悬停执行
  1826. }
  1827. jDialog.append(jContent);
  1828. _this.showPanel(jDialog,bNoFocus);
  1829. }
  1830. this.showPanel=function(content,bNoFocus)
  1831. {
  1832. if(!ev.target)return false;
  1833. _jPanel.html('').append(content).css('left',-999).css('top',-999);
  1834. _jPanelButton=$(ev.target).closest('a').addClass('xheActive');
  1835. var xy=_jPanelButton.offset();
  1836. var x=xy.left,y=xy.top;y+=_jPanelButton.outerHeight()-1;
  1837. _jCntLine.css({'left':x+1,'top':y,'width':_jPanelButton.width()}).show();
  1838. var _docElem=document.documentElement,body=document.body;
  1839. if((x+_jPanel.outerWidth())>((window.pageXOffset||_docElem.scrollLeft||body.scrollLeft)+(_docElem.clientWidth||body.clientWidth)))x-=(_jPanel.outerWidth()-_jPanelButton.outerWidth());//向左显示面板
  1840. var layerShadow=settings.layerShadow;
  1841. if(layerShadow>0)_jShadow.css({'left':x+layerShadow,'top':y+layerShadow,'width':_jPanel.outerWidth(),'height':_jPanel.outerHeight()}).show();
  1842. var basezIndex=$('#'+idContainer).offsetParent().css('zIndex');
  1843. if(basezIndex&&!isNaN(basezIndex)){
  1844. _jShadow.css('zIndex',parseInt(basezIndex,10)+1);
  1845. _jPanel.css('zIndex',parseInt(basezIndex,10)+2);
  1846. _jCntLine.css('zIndex',parseInt(basezIndex,10)+3);
  1847. }
  1848. _jPanel.css({'left':x,'top':y}).show();
  1849. if(!bNoFocus)setTimeout(function(){_jPanel.find('a,input[type=text],textarea').filter(':visible').filter(function(){return $(this).css('visibility')!=='hidden';}).eq(0).focus();},10);//定位首个可见输入表单项,延迟解决opera无法设置焦点
  1850. bQuickHoverExec=bShowPanel=true;
  1851. }
  1852. this.hidePanel=function(){
  1853. if(bShowPanel){
  1854. _jPanelButton.removeClass('xheActive');
  1855. _jShadow.hide();
  1856. _jCntLine.hide();
  1857. _jPanel.hide();
  1858. bShowPanel=false;
  1859. if(!bClickCancel){
  1860. $('.xheFixCancel').remove();
  1861. bClickCancel=true;
  1862. };
  1863. bQuickHoverExec=bDisableHoverExec=false;
  1864. lastAngle=null;
  1865. _this.focus();
  1866. _this.loadBookmark();
  1867. }
  1868. }
  1869. this.exec=function(cmd)
  1870. {
  1871. _this.hidePanel();
  1872. var tool=arrTools[cmd];
  1873. if(!tool)return false;//无效命令
  1874. if(ev===null)//非鼠标点击
  1875. {
  1876. ev={};
  1877. var btn=_jTools.find('.xheButton[cmd='+cmd+']');
  1878. if(btn.length===1)ev.target=btn;//设置当前事件焦点
  1879. }
  1880. if(tool.e)tool.e.call(_this)//插件事件
  1881. else//内置工具
  1882. {
  1883. cmd=cmd.toLowerCase();
  1884. switch(cmd)
  1885. {
  1886. case 'cut':
  1887. try{_doc.execCommand(cmd);if(!_doc.queryCommandSupported(cmd))throw 'Error';}
  1888. catch(ex){alert('您的浏览器安全设置不允许使用剪切操作,请使用键盘快捷键(Ctrl + X)来完成');};
  1889. break;
  1890. case 'copy':
  1891. try{_doc.execCommand(cmd);if(!_doc.queryCommandSupported(cmd))throw 'Error';}
  1892. catch(ex){alert('您的浏览器安全设置不允许使用复制操作,请使用键盘快捷键(Ctrl + C)来完成');}
  1893. break;
  1894. case 'paste':
  1895. try{_doc.execCommand(cmd);if(!_doc.queryCommandSupported(cmd))throw 'Error';}
  1896. catch(ex){alert('您的浏览器安全设置不允许使用粘贴操作,请使用键盘快捷键(Ctrl + V)来完成');}
  1897. break;
  1898. case 'pastetext':
  1899. if(window.clipboardData)_this.pasteText(window.clipboardData.getData('Text', true));
  1900. else _this.showPastetext();
  1901. break;
  1902. case 'blocktag':
  1903. var menuBlocktag=[];
  1904. $.each(arrBlocktag,function(n,v){menuBlocktag.push({s:'<'+v.n+'>'+v.t+'</'+v.n+'>',v:'<'+v.n+'>',t:v.t});});
  1905. _this.showMenu(menuBlocktag,function(v){_this._exec('formatblock',v);});
  1906. break;
  1907. case 'fontface':
  1908. var menuFontname=[];
  1909. $.each(arrFontname,function(n,v){v.c=v.c?v.c:v.n;menuFontname.push({s:'<span style="font-family:'+v.c+'">'+v.n+'</span>',v:v.c,t:v.n});});
  1910. _this.showMenu(menuFontname,function(v){_this._exec('fontname',v);});
  1911. break;
  1912. case 'fontsize':
  1913. var menuFontsize=[];
  1914. $.each(arrFontsize,function(n,v){menuFontsize.push({s:'<span style="font-size:'+v.s+';">'+v.t+'('+v.s+')</span>',v:n+1,t:v.t});});
  1915. _this.showMenu(menuFontsize,function(v){_this._exec('fontsize',v);});
  1916. break;
  1917. case 'fontcolor':
  1918. _this.showColor(function(v){_this._exec('forecolor',v);});
  1919. break;
  1920. case 'backcolor':
  1921. _this.showColor(function(v){if(isIE)_this._exec('backcolor',v);else{setCSS(true);_this._exec('hilitecolor',v);setCSS(false);}});
  1922. break;
  1923. case 'align':
  1924. _this.showMenu(menuAlign,function(v){_this._exec(v);});
  1925. break;
  1926. case 'list':
  1927. _this.showMenu(menuList,function(v){_this._exec(v);});
  1928. break;
  1929. case 'link':
  1930. _this.showLink();
  1931. break;
  1932. case 'anchor':
  1933. _this.showAnchor();
  1934. break;
  1935. case 'img':
  1936. _this.showImg();
  1937. break;
  1938. case 'flash':
  1939. _this.showEmbed('Flash',htmlFlash,'application/x-shockwave-flash','clsid:d27cdb6e-ae6d-11cf-96b8-4445535400000',' wmode="opaque" quality="high" menu="false" play="true" loop="true" allowfullscreen="true"',settings.upFlashUrl,settings.upFlashExt);
  1940. break;
  1941. case 'media':
  1942. _this.showEmbed('Media',htmlMedia,'application/x-mplayer2','clsid:6bf52a52-394a-11d3-b153-00c04f79faa6',' enablecontextmenu="false" autostart="false"',settings.upMediaUrl,settings.upMediaExt);
  1943. break;
  1944. case 'hr':
  1945. _this.pasteHTML('<hr />');
  1946. break;
  1947. case 'emot':
  1948. _this.showEmot();
  1949. break;
  1950. case 'table':
  1951. _this.showTable();
  1952. break;
  1953. case 'source':
  1954. _this.toggleSource();
  1955. break;
  1956. case 'preview':
  1957. _this.showPreview();
  1958. break;
  1959. case 'print':
  1960. _win.print();
  1961. break;
  1962. case 'fullscreen':
  1963. _this.toggleFullscreen();
  1964. break;
  1965. case 'about':
  1966. _this.showAbout();
  1967. break;
  1968. default:
  1969. _this._exec(cmd);
  1970. break;
  1971. }
  1972. }
  1973. ev=null;
  1974. }
  1975. this._exec=function(cmd,param,noFocus)
  1976. {
  1977. if(!noFocus)_this.focus();
  1978. var state;
  1979. if(param!==undefined)state=_doc.execCommand(cmd,false,param);
  1980. else state=_doc.execCommand(cmd,false,null);
  1981. return state;
  1982. }
  1983. function checkDblClick(ev)
  1984. {
  1985. var target=ev.target,tool=arrDbClick[target.tagName.toLowerCase()];
  1986. if(tool)
  1987. {
  1988. if(tool==='Embed')//自动识别Flash和多媒体
  1989. {
  1990. var arrEmbed={'application/x-shockwave-flash':'Flash','application/x-mplayer2':'Media'};
  1991. tool=arrEmbed[target.type.toLowerCase()];
  1992. }
  1993. _this.exec(tool);
  1994. }
  1995. }
  1996. function checkEsc(ev)
  1997. {
  1998. if(ev.which===27)
  1999. {
  2000. if(bShowModal)_this.removeModal();
  2001. else if(bShowPanel)_this.hidePanel();
  2002. return false;
  2003. }
  2004. }
  2005. function loadReset(){setTimeout(_this.setSource,10);}
  2006. function saveResult(){_this.getSource();};
  2007. function cleanPaste(ev){
  2008. var clipboardData,items,item;//for chrome
  2009. if(ev&&(clipboardData=ev.originalEvent.clipboardData)&&(items=clipboardData.items)&&(item=items[0])&&item.kind=='file'&&item.type.match(/^image\//i)){
  2010. var blob = item.getAsFile(),reader = new FileReader();
  2011. reader.onload=function(){
  2012. var sHtml='<img src="'+event.target.result+'">';
  2013. sHtml=replaceRemoteImg(sHtml);
  2014. _this.pasteHTML(sHtml);
  2015. }
  2016. reader.readAsDataURL(blob);
  2017. return false;
  2018. }
  2019. var cleanPaste=settings.cleanPaste;
  2020. if(cleanPaste===0||bSource||bCleanPaste)return true;
  2021. bCleanPaste=true;//解决IE右键粘贴重复产生paste的问题
  2022. _this.saveBookmark();
  2023. var tag=isIE?'pre':'div',jDiv=$('<'+tag+' class="xhe-paste">\uFEFF\uFEFF</'+tag+'>',_doc).appendTo(_doc.body),div=jDiv[0],sel=_this.getSel(),rng=_this.getRng(true);
  2024. jDiv.css('top',_jWin.scrollTop());
  2025. if(isIE){
  2026. rng.moveToElementText(div);
  2027. rng.select();
  2028. //注:调用execommand:paste,会导致IE8,IE9目标路径无法转为绝对路径
  2029. }
  2030. else{
  2031. rng.selectNodeContents(div);
  2032. sel.removeAllRanges();
  2033. sel.addRange(rng);
  2034. }
  2035. setTimeout(function(){
  2036. var bText=(cleanPaste===3),sPaste;
  2037. if(bText)sPaste=jDiv.text();
  2038. else{
  2039. var jTDiv=$('.xhe-paste',_doc.body),arrHtml=[];
  2040. jTDiv.each(function(i,n){if($(n).find('.xhe-paste').length==0)arrHtml.push(n.innerHTML);});
  2041. sPaste=arrHtml.join('<br />');
  2042. }
  2043. jDiv.remove();
  2044. _this.loadBookmark();
  2045. sPaste=sPaste.replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g,'');
  2046. if(sPaste){
  2047. if(bText)_this.pasteText(sPaste);
  2048. else{
  2049. sPaste=_this.cleanHTML(sPaste);
  2050. sPaste=_this.cleanWord(sPaste);
  2051. sPaste=_this.formatXHTML(sPaste);
  2052. if(!settings.onPaste||settings.onPaste&&(sPaste=settings.onPaste(sPaste))!==false){
  2053. sPaste=replaceRemoteImg(sPaste);
  2054. _this.pasteHTML(sPaste);
  2055. }
  2056. }
  2057. }
  2058. bCleanPaste=false;
  2059. },0);
  2060. }
  2061. //远程图片转本地
  2062. function replaceRemoteImg(sHtml){
  2063. var localUrlTest=settings.localUrlTest,remoteImgSaveUrl=settings.remoteImgSaveUrl;
  2064. if(localUrlTest&&remoteImgSaveUrl){
  2065. var arrRemoteImgs=[],count=0;
  2066. sHtml=sHtml.replace(/(<img)((?:\s+[^>]*?)?(?:\s+src="\s*([^"]+)\s*")(?: [^>]*)?)(\/?>)/ig,function(all,left,attr,url,right){
  2067. if(/^(https?|data:image)/i.test(url) && !/_xhe_temp/.test(attr) && !localUrlTest.test(url)){
  2068. arrRemoteImgs[count]=url;
  2069. attr=attr.replace(/\s+(width|height)="[^"]*"/ig,'').replace(/\s+src="[^"]*"/ig,' src="'+skinPath+'img/waiting.gif" remoteimg="'+(count++)+'"');
  2070. }
  2071. return left+attr+right;
  2072. });
  2073. if(arrRemoteImgs.length>0){
  2074. $.post(remoteImgSaveUrl,{urls:arrRemoteImgs.join('|')},function(data){
  2075. data=data.split('|');
  2076. $('img[remoteimg]',_this.doc).each(function(){
  2077. var $this=$(this);
  2078. xheAttr($this,'src',data[$this.attr('remoteimg')]);
  2079. $this.removeAttr('remoteimg');
  2080. });
  2081. });
  2082. }
  2083. }
  2084. return sHtml;
  2085. }
  2086. function setCSS(css)
  2087. {
  2088. try{_this._exec('styleWithCSS',css,true);}
  2089. catch(e)
  2090. {try{_this._exec('useCSS',!css,true);}catch(e){}}
  2091. }
  2092. function setOpts()
  2093. {
  2094. if(bInit&&!bSource)
  2095. {
  2096. setCSS(false);
  2097. try{_this._exec('enableObjectResizing',true,true);}catch(e){}
  2098. //try{_this._exec('enableInlineTableEditing',false,true);}catch(e){}
  2099. if(isIE)try{_this._exec('BackgroundImageCache',true,true);}catch(e){}
  2100. }
  2101. }
  2102. function forcePtag(ev)
  2103. {
  2104. if(bSource||ev.which!==13||ev.shiftKey||ev.ctrlKey||ev.altKey)return true;
  2105. var pNode=_this.getParent('p,h1,h2,h3,h4,h5,h6,pre,address,div,li');
  2106. if(pNode.is('li'))return true;
  2107. if(settings.forcePtag){if(pNode.length===0)_this._exec('formatblock','<p>');}
  2108. else
  2109. {
  2110. _this.pasteHTML('<br />');
  2111. if(isIE&&pNode.length>0&&_this.getRng().parentElement().childNodes.length===2)_this.pasteHTML('<br />');
  2112. return false;
  2113. }
  2114. }
  2115. function fixFullHeight()
  2116. {
  2117. if(!isMozilla&&!isSafari)
  2118. {
  2119. if(bFullscreen)_jArea.height('100%').css('height',_jArea.outerHeight()-_jTools.outerHeight());
  2120. if(isIE)_jTools.hide().show();
  2121. }
  2122. }
  2123. function fixAppleSel(e)
  2124. {
  2125. e=e.target;
  2126. if(e.tagName.match(/(img|embed)/i))
  2127. {
  2128. var sel=_this.getSel(),rng=_this.getRng(true);
  2129. rng.selectNode(e);
  2130. sel.removeAllRanges();
  2131. sel.addRange(rng);
  2132. }
  2133. }
  2134. function xheAttr(jObj,n,v)
  2135. {
  2136. if(!n)return false;
  2137. var kn='_xhe_'+n;
  2138. if(v)//设置属性
  2139. {
  2140. if(urlType)v=getLocalUrl(v,urlType,urlBase);
  2141. jObj.attr(n,urlBase?getLocalUrl(v,'abs',urlBase):v).removeAttr(kn).attr(kn,v);
  2142. }
  2143. return jObj.attr(kn)||jObj.attr(n);
  2144. }
  2145. function clickCancelPanel(){if(bClickCancel)_this.hidePanel();}
  2146. function checkShortcuts(event)
  2147. {
  2148. if(bSource)return true;
  2149. var code=event.which,special=specialKeys[code],sChar=special?special:String.fromCharCode(code).toLowerCase();
  2150. sKey='';
  2151. sKey+=event.ctrlKey?'ctrl+':'';sKey+=event.altKey?'alt+':'';sKey+=event.shiftKey?'shift+':'';sKey+=sChar;
  2152. var cmd=arrShortCuts[sKey],c;
  2153. for(c in cmd)
  2154. {
  2155. c=cmd[c];
  2156. if($.isFunction(c)){if(c.call(_this)===false)return false;}
  2157. else{_this.exec(c);return false;}//按钮独占快捷键
  2158. }
  2159. }
  2160. function is(o,t)
  2161. {
  2162. var n = typeof(o);
  2163. if (!t)return n != 'undefined';
  2164. if (t === 'array' && (o.hasOwnProperty && o instanceof Array))return true;
  2165. return n === t;
  2166. }
  2167. function getLocalUrl(url,urlType,urlBase)//绝对地址:abs,根地址:root,相对地址:rel
  2168. {
  2169. if( (url.match(/^(\w+):\/\//i) && !url.match(/^https?:/i)) || /^#/i.test(url) || /^data:/i.test(url) )return url;//非http和https协议,或者页面锚点不转换,或者base64编码的图片等
  2170. var baseUrl=urlBase?$('<a href="'+urlBase+'" />')[0]:location,protocol=baseUrl.protocol,host=baseUrl.host,hostname=baseUrl.hostname,port=baseUrl.port,path=baseUrl.pathname.replace(/\\/g,'/').replace(/[^\/]+$/i,'');
  2171. if(port==='')port='80';
  2172. if(path==='')path='/';
  2173. else if(path.charAt(0)!=='/')path='/'+path;//修正IE path
  2174. url=$.trim(url);
  2175. //删除域路径
  2176. if(urlType!=='abs')url=url.replace(new RegExp(protocol+'\\/\\/'+hostname.replace(/\./g,'\\.')+'(?::'+port+')'+(port==='80'?'?':'')+'(\/|$)','i'),'/');
  2177. //删除根路径
  2178. if(urlType==='rel')url=url.replace(new RegExp('^'+path.replace(/([\/\.\+\[\]\(\)])/g,'\\$1'),'i'),'');
  2179. //加上根路径
  2180. if(urlType!=='rel')
  2181. {
  2182. if(!url.match(/^(https?:\/\/|\/)/i))url=path+url;
  2183. if(url.charAt(0)==='/')//处理根路径中的..
  2184. {
  2185. var arrPath=[],arrFolder = url.split('/'),folder,i,l=arrFolder.length;
  2186. for(i=0;i<l;i++)
  2187. {
  2188. folder=arrFolder[i];
  2189. if(folder==='..')arrPath.pop();
  2190. else if(folder!==''&&folder!=='.')arrPath.push(folder);
  2191. }
  2192. if(arrFolder[l-1]==='')arrPath.push('');
  2193. url='/'+arrPath.join('/');
  2194. }
  2195. }
  2196. //加上域路径
  2197. if(urlType==='abs'&&!url.match(/^https?:\/\//i))url=protocol+'//'+host+url;
  2198. url=url.replace(/(https?:\/\/[^:\/?#]+):80(\/|$)/i,'$1$2');//省略80端口
  2199. return url;
  2200. }
  2201. function checkFileExt(filename,limitExt)
  2202. {
  2203. if(limitExt==='*'||filename.match(new RegExp('\.('+limitExt.replace(/,/g,'|')+')$','i')))return true;
  2204. else
  2205. {
  2206. alert('上传文件扩展名必需为: '+limitExt);
  2207. return false;
  2208. }
  2209. }
  2210. function formatBytes(bytes)
  2211. {
  2212. var s = ['Byte', 'KB', 'MB', 'GB', 'TB', 'PB'];
  2213. var e = Math.floor(Math.log(bytes)/Math.log(1024));
  2214. return (bytes/Math.pow(1024, Math.floor(e))).toFixed(2)+s[e];
  2215. }
  2216. function returnFalse(){return false;}
  2217. }
  2218. xheditor.settings={skin:'default',tools:'full',clickCancelDialog:true,linkTag:false,internalScript:false,inlineScript:false,internalStyle:true,inlineStyle:true,showBlocktag:false,forcePtag:true,upLinkExt:"zip,rar,txt",upImgExt:"jpg,jpeg,gif,png",upFlashExt:"swf",upMediaExt:"wmv,avi,wma,mp3,mid",modalWidth:350,modalHeight:220,modalTitle:true,defLinkText:'点击打开链接',layerShadow:3,emotMark:false,upBtnText:'上传',cleanPaste:1,hoverExecDelay:100,html5Upload:true,upMultiple:99};
  2219. window.xheditor=xheditor;
  2220. $(function(){
  2221. $.fn.oldVal=$.fn.val;
  2222. $.fn.val=function(value)
  2223. {
  2224. var _this=this,editor;
  2225. if(value===undefined)if(_this[0]&&(editor=_this[0].xheditor))return editor.getSource();else return _this.oldVal();//读
  2226. return _this.each(function(){if(editor=this.xheditor)editor.setSource(value);else _this.oldVal(value);});//写
  2227. }
  2228. $('textarea').each(function(){
  2229. var $this=$(this),xhClass=$this.attr('class');
  2230. if(xhClass&&(xhClass=xhClass.match(/(?:^|\s)xheditor(?:\-(m?full|simple|mini))?(?:\s|$)/i)))$this.xheditor(xhClass[1]?{tools:xhClass[1]}:null);
  2231. });
  2232. });
  2233. })(jQuery);