截流自动化的商城平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 161KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290
  1. /**
  2. @Name:Kz.layedit 富文本编辑器
  3. @Author:贤心
  4. @Modifier:KnifeZ
  5. @License:MIT
  6. @Version: V21.04.11
  7. */
  8. layui.define(['layer', 'form', 'code'], function (exports) {
  9. 'use strict'
  10. /**
  11. * 移动端使用。获取触摸位置的元素。没有则返回null
  12. * @param touchEvent 触摸事件
  13. * @returns {Element} 触摸点的DOM对象
  14. */
  15. var getTouchElement = function (touchEvent) {
  16. var myLocation = touchEvent.originalEvent.changedTouches[0]
  17. return document.elementFromPoint(myLocation.clientX, myLocation.clientY)
  18. }
  19. var $ = layui.$,
  20. layer = layui.layer,
  21. form = layui.form,
  22. hint = layui.hint(),
  23. device = layui.device(),
  24. MOD_NAME = 'layEditor',
  25. THIS = 'layui-this',
  26. SHOW = 'layui-show',
  27. ABLED = 'layui-disabled',
  28. Edit = function () {
  29. var that = this
  30. that.index = 0
  31. //全局配置
  32. that.config = {
  33. //默认工具bar
  34. tool: ["html","|","strong","italic","underline","del","addhr","|","removeformat","fontfamily","fontSize","lineHeight","colorpicker","left","center","right","|","face","link","unlink","image","preview"],
  35. uploadImage: {
  36. url: '',
  37. done: function (data) {},
  38. },
  39. uploadVideo: {
  40. url: '',
  41. done: function (data) {},
  42. },
  43. uploadFiles: {
  44. url: '',
  45. done: function (data) {
  46. //文件上传接口返回code为0时的回调
  47. },
  48. },
  49. calldel: {
  50. url: '',
  51. done: function (data) {},
  52. },
  53. quote: {
  54. style: [],
  55. js: [],
  56. },
  57. customTheme: {
  58. video: {
  59. title: [],
  60. content: [],
  61. preview: [],
  62. },
  63. },
  64. customlink: {
  65. title: '自定义链接',
  66. href: '',
  67. onmouseup: '',
  68. },
  69. facePath: layui.cache.dir,
  70. devmode: false,
  71. autoSync: true,
  72. onchange: function (content) {},
  73. hideTool: [],
  74. height: 500, //默认高
  75. }
  76. }
  77. //全局设置
  78. Edit.prototype.set = function (options) {
  79. var that = this
  80. $.extend(true, that.config, options)
  81. return that
  82. }
  83. //事件监听
  84. Edit.prototype.on = function (events, callback) {
  85. return layui.onevent(MOD_NAME, events, callback)
  86. }
  87. //建立编辑器
  88. Edit.prototype.build = function (id, settings) {
  89. settings = settings || {}
  90. var that = this,
  91. config = that.config,
  92. ELEM = 'layui-layedit',
  93. textArea = $(typeof id == 'string' ? '#' + id : id),
  94. name = 'LAY_layedit_' + ++that.index,
  95. haveBuild = textArea.next('.' + ELEM),
  96. set = $.extend({}, config, settings),
  97. tool = (function () {
  98. var node = [],
  99. hideTools = {}
  100. set._elem = textArea
  101. layui.each(set.hideTool, function (_, item) {
  102. hideTools[item] = true
  103. })
  104. layui.each(set.tool, function (_, item) {
  105. if (tools[item] && !hideTools[item]) {
  106. node.push(tools[item])
  107. }
  108. })
  109. return node.join('')
  110. })(),
  111. editor = $(
  112. [
  113. '<div class="' + ELEM + '">',
  114. '<div class="layui-unselect layui-layedit-tool">' +
  115. tool.replace('layBkColor_Index', 'layBkColor_' + that.index).replace('layFontColor_Index', 'layFontColor_' + that.index) +
  116. '</div>',
  117. '<div class="layui-layedit-iframe">',
  118. '<iframe src="" id="' + name + '" name="' + name + '" textarea="' + id + '" frameborder="0"></iframe>',
  119. '</div>',
  120. '</div>',
  121. ].join('')
  122. )
  123. //编辑器不兼容ie8以下
  124. if (device.ie && device.ie < 8) {
  125. return textArea.removeClass('layui-hide').addClass(SHOW)
  126. }
  127. haveBuild[0] && haveBuild.remove()
  128. setIframe.call(that, editor, textArea[0], set)
  129. textArea.addClass('layui-hide').after(editor)
  130. //tool bind
  131. layui.use(['colorpicker', 'jquery'], function () {
  132. var colorpicker = layui.colorpicker,
  133. $ = layui.jquery
  134. for (var i = 0; i <= that.index; i++) {
  135. colorpicker.render({
  136. elem: '#layBkColor_' + i, //绑定元素
  137. predefine: true,
  138. colors: ['#800000', '#cc0000', '#999999', '#ff8c00', '#ffb800', '#ff7800', '#1e90ff', '#009688', '#5fb878', '#ffffff', '#000000'],
  139. size: 'xs',
  140. done: function (color) {
  141. var iframeWin = getWin(this.elem.split('_')[1])
  142. if (device.ie) iframeWin[0].document.execCommand('backColor', false, color)
  143. else iframeWin[0].document.execCommand('hiliteColor', false, color)
  144. setTimeout(function () {
  145. iframeWin[0].document.body.focus()
  146. }, 10)
  147. },
  148. })
  149. colorpicker.render({
  150. elem: '#layFontColor_' + i, //绑定元素
  151. predefine: true,
  152. colors: ['#800000', '#cc0000', '#999999', '#ff8c00', '#ffb800', '#ff7800', '#1e90ff', '#009688', '#5fb878', '#ffffff', '#000000'],
  153. size: 'xs',
  154. color: '#000',
  155. done: function (color) {
  156. var iframeWin = getWin(this.elem.split('_')[1])
  157. iframeWin[0].document.execCommand('forecolor', false, color)
  158. setTimeout(function () {
  159. iframeWin[0].document.body.focus()
  160. }, 10)
  161. },
  162. })
  163. }
  164. })
  165. //end
  166. return that.index
  167. }
  168. //获得编辑器中内容
  169. Edit.prototype.getContent = function (index) {
  170. var iframeWin = getWin(index)
  171. if (!iframeWin[0]) return
  172. return toLower(iframeWin[0].document.body.innerHTML)
  173. }
  174. //获得编辑器中纯文本内容
  175. Edit.prototype.getText = function (index) {
  176. var iframeWin = getWin(index)
  177. if (!iframeWin[0]) return
  178. return $(iframeWin[0].document.body).text()
  179. }
  180. /**
  181. * 设置编辑器内容
  182. * @param {[type]} index 编辑器索引
  183. * @param {[type]} content 要设置的内容
  184. * @param {[type]} flag 是否追加模式
  185. */
  186. Edit.prototype.setContent = function (index, content, flag) {
  187. var iframeWin = getWin(index)
  188. if (!iframeWin[0]) return
  189. if (flag) {
  190. $(iframeWin[0].document.body).append(content)
  191. } else {
  192. $(iframeWin[0].document.body).html(content)
  193. }
  194. this.sync(index)
  195. }
  196. //将编辑器内容同步到textarea(一般用于异步提交时)
  197. Edit.prototype.sync = function (index) {
  198. var iframeWin = getWin(index)
  199. if (!iframeWin[0]) return
  200. var textarea = $('#' + iframeWin[1].attr('textarea'))
  201. textarea.val(toLower(iframeWin[0].document.body.innerHTML))
  202. }
  203. //获取编辑器选中内容
  204. Edit.prototype.getSelection = function (index) {
  205. var iframeWin = getWin(index)
  206. if (!iframeWin[0]) return
  207. var range = Range(iframeWin[0].document)
  208. return document.selection ? range.text : range.toString()
  209. }
  210. //iframe初始化
  211. var setIframe = function (editor, textArea, set) {
  212. var that = this,
  213. iframe = editor.find('iframe')
  214. iframe
  215. .css({
  216. height: set.height,
  217. })
  218. .on('load', function () {
  219. var conts = iframe.contents(),
  220. iframeWin = iframe.prop('contentWindow'),
  221. head = conts.find('head'),
  222. style = $(
  223. [
  224. '<style>',
  225. '*{margin: 0; padding: 0;}',
  226. 'body{padding: 10px; line-height: 20px; overflow-x: hidden; word-wrap: break-word; font: 14px Helvetica Neue,Helvetica,PingFang SC,Microsoft YaHei,Tahoma,Arial,sans-serif; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;}',
  227. 'a{color:#01AAED; text-decoration:none;}a:hover{color:#c00}',
  228. 'p{margin-bottom: 10px;}',
  229. 'video{max-width:400px;}',
  230. 'td{border: 1px solid #DDD;width:80px}',
  231. 'table{border-collapse: collapse;}',
  232. 'a[name]:before{content:"§";color: #01aaed;font-weight: bold;}',
  233. 'img{display: inline-block; border: none; vertical-align: middle;}',
  234. 'pre{margin: 10px 0; padding: 10px; line-height: 20px; border: 1px solid #ddd; border-left-width: 6px; background-color: #F2F2F2; color: #333; font-family: Courier New; font-size: 12px;}',
  235. '</style>',
  236. ].join('')
  237. ),
  238. body = conts.find('body')
  239. var quoteStyle = (function () {
  240. var content = []
  241. layui.each(set.quote.style, function (index, item) {
  242. content.push('<link href="' + item + '" rel="stylesheet"/>')
  243. })
  244. layui.each(set.quote.js, function (index, item) {
  245. content.push('<script src="' + item + '"></script>')
  246. })
  247. return content.join('')
  248. })()
  249. head.append(style)
  250. head.append(quoteStyle)
  251. body
  252. .attr('contenteditable', 'true')
  253. .css({
  254. 'min-height': set.height,
  255. })
  256. .html(textArea.value || '')
  257. hotkey.apply(that, [iframeWin, iframe, textArea, set]) //快捷键处理
  258. toolActive.call(that, iframeWin, editor, set) //触发工具
  259. })
  260. },
  261. //获得iframe窗口对象
  262. getWin = function (index) {
  263. var iframe = $('#LAY_layedit_' + index),
  264. iframeWin = iframe.prop('contentWindow')
  265. return [iframeWin, iframe]
  266. },
  267. //IE8下将标签处理成小写
  268. toLower = function (html) {
  269. if (device.ie == 8) {
  270. html = html.replace(/<.+>/g, function (str) {
  271. return str.toLowerCase()
  272. })
  273. }
  274. return html
  275. },
  276. //快捷键处理
  277. hotkey = function (iframeWin, iframe, textArea, set) {
  278. var iframeDOM = iframeWin.document,
  279. body = $(iframeDOM.body)
  280. body.on('keydown', function (e) {
  281. var keycode = e.keyCode
  282. //处理回车
  283. if (keycode === 13) {
  284. var range = Range(iframeDOM)
  285. var container = getContainer(range),
  286. parentNode = container.parentNode
  287. if (parentNode.tagName.toLowerCase() === 'pre') {
  288. if (e.shiftKey) return
  289. layer.msg('请暂时用shift+enter')
  290. return false
  291. }
  292. if (parentNode.tagName.toLowerCase() === 'body' || container.tagName === 'BODY') {
  293. iframeDOM.execCommand('formatBlock', false, '<p>')
  294. }
  295. }
  296. //back键
  297. if (keycode === 8) {
  298. var range = Range(iframeDOM)
  299. var container = getContainer(range)
  300. //删除第一条hr水平线
  301. if (container.innerHTML == '<hr>' && container.tagName == 'BODY') {
  302. range.selectNode(container.childNodes[0])
  303. range.deleteContents()
  304. }
  305. //触发图片删除回调函数 p标签内图片
  306. if (container.hasChildNodes() && container.childNodes[0].tagName == 'IMG') {
  307. var callDel = set.calldel
  308. if (callDel.url != '') {
  309. if (range.commonAncestorContainer.childNodes[range.startOffset - 1].tagName != 'IMG') {
  310. //alert("error-无法找到图片路径");
  311. } else {
  312. $.post(
  313. callDel.url,
  314. {
  315. imgpath: range.commonAncestorContainer.childNodes[range.startOffset - 1].src,
  316. },
  317. function (res) {
  318. callDel.done(res)
  319. }
  320. )
  321. }
  322. }
  323. }
  324. }
  325. //del
  326. if (keycode === 46) {
  327. var range = Range(iframeDOM)
  328. var container = getContainer(range)
  329. //触发图片删除回调函数 p标签内图片
  330. if (container.nextElementSibling == null) {
  331. return
  332. }
  333. if (container.nextElementSibling.tagName === 'IMG') {
  334. var callDel = set.calldel
  335. if (callDel.url != '') {
  336. $.post(callDel.url, { imgpath: container.nextElementSibling.src }, function (res) {
  337. callDel.done(res)
  338. })
  339. }
  340. }
  341. }
  342. setTimeout(function () {
  343. //ctrl+b 加粗
  344. if (e.ctrlKey && keycode == 66) {
  345. var elem = document.createElement('strong')
  346. body.find('b').each(function () {
  347. elem.innerText = this.innerText
  348. this.outerHTML = elem.outerHTML
  349. })
  350. }
  351. var html = body.html()
  352. //IE8下将标签处理成小写
  353. if (device.ie == 8) {
  354. html = html.replace(/<.+>/g, function (str) {
  355. return str.toLowerCase()
  356. })
  357. }
  358. if (set.autoSync) {
  359. textArea.value = html
  360. }
  361. set.onchange(html)
  362. }, 10)
  363. })
  364. //给textarea同步内容
  365. $(textArea)
  366. .parents('form')
  367. .on('submit', function () {
  368. var html = body.html()
  369. //IE8下将标签处理成小写
  370. if (device.ie == 8) {
  371. html = html.replace(/<.+>/g, function (str) {
  372. return str.toLowerCase()
  373. })
  374. }
  375. textArea.value = html
  376. })
  377. //处理粘贴
  378. body.on('paste', function (e) {
  379. var range = Range(iframeDOM)
  380. if (!(e.originalEvent.clipboardData && e.originalEvent.clipboardData.items)) {
  381. return
  382. }
  383. for (var i = 0, len = e.originalEvent.clipboardData.items.length; i < len; i++) {
  384. var item = e.originalEvent.clipboardData.items[i]
  385. if (item.kind === 'file') {
  386. var f = item.getAsFile()
  387. var formData = new FormData()
  388. formData.append('file', f)
  389. var url = set.uploadImage.url
  390. var src = ''
  391. $.ajax({
  392. type: 'POST',
  393. url: url,
  394. data: formData,
  395. async: false,
  396. contentType: false,
  397. processData: false,
  398. dataType: 'json',
  399. mimeType: 'multipart/form-data',
  400. success: function (data) {
  401. if (data.code == 0 || data.code == 2) {
  402. src = data.data.src
  403. set.uploadImage.done(data)
  404. }
  405. },
  406. error: function (d) {
  407. layer.msg('上传服务器出错')
  408. },
  409. })
  410. if (src != '') {
  411. var elem = document.createElement('img')
  412. elem.src = src
  413. if (device.ie) {
  414. layer.msg('暂不支持IE浏览器')
  415. } else {
  416. var container = getContainer(range)
  417. if (container.innerHTML == '<br>') {
  418. range.selectNode(container)
  419. range.deleteContents()
  420. }
  421. range.deleteContents()
  422. range.insertNode(elem)
  423. e.preventDefault() //插入后禁止默认事件
  424. }
  425. } else {
  426. layer.msg('图片上传失败!仅粘贴到内容')
  427. }
  428. }
  429. }
  430. setTimeout(function () {
  431. filter.call(iframeWin, body)
  432. textArea.value = body.html()
  433. }, 10)
  434. })
  435. },
  436. //标签过滤
  437. filter = function (body) {
  438. var iframeWin = this,
  439. iframeDOM = iframeWin.document
  440. //clean word start
  441. body.find('.MsoNormal,.MsoListParagraph').each(function () {
  442. this.removeAttribute('class')
  443. })
  444. body.html(body.html().replace(/<o:p> <\/o:p>/g, ''))
  445. body.html(body.html().replace(/o:/g, ''))
  446. body.html(body.html().replace(/<font>/gi, ''))
  447. body.html(body.html().replace(/<span>/gi, ''))
  448. body.html(body.html().replace(/<span [^>]+>/gi, ''))
  449. body.html(body.html().replace(/<\/span>/gi, ''))
  450. body.html(body.html().replace(/<P>/g, ''))
  451. body.html(body.html().replace(/<\/P>/g, ''))
  452. body.html(body.html().replace(/<p><\/p>/g, '')) //移除空p
  453. //clean word end
  454. //清除影响版面的css属性
  455. //body.find('*[style]').each(function () {
  456. // var textAlign = this.style.textAlign;
  457. // this.removeAttribute('style');
  458. // $(this).css({
  459. // 'text-align': textAlign || ''
  460. // })
  461. //});
  462. // 移除不安全的标签
  463. // body.find('script,link').remove();
  464. ////修饰表格
  465. //body.find('table').addClass('layui-table');
  466. },
  467. //Range对象兼容性处理
  468. Range = function (iframeDOM) {
  469. const selection = iframeDOM.getSelection()
  470. return iframeDOM.selection ? iframeDOM.selection.createRange() : selection.rangeCount && selection.getRangeAt(0)
  471. },
  472. //当前Range对象的endContainer兼容性处理
  473. getContainer = function (range) {
  474. if (!range) return
  475. return range.endContainer || range.parentElement().childNodes[0]
  476. },
  477. //在选区插入内联元素
  478. insertInline = function (tagName, attr, range) {
  479. var iframeDOM = this.document,
  480. elem = document.createElement(tagName)
  481. for (var key in attr) {
  482. elem.setAttribute(key, attr[key])
  483. }
  484. elem.removeAttribute('text')
  485. // be fix by knifeZ
  486. if (device.ie) {
  487. //IE
  488. var text = range.text || attr.text
  489. if (tagName === 'a' && !text) return
  490. if (text) {
  491. elem.innerHTML = text
  492. }
  493. layer.msg('暂不支持IE浏览器')
  494. range.selectNode(this.document.body.childNodes.item(0))
  495. range.insertNode(elem)
  496. } else {
  497. //非IE
  498. var text = range.toString() || attr.text
  499. if (tagName === 'a' && !text) return
  500. if (text) {
  501. elem.innerHTML = text
  502. }
  503. var container = getContainer(range),
  504. parentNode = container.parentNode
  505. //var elep = document.createElement('p');
  506. //if (tagName != "pre" && tagName != "span" && tagName != "p" && tagName != "a" && tagName != "hr" && tagName != "div" && parentNode.tagName != "P" && container.innerHTML != "<br>") {
  507. // elep.appendChild(elem);
  508. //} else {
  509. // elep = elem;
  510. //}
  511. //处理换行
  512. if (container.innerHTML == '<br>') {
  513. range.selectNode(container)
  514. range.deleteContents()
  515. }
  516. range.deleteContents()
  517. range.insertNode(elem)
  518. //图片默认居中
  519. // if (tagName == 'img' && container.innerHTML == '<br>') {
  520. // iframeDOM.execCommand('formatBlock', false, '<p>')
  521. // iframeDOM.execCommand('justifyCenter')
  522. // setTimeout(function () {
  523. // body.focus()
  524. // }, 10)
  525. // }
  526. }
  527. },
  528. // 批量在选区插入内联元素 - 此处服务于图片
  529. insertInlineAll = function (data, range) {
  530. var iframeDOM = this.document
  531. var elems = []
  532. for (var i = 0; i < data.length; i++) {
  533. elems[i] = document.createElement(data[i].tagName)
  534. for (var key in data[i].attr) {
  535. elems[i].setAttribute(key, data[i].attr[key])
  536. }
  537. elems[i].removeAttribute('text')
  538. }
  539. if (iframeDOM.selection) {
  540. //IE
  541. var text = range.text || attr.text
  542. if (tagName === 'a' && !text) return
  543. if (text) {
  544. elem.innerHTML = text
  545. }
  546. range.pasteHTML($(elems).prop('outerHTML'))
  547. range.select()
  548. } else {
  549. //非IE
  550. /*
  551. var text = range.toString() || attr.text;
  552. if (tagName === 'a' && !text) return;
  553. if (text) {
  554. elem.innerHTML = text;
  555. }
  556. */
  557. range.deleteContents()
  558. for (var j = 0; j < elems.length; j++) {
  559. var text = range.toString() || data[j].attr.text
  560. // if (data[j].tagName === 'a' && !text) return;
  561. if (text) {
  562. elem.innerHTML = text
  563. }
  564. range.insertNode(elems[j])
  565. }
  566. }
  567. },
  568. //工具选中
  569. toolCheck = function (tools, othis) {
  570. var iframeDOM = this.document,
  571. CHECK = 'layedit-tool-active',
  572. container = getContainer(Range(iframeDOM)),
  573. item = function (type) {
  574. return tools.find('.layedit-tool-' + type)
  575. }
  576. if (othis) {
  577. othis[othis.hasClass(CHECK) ? 'removeClass' : 'addClass'](CHECK)
  578. }
  579. tools.find('>i').removeClass(CHECK)
  580. item('unlink').addClass(ABLED)
  581. $(container)
  582. .parents()
  583. .each(function () {
  584. var tagName = this.tagName.toLowerCase(),
  585. textAlign = this.style.textAlign
  586. //be fix by kinfeZ
  587. //文字
  588. //if (tagName === 'b' || tagName === 'strong') {
  589. // item('b').addClass(CHECK)
  590. //}
  591. //if (tagName === 'i' || tagName === 'em') {
  592. // item('i').addClass(CHECK)
  593. //}
  594. //if (tagName === 'u') {
  595. // item('u').addClass(CHECK)
  596. //}
  597. //if (tagName === 'strike') {
  598. // item('d').addClass(CHECK)
  599. //}
  600. //对齐
  601. if (tagName === 'p') {
  602. if (textAlign === 'center') {
  603. item('center').addClass(CHECK)
  604. } else if (textAlign === 'right') {
  605. item('right').addClass(CHECK)
  606. } else {
  607. item('left').addClass(CHECK)
  608. }
  609. }
  610. //超链接
  611. if (tagName === 'a') {
  612. item('link').addClass(CHECK)
  613. item('unlink').removeClass(ABLED)
  614. }
  615. })
  616. },
  617. //触发工具
  618. toolActive = function (iframeWin, editor, set) {
  619. var iframeDOM = iframeWin.document,
  620. body = $(iframeDOM.body),
  621. toolEvent = {
  622. //超链接
  623. link: function (range) {
  624. var container = getContainer(range),
  625. parentNode = $(container).parent()
  626. link.call(
  627. body,
  628. {
  629. href: parentNode.attr('href'),
  630. target: parentNode.attr('target'),
  631. rel: parentNode.attr('rel'),
  632. text: parentNode.attr('text') || range.toString(),
  633. dmode: set.devmode,
  634. },
  635. function (field) {
  636. var parent = parentNode[0]
  637. if (parent.tagName === 'A') {
  638. parent.href = field.url
  639. parent.rel = field.rel
  640. if (field.rel == '') {
  641. parent.removeAttr('rel')
  642. }
  643. parent.target = field.target
  644. if (field.target == '_self' || field.target == undefined) {
  645. parent.removeAttr('target')
  646. }
  647. if (field.text != '') {
  648. parent.text = field.text
  649. }
  650. } else {
  651. var data = {
  652. target: field.target,
  653. href: field.url,
  654. rel: field.rel,
  655. text: field.text,
  656. }
  657. if (field.rel == '' || field.rel == undefined) {
  658. delete data['rel']
  659. }
  660. if (field.target == '_self' || field.target == undefined) {
  661. delete data['target']
  662. }
  663. if (field.text == '') {
  664. data['text'] = data['href']
  665. }
  666. insertInline.call(iframeWin, 'a', data, range)
  667. }
  668. }
  669. )
  670. },
  671. //清除超链接
  672. unlink: function (range) {
  673. iframeDOM.execCommand('unlink')
  674. },
  675. //表情
  676. face: function (range) {
  677. face.call(this, { facePath: set.facePath }, function (img) {
  678. insertInline.call(
  679. iframeWin,
  680. 'img',
  681. {
  682. src: img.src,
  683. alt: img.alt,
  684. },
  685. range
  686. )
  687. setTimeout(function () {
  688. body.focus()
  689. }, 10)
  690. })
  691. },
  692. //图片
  693. // image: function (range) {
  694. // var that = this
  695. // layui.use('upload', function (upload) {
  696. // var uploadImage = set.uploadImage || {}
  697. // if (uploadImage.url == '') {
  698. // layer.msg('上传接口配置错误!')
  699. // }
  700. // upload.render({
  701. // url: uploadImage.url,
  702. // method: uploadImage.method,
  703. // field: uploadImage.field,
  704. // data: uploadImage.data,
  705. // headers: uploadImage.headers,
  706. // accept: uploadImage.accept || 'image',
  707. // acceptMime: uploadImage.acceptMime || 'image/*',
  708. // exts: uploadImage.exts || 'jpg|png|gif|bmp|jpeg',
  709. // size: uploadImage.size || 1024 * 10,
  710. // elem: $(that).find('input')[0],
  711. // done: function (res) {
  712. // if (res.code == 0) {
  713. // res.data = res.data || {}
  714. // insertInline.call(
  715. // iframeWin,
  716. // 'img',
  717. // {
  718. // src: res.data.src,
  719. // alt: res.data.title,
  720. // },
  721. // range
  722. // )
  723. // uploadImage.done(res)
  724. // setTimeout(function () {
  725. // body.focus()
  726. // }, 10)
  727. // } else {
  728. // layer.msg(res.msg || '上传失败')
  729. // }
  730. // },
  731. // })
  732. // })
  733. // },
  734. image: function (range) {
  735. var uploadImage = set.uploadImage || {}
  736. var windows = layer.open({type: 2, title: "上传图片", content: uploadImage.url, area: ["90%", "90%"]});
  737. window.callback = function (uri) {
  738. var uriArr = []
  739. uri.forEach(function (item) {
  740. uriArr.push({
  741. tagName: 'img',
  742. attr: {
  743. src: item,
  744. },
  745. })
  746. // insertInline.call(iframeWin, "img", {src: item}, range)
  747. });
  748. insertInlineAll.call(iframeWin, uriArr, range)
  749. };
  750. // window.callbackSetUri = function (uri) {
  751. // console.log(uri)
  752. // insertInline.call(iframeWin, "img", {src: "/" + uri}, range);
  753. // layer.close(windows)
  754. // }
  755. },
  756. //插入代码
  757. code: function (range) {
  758. var codeConfig = set.codeConfig || { hide: false, encode: true, class: 'layui-code' }
  759. code.call(body, { hide: codeConfig.hide, default: codeConfig.default }, function (pre) {
  760. if (codeConfig.encode || true) {
  761. pre.code = pre.code
  762. .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
  763. .replace(/</g, '&lt;')
  764. .replace(/>/g, '&gt;')
  765. .replace(/'/g, '&#39;')
  766. .replace(/"/g, '&quot;')
  767. }
  768. insertInline.call(
  769. iframeWin,
  770. 'pre',
  771. {
  772. text: pre.code,
  773. 'lay-lang': pre.lang,
  774. 'lay-encode': codeConfig.encode,
  775. class: codeConfig.class || 'layui-code',
  776. },
  777. range
  778. )
  779. setTimeout(function () {
  780. layui.code()
  781. body.focus()
  782. }, 10)
  783. })
  784. },
  785. /*#Extens#*/
  786. //多图上传
  787. images: function (range) {
  788. var that = this
  789. layer.open({
  790. type: 1,
  791. id: 'fly-jie-image-upload',
  792. title: '图片管理',
  793. shade: 0.05,
  794. shadeClose: true,
  795. area: (function () {
  796. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 485) {
  797. return ['90%']
  798. } else {
  799. return ['485px']
  800. }
  801. })(),
  802. offset: (function () {
  803. if (/mobile/i.test(navigator.userAgent)) {
  804. return 'auto'
  805. } else {
  806. return '100px'
  807. }
  808. })(),
  809. skin: 'layui-layer-border',
  810. content: [
  811. '<ul class="layui-form layui-form-pane" style="margin: 20px 20px 0 20px;">',
  812. '<li class="layui-form-item">',
  813. '<div class="layui-upload">',
  814. '<button type="button" class="layui-btn" id="LayEdit_InsertImages"><i class="layui-icon"></i>多图上传</button> ',
  815. '<blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;min-height: 116px">',
  816. ' 预览图(点击图片可删除):<div class="layui-upload-list" id="imgsPrev"></div>',
  817. '</blockquote>',
  818. '</div>',
  819. '</li>',
  820. '<li class="layui-form-item" style="position: relative;width: 48%;display: inline-block;">',
  821. '<label class="layui-form-label" style="position: relative;z-index: 10;width: 60px;">宽度</label>',
  822. '<input type="text" required name="imgWidth" placeholder="px" style="position: absolute;width: 100%;padding-left: 70px;left: 0;top:0" value="" class="layui-input">',
  823. '</li>',
  824. '<li class="layui-form-item" style="position: relative;width: 48%;display: inline-block;margin-left: 4%;">',
  825. '<label class="layui-form-label" style="width: 60px;position: relative;z-index: 10;">高度</label>',
  826. '<input type="text" required name="imgHeight" placeholder="px" style="position: absolute;width: 100%;padding-left: 70px;left: 0;top:0" value="" class="layui-input">',
  827. '</li>',
  828. '</ul>',
  829. ].join(''),
  830. btn: ['确定', '取消'],
  831. btnAlign: 'c',
  832. yes: function (index, layero) {
  833. var styleStr = ''
  834. if (layero.find('input[name="imgWidth"]').val() != '') {
  835. var w = layero.find('input[name="imgWidth"]').val()
  836. styleStr += w.indexOf('%') > 0 ? 'width:' + w + ';' : 'width:' + w + 'px;'
  837. }
  838. if (layero.find('input[name="imgHeight"]').val() != '') {
  839. var h = layero.find('input[name="imgHeight"]').val()
  840. styleStr += h.indexOf('%') > 0 ? 'height:' + h + ';' : 'height:' + h + 'px;'
  841. }
  842. if (layero.find('#imgsPrev').find('img').length === 0) {
  843. layer.msg('请选择要插入的图片')
  844. } else {
  845. /*
  846. if (styleStr != "") styleStr = "style='" + styleStr + "'";
  847. insertInline.call(iframeWin, 'p', {
  848. text: layero.find('#imgsPrev').html().replace(new RegExp(/(style="max-width:70px;margin:2px")/g), styleStr)
  849. }, range);
  850. */
  851. var list = document.getElementById('imgsPrev').children
  852. var objs = []
  853. for (var i = 0; i < list.length; i++) {
  854. objs.push({
  855. tagName: 'img',
  856. attr: {
  857. src: list[i].src,
  858. alt: list[i].alt,
  859. style: styleStr,
  860. },
  861. })
  862. }
  863. insertInlineAll.call(iframeWin, objs, range)
  864. layer.close(index)
  865. }
  866. },
  867. btn2: function (index, layero) {
  868. if (layero.find('#imgsPrev img').length > 0) {
  869. var imgPaths = ''
  870. for (var i = 0; i < layero.find('#imgsPrev img').length; i++) {
  871. imgPaths += layero.find('#imgsPrev img')[i].src
  872. }
  873. var callDel = set.calldel
  874. if (callDel.url != '') {
  875. $.post(callDel.url, { imgpath: imgPaths }, function (res) {
  876. callDel.done(res)
  877. })
  878. }
  879. }
  880. },
  881. cancel: function (index, layero) {
  882. if (layero.find('#imgsPrev img').length > 0) {
  883. var imgPaths = ''
  884. for (var i = 0; i < layero.find('#imgsPrev img').length; i++) {
  885. imgPaths += layero.find('#imgsPrev img')[i].src
  886. }
  887. var callDel = set.calldel
  888. if (callDel.url != '') {
  889. $.post(callDel.url, { imgpath: imgPaths }, function (res) {
  890. callDel.done(res)
  891. })
  892. }
  893. }
  894. },
  895. success: function (layero, index) {
  896. layui.use('upload', function () {
  897. var upload = layui.upload
  898. var uploadImage = set.uploadImage || {}
  899. if (uploadImage.url == '') {
  900. layer.msg('上传接口配置错误!')
  901. }
  902. var loding
  903. var errorIndex = [] //上传接口出错的文件索引
  904. //执行实例
  905. upload.render({
  906. elem: '#LayEdit_InsertImages',
  907. url: uploadImage.url,
  908. method: uploadImage.method,
  909. data: uploadImage.data,
  910. headers: uploadImage.headers,
  911. accept: uploadImage.accept || 'image',
  912. acceptMime: uploadImage.acceptMime || 'image/*',
  913. exts: uploadImage.exts || 'jpg|png|gif|bmp|jpeg',
  914. size: uploadImage.size || 1024 * 10,
  915. field: uploadImage.field,
  916. multiple: true,
  917. before: function (obj) {
  918. loding = layer.msg('文件上传中,请稍等', { icon: 16, shade: 0.3, time: 0 })
  919. obj.preview(function (index, file, result) {
  920. //由于有时预览会在allDone之后回调,此时所有单个文件的error已经执行,即已经出错的文件id以有,因此需要判断此预览文件id是否是上传出错文件的id,不是才预览
  921. if (errorIndex.indexOf(index) === -1)
  922. $('#imgsPrev').append(
  923. '<img data-index="' +
  924. index +
  925. '" src="' +
  926. result +
  927. '" alt="' +
  928. file.name +
  929. '" style="width:110px;height:110px;box-sizing: border-box;border: 1px solid #999;padding: 2px;margin-right:8px;margin-bottom:10px;" /> '
  930. )
  931. })
  932. },
  933. allDone: function () {
  934. //所有上传操作完成后,删除出错的文件
  935. for (var i = 0; i < errorIndex.length; i++) {
  936. $('#imgsPrev')
  937. .find('img[data-index="' + errorIndex[i] + '"]')
  938. .remove()
  939. }
  940. layer.close(loding)
  941. },
  942. error: function (index, upload) {
  943. //某文件上传接口返回错误时,将其错误index记录下来
  944. errorIndex.push(index)
  945. },
  946. done: function (res, index, upload) {
  947. if (res.code == 0) {
  948. res.data = res.data || {}
  949. $('#imgsPrev img[data-index="' + index + '"]').attr('src', res.data.src)
  950. uploadImage.done(res)
  951. } else if (res.code == 2) {
  952. res.data = res.data || {}
  953. $('#imgsPrev img[data-index="' + index + '"]').attr('src', res.data.src)
  954. uploadImage.done(res)
  955. } else {
  956. layer.msg(res.msg || '上传失败')
  957. }
  958. layero.find('#imgsPrev img').on('click', function () {
  959. var imgsrc = this.src
  960. var dataIndex = this.getAttribute('data-index')
  961. layer.confirm('是否删除该图片?', { icon: 3, title: '提示' }, function (index) {
  962. var callDel = set.calldel
  963. if (callDel.url != '') {
  964. $.post(callDel.url, { imgpath: imgsrc }, function (res) {
  965. $('#imgsPrev img[data-index=' + dataIndex + ']')[0].remove()
  966. callDel.done(res)
  967. })
  968. } else {
  969. layer.msg('没有配置回调参数')
  970. $('#imgsPrev img[data-index=' + dataIndex + ']')[0].remove()
  971. }
  972. layer.close(index)
  973. })
  974. })
  975. },
  976. })
  977. })
  978. },
  979. })
  980. },
  981. //图片2
  982. image_alt: function (range) {
  983. //使用通用的图片编辑
  984. imageEditor({
  985. context: {
  986. set: set,
  987. }, //上传成功后,用于删除之前的图片
  988. beforeUpload: function (imageData, context) {
  989. context.deleteImage(imageData)
  990. },
  991. success: function (imageData) {
  992. insertInline.call(
  993. iframeWin,
  994. 'img',
  995. {
  996. src: imageData.src,
  997. alt: imageData.alt,
  998. style: imageData.style,
  999. },
  1000. range
  1001. )
  1002. },
  1003. })
  1004. },
  1005. //插入视频
  1006. video: function (range) {
  1007. var body = this,
  1008. customTheme = set.customTheme || { video: [] },
  1009. customContent = ''
  1010. if (customTheme.video.title.length > 0) {
  1011. customContent = AddCustomThemes(customTheme.video.title, customTheme.video.content, customTheme.video.preview)
  1012. }
  1013. layer.open({
  1014. type: 1,
  1015. id: 'fly-jie-video-upload',
  1016. title: '视频管理',
  1017. shade: 0.05,
  1018. shadeClose: true,
  1019. area: (function () {
  1020. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 485) {
  1021. return ['90%']
  1022. } else {
  1023. return ['485px']
  1024. }
  1025. })(),
  1026. offset: (function () {
  1027. if (/mobile/i.test(navigator.userAgent)) {
  1028. return 'auto'
  1029. } else {
  1030. return '100px'
  1031. }
  1032. })(),
  1033. skin: 'layui-layer-border',
  1034. content: [
  1035. '<ul class="layui-form layui-form-pane" style="margin: 20px 20px 0 20px">',
  1036. '<li class="layui-form-item" style="position: relative">',
  1037. '<button type="button" class="layui-btn" id="LayEdit_InsertVideo" style="width: 110px;position: relative;z-index: 10;"> <i class="layui-icon"></i>上传视频</button>',
  1038. '<input type="text" name="video" placeholder="请选择文件" style="position: absolute;width: 100%;padding-left: 120px;left: 0;top:0" class="layui-input">',
  1039. '</li>',
  1040. '<li class="layui-form-item" style="position: relative">',
  1041. '<button type="button" class="layui-btn" id="LayEdit_InsertImage" style="width: 110px;position: relative;z-index: 10;"> <i class="layui-icon"></i>上传封面</button>',
  1042. '<input type="text" name="cover" placeholder="请选择文件" style="position: absolute;width: 100%;padding-left: 120px;left: 0;top:0" class="layui-input">',
  1043. '</li>',
  1044. customContent,
  1045. '</ul>',
  1046. ].join(''),
  1047. btn: ['确定', '取消'],
  1048. btnAlign: 'c',
  1049. yes: function (index, layero) {
  1050. var video = layero.find('input[name="video"]'),
  1051. cover = layero.find('input[name="cover"]'),
  1052. theme = layero.find('select[name="theme"]')
  1053. if (video.val() == '') {
  1054. layer.msg('请选择一个视频或输入视频地址')
  1055. } else {
  1056. var txt =
  1057. '&nbsp;<video src="' +
  1058. video.val() +
  1059. '" poster="' +
  1060. cover.val() +
  1061. '" ' +
  1062. set.videoAttr +
  1063. ' controls="controls" >您的浏览器不支持video播放</video>&nbsp;'
  1064. var custclass = ''
  1065. if (customTheme.video.title.length > 0 && theme.length > 0) {
  1066. //追加样式
  1067. custclass = theme[0].options[theme[0].selectedIndex].value
  1068. }
  1069. insertInline.call(
  1070. iframeWin,
  1071. 'div',
  1072. {
  1073. text: txt,
  1074. class: custclass,
  1075. },
  1076. range
  1077. )
  1078. layer.close(index)
  1079. }
  1080. },
  1081. btn2: function (index, layero) {
  1082. var callDel = set.calldel
  1083. if (callDel.url != '') {
  1084. $.post(
  1085. callDel.url,
  1086. {
  1087. imgpath: layero.find('input[name="cover"]').val(),
  1088. filepath: layero.find('input[name="video"]').val(),
  1089. },
  1090. function (res) {
  1091. callDel.done(res)
  1092. }
  1093. )
  1094. }
  1095. },
  1096. cancel: function (index, layero) {
  1097. var callDel = set.calldel
  1098. if (callDel.url != '') {
  1099. $.post(
  1100. callDel.url,
  1101. {
  1102. imgpath: layero.find('input[name="cover"]').val(),
  1103. filepath: layero.find('input[name="video"]').val(),
  1104. },
  1105. function (res) {
  1106. callDel.done(res)
  1107. }
  1108. )
  1109. }
  1110. },
  1111. success: function (layero, index) {
  1112. layui.use('upload', function (upload) {
  1113. var loding,
  1114. video = layero.find('input[name="video"]'),
  1115. cover = layero.find('input[name="cover"]'),
  1116. upload = layui.upload,
  1117. uploadImage = set.uploadImage || {}
  1118. if (uploadImage.url == '') {
  1119. layer.msg('图片上传接口配置错误!')
  1120. }
  1121. var uploadfile = set.uploadVideo || {}
  1122. if (uploadfile.url == '') {
  1123. layer.msg('视频上传接口配置错误!')
  1124. }
  1125. //执行实例
  1126. upload.render({
  1127. elem: '#LayEdit_InsertImage',
  1128. url: uploadImage.url,
  1129. method: uploadImage.method,
  1130. data: uploadImage.data,
  1131. headers: uploadImage.headers,
  1132. accept: uploadImage.accept || 'image',
  1133. acceptMime: uploadImage.acceptMime || 'image/*',
  1134. exts: uploadImage.exts || 'jpg|png|gif|bmp|jpeg',
  1135. size: uploadImage.size || 1024 * 10,
  1136. field: uploadImage.field,
  1137. before: function (obj) {
  1138. loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 })
  1139. },
  1140. done: function (res, input, upload) {
  1141. layer.close(loding)
  1142. if (res.code == 0) {
  1143. res.data = res.data || {}
  1144. cover.val(res.data.src)
  1145. uploadImage.done(res)
  1146. } else if (res.code == 2) {
  1147. var curIndex = layer.open({
  1148. type: 1,
  1149. anim: 2,
  1150. icon: 5,
  1151. title: '提示',
  1152. area: ['390px', '260px'],
  1153. offset: 't',
  1154. content:
  1155. res.msg +
  1156. "<div><img src='" +
  1157. res.data.src +
  1158. "' style='max-height:100px'/></div><p style='text-align:center'>确定使用该文件吗?</p>",
  1159. btn: ['确定', '取消'],
  1160. yes: function () {
  1161. res.data = res.data || {}
  1162. cover.val(res.data.src)
  1163. layer.close(curIndex)
  1164. },
  1165. })
  1166. } else {
  1167. layer.msg(res.msg || '上传失败')
  1168. }
  1169. },
  1170. })
  1171. upload.render({
  1172. elem: '#LayEdit_InsertVideo',
  1173. url: uploadfile.url,
  1174. method: uploadfile.method,
  1175. data: uploadfile.data,
  1176. headers: uploadfile.headers,
  1177. field: uploadfile.field,
  1178. accept: uploadfile.accept || 'video',
  1179. acceptMime: uploadfile.acceptMime || 'video/*',
  1180. exts: uploadfile.exts || 'mp4|flv|avi|rm|rmvb',
  1181. size: uploadfile.size || 1024 * 20,
  1182. before: function (obj) {
  1183. loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 })
  1184. },
  1185. done: function (res, input, upload) {
  1186. layer.close(loding)
  1187. if (res.code == 0) {
  1188. res.data = res.data || {}
  1189. video.val(res.data.src)
  1190. uploadfile.done(res)
  1191. } else if (res.code == 2) {
  1192. var curIndex = layer.open({
  1193. type: 1,
  1194. anim: 2,
  1195. icon: 5,
  1196. title: '提示',
  1197. area: ['390px', '260px'],
  1198. offset: 't',
  1199. content:
  1200. res.msg +
  1201. "<div><video src='" +
  1202. res.data.src +
  1203. "' style='max-height:100px' controls='controls'/></div><p style='text-align:center'>确定使用该文件吗?</p>",
  1204. btn: ['确定', '取消'],
  1205. yes: function () {
  1206. res.data = res.data || {}
  1207. video.val(res.data.src)
  1208. layer.close(curIndex)
  1209. },
  1210. })
  1211. } else {
  1212. layer.msg(res.msg || '上传失败')
  1213. }
  1214. },
  1215. })
  1216. var theme = layero.find('select[name="theme"]')
  1217. if (customTheme.video.title.length > 0 && theme.length > 0) {
  1218. layero.find('select[name="theme"]').on('change mouseover', function () {
  1219. layer.tips("<img src='" + theme[0].options[theme[0].selectedIndex].attributes['data-img'].value + "' />", this)
  1220. })
  1221. }
  1222. })
  1223. },
  1224. })
  1225. },
  1226. //上传附件
  1227. attachment: function (range) {
  1228. var that = this
  1229. layer.open({
  1230. type: 1,
  1231. id: 'fly-jie-image-upload',
  1232. title: '附件上传',
  1233. shade: 0.05,
  1234. shadeClose: true,
  1235. area: (function () {
  1236. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 485) {
  1237. return ['90%']
  1238. } else {
  1239. return ['485px']
  1240. }
  1241. })(),
  1242. offset: (function () {
  1243. if (/mobile/i.test(navigator.userAgent)) {
  1244. return 'auto'
  1245. } else {
  1246. return '100px'
  1247. }
  1248. })(),
  1249. skin: 'layui-layer-border',
  1250. content: [
  1251. '<ul class="layui-form layui-form-pane" style="margin: 20px 20px 0 20px;">',
  1252. '<li class="layui-form-item">',
  1253. '<div class="layui-upload">',
  1254. '<button type="button" class="layui-btn" id="LayEdit_InsertFiles"><i class="layui-icon"></i>上传附件</button> ',
  1255. '<blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;min-height: 116px">',
  1256. ' 上传列表:<div class="layui-upload-list" id="filesPrev"></div>',
  1257. '</blockquote>',
  1258. '</div>',
  1259. '</li>',
  1260. '</ul>',
  1261. ].join(''),
  1262. btn: ['确定', '取消'],
  1263. btnAlign: 'c',
  1264. yes: function (index, layero) {
  1265. if (layero.find('#filesPrev').find('a').length === 0) {
  1266. layer.msg('请选择要上传的附件')
  1267. } else {
  1268. insertInline.call(
  1269. iframeWin,
  1270. 'p',
  1271. {
  1272. text: layero.find('#filesPrev').html(),
  1273. },
  1274. range
  1275. )
  1276. layer.close(index)
  1277. }
  1278. },
  1279. success: function (layero, index) {
  1280. layui.use('upload', function () {
  1281. var upload = layui.upload
  1282. var uploadFiles = set.uploadFiles || {}
  1283. if (uploadFiles.url == '') {
  1284. layer.msg('上传接口配置错误!')
  1285. }
  1286. var errorIndex = [] //上传接口出错的文件索引
  1287. //执行实例
  1288. upload.render({
  1289. elem: '#LayEdit_InsertFiles',
  1290. url: uploadFiles.url,
  1291. field: uploadFiles.field,
  1292. headers: uploadFiles.headers,
  1293. data: uploadFiles.data,
  1294. method: uploadFiles.type,
  1295. accept: uploadFiles.accept || 'file',
  1296. acceptMime: uploadFiles.acceptMime || 'file/*',
  1297. exts: uploadFiles.exts,
  1298. size: uploadFiles.size || 1024 * 30,
  1299. multiple: true,
  1300. before: function (obj) {
  1301. obj.preview(function (index, file, result) {
  1302. //由于有时预览会在allDone之后回调,此时所有单个文件的error已经执行,即已经出错的文件id以有,因此需要判断此预览文件id是否是上传出错文件的id,不是才预览
  1303. if (errorIndex.indexOf(index) === -1)
  1304. $('#filesPrev').append(
  1305. '<a data-index="' + index + '" target="_blank" href="' + result + '" alt="' + file.name + '" >' + file.name + '</a>&nbsp;'
  1306. )
  1307. })
  1308. },
  1309. allDone: function () {
  1310. //所有上传操作完成后,删除出错的文件
  1311. for (var i = 0; i < errorIndex.length; i++) {
  1312. $('#filesPrev')
  1313. .find('a[data-index="' + errorIndex[i] + '"]')
  1314. .remove()
  1315. }
  1316. //触发自动插入编辑器功能
  1317. if (uploadFiles.autoInsert) {
  1318. insertInline.call(
  1319. iframeWin,
  1320. 'p',
  1321. {
  1322. text: layero.find('#filesPrev').html(),
  1323. },
  1324. range
  1325. )
  1326. layer.close(index)
  1327. }
  1328. },
  1329. error: function (index, upload) {
  1330. //某文件上传接口返回错误时,将其错误index记录下来
  1331. errorIndex.push(index)
  1332. },
  1333. done: function (res, index, upload) {
  1334. if (res.code == 0) {
  1335. res.data = res.data || {}
  1336. $('#filesPrev a[data-index="' + index + '"]').attr('href', res.data.src)
  1337. uploadFiles.done(res)
  1338. } else if (res.code == 2) {
  1339. layer.msg(res.msg || '上传失败')
  1340. res.data = res.data || {}
  1341. $('#filesPrev a[data-index="' + index + '"]').attr('href', res.data.src)
  1342. uploadFiles.done(res)
  1343. } else {
  1344. layer.msg(res.msg || '上传失败')
  1345. }
  1346. layero.find('#filesPrev a').on('click', function () {
  1347. var dataIndex = this.getAttribute('data-index')
  1348. layer.confirm('是否删除该附件?', { icon: 3, title: '提示' }, function (index) {
  1349. var callDel = set.calldel
  1350. if (callDel.url != '') {
  1351. $.post(callDel.url, { filepath: this.href }, function (res) {
  1352. $('#filesPrev')
  1353. .find('a[data-index="' + dataIndex + '"]')
  1354. .remove()
  1355. callDel.done(res)
  1356. })
  1357. } else {
  1358. layer.msg('没有配置回调参数')
  1359. $('#filesPrev')
  1360. .find('a[data-index="' + dataIndex + '"]')
  1361. .remove()
  1362. }
  1363. layer.close(index)
  1364. })
  1365. })
  1366. },
  1367. })
  1368. })
  1369. },
  1370. })
  1371. },
  1372. //源码模式
  1373. html: function (range) {
  1374. var that = this
  1375. if (that.parentElement.nextElementSibling.lastElementChild.id.indexOf('aceHtmleditor') == -1) {
  1376. var docs = that.parentElement.nextElementSibling.firstElementChild.contentDocument.body.innerHTML
  1377. if (docs.indexOf('</pre>') > -1) {
  1378. docs = docs
  1379. .replace(/&lt;/g, '<')
  1380. .replace(/&gt;/g, '>')
  1381. .replace(/&#39;/g, "'")
  1382. .replace(/&quot;/g, '"')
  1383. }
  1384. docs = style_html(docs, 4, ' ', 80)
  1385. that.parentElement.nextElementSibling.setAttribute(
  1386. 'style',
  1387. 'z-index: 999; overflow: hidden;height:' + that.parentElement.nextElementSibling.clientHeight + 'px'
  1388. )
  1389. if (this.parentElement.parentElement.getAttribute('style') !== null)
  1390. this.parentElement.nextElementSibling.setAttribute(
  1391. 'style',
  1392. 'z-index: 999; overflow: hidden;height: ' +
  1393. (this.parentElement.parentElement.offsetHeight - this.parentElement.offsetHeight - 14) +
  1394. 'px'
  1395. )
  1396. that.parentElement.nextElementSibling.firstElementChild.style = 'position: absolute;left: -32768px;top: -32768px;'
  1397. var htmlPanel = document.createElement('div')
  1398. htmlPanel.setAttribute('id', that.parentElement.nextElementSibling.firstElementChild.id + 'aceHtmleditor')
  1399. htmlPanel.setAttribute('style', 'left: 0px;top: 0px;width: 100%;height: 100%')
  1400. that.parentElement.nextElementSibling.appendChild(htmlPanel)
  1401. var editor = ace.edit(that.parentElement.nextElementSibling.firstElementChild.id + 'aceHtmleditor')
  1402. editor.setFontSize(14)
  1403. editor.session.setMode('ace/mode/html')
  1404. editor.setTheme('ace/theme/tomorrow')
  1405. editor.setValue(docs)
  1406. editor.setOption('wrap', 'free')
  1407. editor.gotoLine(0)
  1408. //工具栏屏蔽
  1409. $(that).siblings('i').addClass('layui-disabled')
  1410. $(that).siblings('.layedit-tool-fullScreen').removeClass('layui-disabled')
  1411. $(that).removeClass('layui-disabled')
  1412. } else {
  1413. var editor = ace.edit(that.parentElement.nextElementSibling.firstElementChild.id + 'aceHtmleditor')
  1414. var doc = editor.getValue()
  1415. iframeWin.document.body.innerHTML = doc
  1416. iframeWin.document.body.childNodes.forEach(function (item, index, arr) {
  1417. if (item.tagName == 'PRE') {
  1418. item.innerHTML = item.innerHTML
  1419. .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
  1420. .replace(/</g, '&lt;')
  1421. .replace(/>/g, '&gt;')
  1422. .replace(/'/g, '&#39;')
  1423. .replace(/"/g, '&quot;')
  1424. }
  1425. })
  1426. var height = that.parentElement.nextElementSibling.clientHeight
  1427. that.parentElement.nextElementSibling.removeAttribute('style')
  1428. this.parentElement.nextElementSibling.firstElementChild.style = 'height:' + height + 'px'
  1429. this.parentElement.nextElementSibling.lastElementChild.remove()
  1430. $(that).siblings('i').removeClass('layui-disabled')
  1431. }
  1432. },
  1433. //全屏
  1434. fullScreen: function (range) {
  1435. if (this.parentElement.parentElement.getAttribute('style') == null) {
  1436. this.parentElement.parentElement.setAttribute(
  1437. 'style',
  1438. 'position: fixed;top: 0;left: 0;height: 100%;width: 100%;background-color: #fff;z-index: 9999;'
  1439. )
  1440. this.parentElement.nextElementSibling.style =
  1441. 'height:' + (this.parentElement.parentElement.offsetHeight - this.parentElement.offsetHeight - 8) + 'px'
  1442. this.parentElement.nextElementSibling.firstElementChild.style = 'height:100%'
  1443. //是否源码模式
  1444. if (this.parentElement.nextElementSibling.lastElementChild.id.indexOf('aceHtmleditor') > -1) {
  1445. this.parentElement.nextElementSibling.firstElementChild.style = 'position: absolute;left: -32768px;top: -32768px;'
  1446. this.parentElement.nextElementSibling.setAttribute(
  1447. 'style',
  1448. 'z-index: 999; overflow: hidden;height: ' + (this.parentElement.parentElement.offsetHeight - this.parentElement.offsetHeight) + 'px'
  1449. )
  1450. }
  1451. } else {
  1452. this.parentElement.parentElement.removeAttribute('style')
  1453. this.parentElement.nextElementSibling.removeAttribute('style')
  1454. this.parentElement.nextElementSibling.firstElementChild.style = 'height:' + set.height
  1455. if (this.parentElement.nextElementSibling.lastElementChild.id.indexOf('aceHtmleditor') > -1) {
  1456. this.parentElement.nextElementSibling.setAttribute(
  1457. 'style',
  1458. 'z-index: 999; overflow: hidden;height:' + this.parentElement.nextElementSibling.firstElementChild.clientHeight + 'px'
  1459. )
  1460. this.parentElement.nextElementSibling.firstElementChild.style = 'position: absolute;left: -32768px;top: -32768px;'
  1461. }
  1462. }
  1463. },
  1464. preview: function (range) {
  1465. var currStyle = []
  1466. layui.each(set.quote.style, function (index, item) {
  1467. currStyle.push('<link href="' + item + '" rel="stylesheet"/>')
  1468. })
  1469. var setPreview = set.previewAttr || {
  1470. area: ['50%', '100%'],
  1471. offset: 'r',
  1472. }
  1473. var docs = this.parentElement.nextElementSibling.firstElementChild.contentDocument.body.innerHTML
  1474. layer.open({
  1475. type: 1,
  1476. id: 'layui-kz-preview',
  1477. title: '预览',
  1478. shade: 0.05,
  1479. maxmin: true,
  1480. full: function (index) {
  1481. index[0].style.height = $('.layui-layer-shade').offsetHeight + 'px'
  1482. index[0].children[1].style.height = $('.layui-layer-shade').offsetHeight - 43 + 'px'
  1483. },
  1484. min: function (index) {},
  1485. restore: function (index) {
  1486. index[0].style.height = document.body.clientHeight - 100 + 'px'
  1487. index[0].children[1].style.height = document.body.clientHeight - 143 + 'px'
  1488. },
  1489. shadeClose: true,
  1490. area: (function () {
  1491. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 485) {
  1492. return ['90%', '90%']
  1493. } else {
  1494. return setPreview.area
  1495. }
  1496. })(),
  1497. offset: (function () {
  1498. if (/mobile/i.test(navigator.userAgent)) {
  1499. return 'auto'
  1500. } else {
  1501. return setPreview.offset
  1502. }
  1503. })(),
  1504. content: currStyle.join('') + docs,
  1505. success: function (layero, index) {
  1506. //layer.full(index);//全屏
  1507. layer.setTop(layero) //置顶
  1508. },
  1509. })
  1510. },
  1511. removeformat: function (range) {
  1512. //if (device.ie)
  1513. // iframeDOM.execCommand('backColor', false, "#fff");
  1514. //else
  1515. // iframeDOM.execCommand('hiliteColor', false, "#fff");
  1516. //iframeDOM.execCommand('forecolor', false, "#000");
  1517. iframeDOM.execCommand('removeFormat', 'strong', 'color')
  1518. setTimeout(function () {
  1519. body.focus()
  1520. }, 10)
  1521. },
  1522. fontFomatt: function (range) {
  1523. var alt = set.fontFomatt || {
  1524. code: ['p', 'h1', 'h2', 'h3', 'h4', 'div'],
  1525. text: ['正文(p)', '一级标题(h1)', '二级标题(h2)', '三级标题(h3)', '四级标题(h4)', '块级元素(div)'],
  1526. }
  1527. var arr = {},
  1528. arr2 = {},
  1529. codes = alt.code,
  1530. texts = alt.text,
  1531. fonts = (function () {
  1532. layui.each(codes, function (index, item) {
  1533. arr[index] = item
  1534. })
  1535. return arr
  1536. })(),
  1537. fonttexts = (function () {
  1538. layui.each(texts, function (index, item) {
  1539. arr2[index] = item
  1540. })
  1541. return arr2
  1542. })()
  1543. fontFomatt.call(this, { fonts: fonts, texts: fonttexts }, function (value) {
  1544. iframeDOM.execCommand('formatBlock', false, '<' + value + '>')
  1545. setTimeout(function () {
  1546. body.focus()
  1547. }, 10)
  1548. })
  1549. },
  1550. fontfamily: function (range) {
  1551. var alt = set.fontfamily || {
  1552. code: [
  1553. 'font-family:宋体,SimSun',
  1554. 'font-family:微软雅黑,Microsoft YaHei',
  1555. 'font-family:黑体, SimHei',
  1556. 'font-family:楷体,楷体_GB2312, SimKai',
  1557. 'font-family:arial, helvetica,sans-serif',
  1558. 'font-family:arial black,avant garde',
  1559. 'font-family:times new roman',
  1560. ],
  1561. text: ['宋体', '微软雅黑', '黑体', '楷体', 'arial', 'arial black', 'times new roman'],
  1562. }
  1563. var arr = {},
  1564. arr2 = {},
  1565. codes = alt.code,
  1566. texts = alt.text,
  1567. fonts = (function () {
  1568. layui.each(codes, function (index, item) {
  1569. arr[index] = item
  1570. })
  1571. return arr
  1572. })(),
  1573. fonttexts = (function () {
  1574. layui.each(texts, function (index, item) {
  1575. arr2[index] = item
  1576. })
  1577. return arr2
  1578. })()
  1579. fontfamily.call(this, { fonts: fonts, texts: fonttexts }, function (value) {
  1580. insertInline.call(
  1581. iframeWin,
  1582. 'span',
  1583. {
  1584. style: value,
  1585. text: '&nbsp;',
  1586. },
  1587. range
  1588. )
  1589. setTimeout(function () {
  1590. body.focus()
  1591. }, 10)
  1592. })
  1593. },
  1594. /*
  1595. , fontSize: function (range) {
  1596. var alt = set.fontSize || {
  1597. code: ["font-size:10px", "font-size:12px", "font-size:14px", "font-size:16px", "font-size:18px", "font-size:20px", "font-size:24px", "font-size:26px", "font-size:28px", "font-size:30px", "font-size:32px"]
  1598. , text: ["10px", "12px", "14px", "16px", "18px", "20px", "24px", "26px", "28px", "30px", "32px"]
  1599. };
  1600. var arr = {}
  1601. , arr2 = {}
  1602. , codes = alt.code
  1603. , texts = alt.text
  1604. , fonts = function () {
  1605. layui.each(codes, function (index, item) {
  1606. arr[index] = item;
  1607. });
  1608. return arr;
  1609. }()
  1610. , fonttexts = function () {
  1611. layui.each(texts, function (index, item) {
  1612. arr2[index] = item;
  1613. });
  1614. return arr2;
  1615. }();
  1616. fontSize.call(this, { fonts: fonts, texts: fonttexts }, function (value) {
  1617. insertInline.call(iframeWin, 'span', {
  1618. style: value
  1619. , text: "&nbsp;"
  1620. }, range);
  1621. setTimeout(function () {
  1622. body.focus();
  1623. }, 10);
  1624. });
  1625. }
  1626. */
  1627. // 字体大小
  1628. fontSize: function (range) {
  1629. var alt = set.fontSize || {
  1630. code: ['1', '2', '3', '4', '5', '6', '7'],
  1631. text: ['9px', '13px', '16px', '18px', '24px', '32px', '48px'],
  1632. },
  1633. arr = {},
  1634. arr2 = {}
  1635. var codes = alt.code
  1636. var texts = alt.text
  1637. var fonts = (function () {
  1638. layui.each(codes, function (index, item) {
  1639. arr[index] = item
  1640. })
  1641. return arr
  1642. })()
  1643. var fonttexts = (function () {
  1644. layui.each(texts, function (index, item) {
  1645. arr2[index] = item
  1646. })
  1647. return arr2
  1648. })()
  1649. fontSize.call(this, { fonts: fonts, texts: fonttexts, last_value: set.fontSize_value }, function (value) {
  1650. set.fontSize_value = value
  1651. var fontText = alt.code.indexOf(value)
  1652. if (fontText > 0) {
  1653. fontText = alt.text[fontText]
  1654. } else {
  1655. fontText = value
  1656. }
  1657. // 获取到对应的节点id
  1658. var list = getRangeNodes(range)
  1659. // window.iframeDOM = iframeDOM;
  1660. layer.msg('已成功设置字号为:' + fontText, { icon: 6 })
  1661. iframeDOM.execCommand('FontSize', false, value)
  1662. // 修改字体样式
  1663. for (var i = 0; i < list.length; i++) {
  1664. var len = list[i].children.length
  1665. if (!len || len == 0) {
  1666. continue
  1667. }
  1668. for (var j = 0; j < len; j++) {
  1669. if (list[i].children[j].nodeName == 'FONT') {
  1670. list[i].children[j].size = null
  1671. list[i].children[j].style.fontSize = fontText
  1672. }
  1673. }
  1674. }
  1675. // d.queryCommandValue("FontSize")
  1676. // iframeDOM.queryCommandValue('FontSize', false, value)
  1677. setTimeout(function () {
  1678. body.focus()
  1679. // 进行批量更改
  1680. }, 10)
  1681. })
  1682. },
  1683. // 间距
  1684. lineHeight: function (range) {
  1685. var alt = set.lineHeight || {
  1686. code: ['1', '1.5', '1.75', '2', '3', '4', '5'],
  1687. text: ['1', '1.5', '1.75', '2', '3', '4', '5'],
  1688. },
  1689. arr = {},
  1690. arr2 = {}
  1691. var codes = alt.code
  1692. var texts = alt.text
  1693. var fonts = (function () {
  1694. layui.each(codes, function (index, item) {
  1695. arr[index] = item
  1696. })
  1697. return arr
  1698. })()
  1699. var fonttexts = (function () {
  1700. layui.each(texts, function (index, item) {
  1701. arr2[index] = item
  1702. })
  1703. return arr2
  1704. })()
  1705. lineHeight.call(this, { fonts: fonts, texts: fonttexts, last_value: set.lineHeight_value }, function (value) {
  1706. set.lineHeight_value = value
  1707. var fontText = alt.code.indexOf(value)
  1708. if (fontText > 0) {
  1709. fontText = alt.text[fontText]
  1710. } else {
  1711. fontText = value
  1712. }
  1713. // 获取到对应的节点id
  1714. var list = getRangeNodes(range)
  1715. // window.iframeDOM = iframeDOM;
  1716. layer.msg('已成功设置行间距为:' + fontText, { icon: 6 })
  1717. // iframeDOM.execCommand('FontSize', false, value);
  1718. window.list = list
  1719. // 修改字体样式
  1720. for (var i = 0; i < list.length; i++) {
  1721. var len = list[i].children.length
  1722. list[i].style.lineHeight = value + 'em'
  1723. }
  1724. // iframeDOM.execCommand('formatBlock', false, "<" + value + ">");
  1725. setTimeout(function () {
  1726. body.focus()
  1727. }, 10)
  1728. })
  1729. },
  1730. customlink: function (range) {
  1731. var container = getContainer(range),
  1732. parentNode = $(container).parent()
  1733. customlink.call(body, { title: set.customlink.title }, function (field) {
  1734. var parent = parentNode[0]
  1735. if (parent.tagName === 'A') {
  1736. parent.href = field.url
  1737. parent.rel = field.rel
  1738. } else {
  1739. insertInline.call(
  1740. iframeWin,
  1741. 'a',
  1742. {
  1743. target: '_blank',
  1744. href: set.customlink.href,
  1745. rel: 'nofollow',
  1746. text: field.text,
  1747. onmouseup: set.customlink.onmouseup,
  1748. },
  1749. range
  1750. )
  1751. }
  1752. })
  1753. },
  1754. anchors: function (range) {
  1755. anchors.call(body, {}, function (field) {
  1756. insertInline.call(
  1757. iframeWin,
  1758. 'a',
  1759. {
  1760. name: field.text,
  1761. text: ' ',
  1762. },
  1763. range
  1764. )
  1765. })
  1766. },
  1767. table: function (range) {
  1768. table.call(this, {}, function (opts) {
  1769. var tbody = '<tr>'
  1770. for (var i = 0; i < opts.cells; i++) {
  1771. tbody += '<td></td>'
  1772. }
  1773. tbody += '</tr>'
  1774. var tmptr = tbody
  1775. for (var i = 0; i < opts.rows; i++) {
  1776. tbody += tmptr
  1777. }
  1778. insertInline.call(
  1779. iframeWin,
  1780. 'table',
  1781. {
  1782. text: tbody,
  1783. },
  1784. range
  1785. )
  1786. })
  1787. },
  1788. addhr: function (range) {
  1789. insertInline.call(iframeWin, 'hr', {}, range)
  1790. },
  1791. /*End*/
  1792. //帮助
  1793. help: function () {
  1794. layer.open({
  1795. type: 2,
  1796. title: '帮助',
  1797. area: ['600px', '380px'],
  1798. shadeClose: true,
  1799. shade: 0.1,
  1800. offset: '100px',
  1801. skin: 'layui-layer-msg',
  1802. content: ['http://www.layui.com/about/layedit/help.html', 'no'],
  1803. })
  1804. },
  1805. },
  1806. tools = editor.find('.layui-layedit-tool'),
  1807. click = function () {
  1808. var othis = $(this),
  1809. events = othis.attr('layedit-event'),
  1810. command = othis.attr('lay-command')
  1811. if (othis.hasClass(ABLED)) return
  1812. body.focus()
  1813. var range = Range(iframeDOM),
  1814. container = range.commonAncestorContainer
  1815. if (command) {
  1816. if (/justifyLeft|justifyCenter|justifyRight/.test(command)) {
  1817. if (container.parentNode.tagName === 'BODY') {
  1818. iframeDOM.execCommand('formatBlock', false, '<p>')
  1819. }
  1820. }
  1821. iframeDOM.execCommand(command)
  1822. setTimeout(function () {
  1823. if (/Bold/.test(command)) {
  1824. var elem = document.createElement('strong')
  1825. body.find('b').each(function () {
  1826. elem.innerText = this.innerText
  1827. this.outerHTML = elem.outerHTML
  1828. })
  1829. }
  1830. body.focus()
  1831. }, 10)
  1832. } else {
  1833. toolEvent[events] && toolEvent[events].call(this, range, iframeDOM)
  1834. }
  1835. toolCheck.call(iframeWin, tools, othis)
  1836. },
  1837. isClick = /image/
  1838. tools
  1839. .find('>i')
  1840. .on('mousedown', function () {
  1841. var othis = $(this),
  1842. events = othis.attr('layedit-event')
  1843. if (isClick.test(events)) return
  1844. click.call(this)
  1845. })
  1846. .on('click', function () {
  1847. var othis = $(this),
  1848. events = othis.attr('layedit-event')
  1849. if (!isClick.test(events)) return
  1850. click.call(this)
  1851. })
  1852. //触发内容区域
  1853. body.on('click', function () {
  1854. toolCheck.call(iframeWin, tools)
  1855. layer.close(face.index)
  1856. layer.close(fontFomatt.index)
  1857. layer.close(fontfamily.index)
  1858. layer.close(fontSize.index)
  1859. layer.close(table.index)
  1860. })
  1861. //右键菜单自定义
  1862. var rbtnIndex = null
  1863. var contextmenu = function (event) {
  1864. var rbtn = set.rightBtn || {
  1865. type: 'layBtn',
  1866. customEvent: function (tagName, event) {},
  1867. }
  1868. if (event != null && rbtn.type != 'default') {
  1869. layer.close(rbtnIndex)
  1870. var currenNode, parentNode
  1871. currenNode = event.target
  1872. parentNode = currenNode.parentNode
  1873. if (rbtn.type == 'custom') {
  1874. rbtn.customEvent(currenNode.tagName, event)
  1875. return false
  1876. }
  1877. switch (currenNode.tagName) {
  1878. case 'IMG':
  1879. imageEditor({
  1880. context: {
  1881. set: set,
  1882. },
  1883. data: {
  1884. src: event.target.src,
  1885. alt: event.target.alt,
  1886. width: event.target.style.width || event.target.getAttribute('width'),
  1887. height: event.target.style.height || event.target.getAttribute('height'),
  1888. }, //打开图片编辑器之前
  1889. // beforeOpen: function (options, context) {
  1890. // //增加图片删除按钮
  1891. // options.btn.push('<span style="background:#FF5722;color:#FFF;display:block;margin:0 -15px;padding:0 15px;">删除</span>')
  1892. // options.btn3 = function (index, layero) {
  1893. // context.deleteImage(context.getImageData(), { src: 'must-delete' })
  1894. // event.toElement.remove()
  1895. // layer.close(index)
  1896. // }
  1897. // }, //上传前,用于删除之前的图片
  1898. beforeUpload: function (imageData, context) {
  1899. context.deleteImage(imageData)
  1900. }, //点击确定后
  1901. success: function (imageData, context) {
  1902. event.target.src = imageData.src
  1903. event.target.alt = imageData.alt
  1904. event.target.style.width = imageData.width
  1905. event.target.style.height = imageData.height
  1906. },
  1907. })
  1908. break
  1909. case 'VIDEO':
  1910. var customTheme = set.customTheme || { video: [] },
  1911. customContent = ''
  1912. if (customTheme.video.title.length > 0) {
  1913. customContent = AddCustomThemes(customTheme.video.title, customTheme.video.content, customTheme.video.preview)
  1914. }
  1915. rbtnIndex = layer.open({
  1916. type: 1,
  1917. id: 'fly-jie-video-upload',
  1918. title: '视频管理',
  1919. shade: 0.05,
  1920. shadeClose: true,
  1921. area: (function () {
  1922. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 485) {
  1923. return ['90%']
  1924. } else {
  1925. return ['485px']
  1926. }
  1927. })(),
  1928. offset: (function () {
  1929. if (/mobile/i.test(navigator.userAgent)) {
  1930. return 'auto'
  1931. } else {
  1932. return '100px'
  1933. }
  1934. })(),
  1935. skin: 'layui-layer-border',
  1936. content: [
  1937. '<ul class="layui-form layui-form-pane" style="margin: 20px 20px 0 20px">',
  1938. '<li class="layui-form-item" style="position: relative">',
  1939. '<button type="button" class="layui-btn" id="LayEdit_InsertVideo" style="width: 110px;position: relative;z-index: 10;"> <i class="layui-icon"></i>上传视频</button>',
  1940. '<input type="text" name="video" value="' +
  1941. event.target.src +
  1942. '" placeholder="请选择文件" style="position: absolute;width: 100%;padding-left: 120px;left: 0;top:0" class="layui-input">',
  1943. '</li>',
  1944. '<li class="layui-form-item" style="position: relative">',
  1945. '<button type="button" class="layui-btn" id="LayEdit_InsertImage" style="width: 110px;position: relative;z-index: 10;"> <i class="layui-icon"></i>上传封面</button>',
  1946. '<input type="text" name="cover" value="' +
  1947. event.target.poster +
  1948. '" placeholder="请选择文件" style="position: absolute;width: 100%;padding-left: 120px;left: 0;top:0" class="layui-input">',
  1949. '</li>',
  1950. customContent,
  1951. '</ul>',
  1952. ].join(''),
  1953. btn: ['确定', '取消', '<span style="color:red">删除</span>'],
  1954. btnAlign: 'c',
  1955. yes: function (index, layero) {
  1956. var video = layero.find('input[name="video"]'),
  1957. cover = layero.find('input[name="cover"]')
  1958. if (video.val() == '') {
  1959. layer.msg('请选择一个视频或输入视频地址')
  1960. } else {
  1961. event.target.src = video.val()
  1962. event.target.poster = cover.val()
  1963. layer.close(index)
  1964. }
  1965. },
  1966. btn2: function (index, layero) {},
  1967. btn3: function (index, layero) {
  1968. var callDel = set.calldel
  1969. if (callDel.url != '') {
  1970. $.post(
  1971. callDel.url,
  1972. {
  1973. filepath: event.target.src,
  1974. imgpath: event.target.poster,
  1975. },
  1976. function (res) {
  1977. parentNode.remove()
  1978. callDel.done(res)
  1979. }
  1980. )
  1981. } else {
  1982. event.toElement.remove()
  1983. }
  1984. layer.close(index)
  1985. },
  1986. success: function (layero, index) {
  1987. layui.use('upload', function (upload) {
  1988. var loding,
  1989. video = layero.find('input[name="video"]'),
  1990. cover = layero.find('input[name="cover"]'),
  1991. upload = layui.upload,
  1992. uploadImage = set.uploadImage || {},
  1993. uploadfile = set.uploadVideo || {}
  1994. if (uploadImage.url == '') {
  1995. layer.msg('图片上传接口配置错误!')
  1996. }
  1997. if (uploadfile.url == '') {
  1998. layer.msg('视频上传接口配置错误!')
  1999. }
  2000. //执行实例
  2001. upload.render({
  2002. elem: '#LayEdit_InsertImage',
  2003. url: uploadImage.url,
  2004. method: uploadImage.method,
  2005. data: uploadImage.data,
  2006. headers: uploadImage.headers,
  2007. accept: uploadImage.accept || 'image',
  2008. acceptMime: uploadImage.acceptMime || 'image/*',
  2009. exts: uploadImage.exts || 'jpg|png|gif|bmp|jpeg',
  2010. size: uploadImage.size || 1024 * 10,
  2011. field: uploadImage.field,
  2012. before: function (obj) {
  2013. loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 })
  2014. },
  2015. done: function (res, input, upload) {
  2016. layer.close(loding)
  2017. if (res.code == 0) {
  2018. res.data = res.data || {}
  2019. cover.val(res.data.src)
  2020. uploadImage.done(res)
  2021. } else if (res.code == 2) {
  2022. var curIndex = layer.open({
  2023. type: 1,
  2024. anim: 2,
  2025. icon: 5,
  2026. title: '提示',
  2027. area: ['390px', '260px'],
  2028. offset: 't',
  2029. content:
  2030. res.msg +
  2031. "<div><img src='" +
  2032. res.data.src +
  2033. "' style='max-height:100px'/></div><p style='text-align:center'>确定使用该文件吗?</p>",
  2034. btn: ['确定', '取消'],
  2035. yes: function () {
  2036. res.data = res.data || {}
  2037. cover.val(res.data.src)
  2038. layer.close(curIndex)
  2039. },
  2040. })
  2041. } else {
  2042. layer.msg(res.msg || '上传失败')
  2043. }
  2044. },
  2045. })
  2046. upload.render({
  2047. elem: '#LayEdit_InsertVideo',
  2048. url: uploadfile.url,
  2049. method: uploadfile.method,
  2050. data: uploadfile.data,
  2051. headers: uploadfile.headers,
  2052. field: uploadfile.field,
  2053. accept: uploadfile.accept || 'video',
  2054. acceptMime: uploadfile.acceptMime || 'video/*',
  2055. exts: uploadfile.exts || 'mp4|flv|avi|rm|rmvb',
  2056. size: uploadfile.size || 1024 * 20,
  2057. before: function (obj) {
  2058. loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 })
  2059. },
  2060. done: function (res, input, upload) {
  2061. layer.close(loding)
  2062. if (res.code == 0) {
  2063. res.data = res.data || {}
  2064. video.val(res.data.src)
  2065. uploadfile.done(res)
  2066. } else if (res.code == 2) {
  2067. var curIndex = layer.open({
  2068. type: 1,
  2069. anim: 2,
  2070. icon: 5,
  2071. title: '提示',
  2072. area: ['390px', '260px'],
  2073. offset: 't',
  2074. content:
  2075. res.msg +
  2076. "<div><video src='" +
  2077. res.data.src +
  2078. "' style='max-height:100px' controls='controls'/></div><p style='text-align:center'>确定使用该文件吗?</p>",
  2079. btn: ['确定', '取消'],
  2080. yes: function () {
  2081. res.data = res.data || {}
  2082. video.val(res.data.src)
  2083. layer.close(curIndex)
  2084. },
  2085. })
  2086. } else {
  2087. layer.msg(res.msg || '上传失败')
  2088. }
  2089. },
  2090. })
  2091. var theme = layero.find('select[name="theme"]')
  2092. if (customTheme.video.title.length > 0 && theme.length > 0) {
  2093. layero.find('select[name="theme"]').on('change mouseover', function () {
  2094. layer.tips("<img src='" + theme[0].options[theme[0].selectedIndex].attributes['data-img'].value + "' />", this)
  2095. })
  2096. }
  2097. })
  2098. },
  2099. })
  2100. break
  2101. case 'TD':
  2102. rbtnIndex = layer.open({
  2103. type: 1,
  2104. title: false,
  2105. shade: 0,
  2106. offset: [event.clientY + 'px', event.clientX + 'px'],
  2107. skin: 'layui-box layui-util-face',
  2108. content: (function () {
  2109. var content = [
  2110. ,
  2111. '<li style="float: initial;width:100%;" lay-command="addnewtr"> 新增行 </li>',
  2112. '<li style="float: initial;width:100%;" lay-command="deltr"> 删除行 </li>',
  2113. ].join('')
  2114. return '<ul class="layui-clear" style="width: max-content;width:-moz-max-content;">' + content + '</ul>'
  2115. })(),
  2116. success: function (layero, index) {
  2117. layero.find('li').on('click', function () {
  2118. var othis = $(this),
  2119. command = othis.attr('lay-command')
  2120. if (command) {
  2121. switch (command) {
  2122. case 'deltr':
  2123. parentNode.remove()
  2124. break
  2125. case 'addnewtr':
  2126. var html = '<tr>'
  2127. for (var i = 0; i < parentNode.children.length; i++) {
  2128. html += '<td></td>'
  2129. }
  2130. html += '</tr>'
  2131. $(parentNode).after(html)
  2132. break
  2133. }
  2134. }
  2135. layer.close(index)
  2136. })
  2137. },
  2138. })
  2139. break
  2140. default:
  2141. rbtnIndex = layer.open({
  2142. type: 1,
  2143. title: false,
  2144. closeBtn: false,
  2145. offset: (function () {
  2146. if (/mobile/i.test(navigator.userAgent)) {
  2147. return 'auto'
  2148. } else {
  2149. var frame = set._elem.next().find('iframe').get(0)
  2150. return [
  2151. frame.offsetTop + event.clientY + parentNode.getBoundingClientRect().y + 'px',
  2152. frame.offsetLeft + event.clientX + parentNode.getBoundingClientRect().x + 'px',
  2153. ]
  2154. }
  2155. })(),
  2156. shade: function () {
  2157. if (/mobile/i.test(navigator.userAgent)) {
  2158. return 0.1
  2159. }
  2160. return 0
  2161. },
  2162. shadeClose: true,
  2163. content: [
  2164. '<style>',
  2165. 'ul.context-menu > li > a{border: none;border-bottom: 1px solid rgba(0,0,0,.2);border-radius: 0}',
  2166. 'ul.context-menu > li > a:hover{border-color: rgba(0,0,0,.2);background:#eaeaea}',
  2167. 'ul.context-menu > li:last-child > a{border: none;}',
  2168. '</style>',
  2169. '<ul style="width:100px" class="context-menu">',
  2170. '<li><a type="button" class="layui-btn layui-btn-primary layui-btn-sm" style="width:100%" lay-command="left"> 居左 </a></li>',
  2171. '<li><a type="button" class="layui-btn layui-btn-primary layui-btn-sm" style="width:100%" lay-command="center"> 居中 </a></li>',
  2172. '<li><a type="button" class="layui-btn layui-btn-primary layui-btn-sm" style="width:100%" lay-command="right"> 居右 </a></li>',
  2173. '<li><a type="button" class="layui-btn layui-btn-primary layui-btn-sm context-menu-delete" style="width:100%" lay-command="right"> 删除 </a></li>',
  2174. '</ul>',
  2175. ].join(''),
  2176. success: function (layero, index) {
  2177. var callDel = set.calldel
  2178. layero.find('.layui-btn-primary').on('click', function () {
  2179. var othis = $(this),
  2180. command = othis.attr('lay-command')
  2181. if (command) {
  2182. if (currenNode.tagName == 'VIDEO') {
  2183. parentNode.style = 'text-align:' + command
  2184. } else {
  2185. currenNode.style = 'text-align:' + command
  2186. }
  2187. }
  2188. layer.close(index)
  2189. })
  2190. layero.find('.context-menu-delete').on('click', function () {
  2191. if (currenNode.tagName == 'BODY') {
  2192. layer.msg('不能再删除了')
  2193. } else if (currenNode.tagName == 'VIDEO') {
  2194. if (callDel.url != '') {
  2195. $.post(
  2196. callDel.url,
  2197. {
  2198. filepath: event.target.src,
  2199. imgpath: event.target.poster,
  2200. },
  2201. function (res) {
  2202. parentNode.remove()
  2203. callDel.done(res)
  2204. }
  2205. )
  2206. } else {
  2207. parentNode.remove()
  2208. }
  2209. } else if (currenNode.tagName == 'IMG') {
  2210. if (callDel.url != '') {
  2211. $.post(callDel.url, { para: event.target.src }, function (res) {
  2212. currenNode.remove()
  2213. callDel.done(res)
  2214. })
  2215. } else {
  2216. currenNode.remove()
  2217. }
  2218. } else {
  2219. currenNode.remove()
  2220. }
  2221. layer.close(index)
  2222. })
  2223. },
  2224. })
  2225. break
  2226. //return true;
  2227. }
  2228. return false
  2229. }
  2230. }
  2231. if (/mobile/i.test(navigator.userAgent)) {
  2232. var timeOutEvent
  2233. body.on({
  2234. touchstart: function (e) {
  2235. // 长按事件触发
  2236. timeOutEvent = setTimeout(function () {
  2237. contextmenu(e)
  2238. clearTimeout(timeOutEvent)
  2239. }, 300)
  2240. //长按300毫秒
  2241. e.preventDefault()
  2242. },
  2243. touchmove: function () {
  2244. clearTimeout(timeOutEvent)
  2245. },
  2246. touchend: function () {
  2247. clearTimeout(timeOutEvent)
  2248. },
  2249. })
  2250. } else {
  2251. body.on('contextmenu', function (event) {
  2252. return contextmenu(event)
  2253. })
  2254. }
  2255. },
  2256. //超链接面板
  2257. link = function (options, callback) {
  2258. var dMode = options.dmode
  2259. var body = this,
  2260. index = layer.open({
  2261. type: 1,
  2262. id: 'LAY_layedit_link',
  2263. area: (function () {
  2264. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 460) {
  2265. return ['90%']
  2266. } else {
  2267. return ['460px']
  2268. }
  2269. })(),
  2270. offset: (function () {
  2271. if (/mobile/i.test(navigator.userAgent)) {
  2272. return 'auto'
  2273. } else {
  2274. return '100px'
  2275. }
  2276. })(),
  2277. shade: 0.05,
  2278. shadeClose: true,
  2279. moveType: 1,
  2280. title: '超链接',
  2281. skin: 'layui-layer-msg',
  2282. content: [
  2283. '<ul class="layui-form" style="margin: 15px;">',
  2284. '<li class="layui-form-item">',
  2285. '<label class="layui-form-label" style="width: 70px;">链接地址</label>',
  2286. '<div class="layui-input-block">',
  2287. '<input name="url" value="' + (options.href || '') + '" autofocus="true" autocomplete="off" class="layui-input">',
  2288. '</div>',
  2289. '</li>',
  2290. '<li class="layui-form-item">',
  2291. '<label class="layui-form-label" style="width: 70px;">链接文本</label>',
  2292. '<div class="layui-input-block">',
  2293. '<input name="text" value="' +
  2294. (options.text || '') +
  2295. '" autofocus="true" autocomplete="off" class="layui-input" ' +
  2296. (options.text !== '' ? 'readonly="readonly"' : '') +
  2297. '>',
  2298. '</div>',
  2299. '</li>',
  2300. '<li class="layui-form-item ' + (dMode ? '' : 'layui-hide') + '">',
  2301. '<label class="layui-form-label" style="width: 70px;">打开方式</label>',
  2302. '<div class="layui-input-block">',
  2303. '<input type="radio" name="target" value="_blank" class="layui-input" title="新窗口" ' +
  2304. (options.target === '_blank' ? 'checked' : '') +
  2305. '>',
  2306. '<input type="radio" name="target" value="_self" class="layui-input" title="当前窗口"' +
  2307. (options.target === '_self' || !options.target ? 'checked' : '') +
  2308. '>',
  2309. '</div>',
  2310. '</li>',
  2311. '<li class="layui-form-item ' + (dMode ? '' : 'layui-hide') + '">',
  2312. '<label class="layui-form-label" style="width: 70px;">rel属性</label>',
  2313. '<div class="layui-input-block">',
  2314. '<input type="radio" name="rel" value="" class="layui-input" title="无" ' +
  2315. (options.rel === '' || !options.target ? 'checked' : '') +
  2316. '>',
  2317. '<input type="radio" name="rel" value="nofollow" class="layui-input" title="nofollow"' +
  2318. (options.rel === 'nofollow' ? 'checked' : '') +
  2319. '>',
  2320. '</div>',
  2321. '</li>',
  2322. '<button type="button" lay-submit lay-filter="layedit-link-yes" id="layedit-link-yes" class="layui-btn" style="display: none;"> 确定 </button>',
  2323. '</ul>',
  2324. ].join(''),
  2325. btn: ['确定', '取消'],
  2326. btnAlign: 'c',
  2327. yes: function (index, layero) {
  2328. $('#layedit-link-yes').click()
  2329. },
  2330. btn1: function (index, layero) {
  2331. layer.close(index)
  2332. setTimeout(function () {
  2333. body.focus()
  2334. }, 10)
  2335. },
  2336. success: function (layero, index) {
  2337. var eventFilter = 'submit(layedit-link-yes)'
  2338. form.render('radio')
  2339. form.on(eventFilter, function (data) {
  2340. layer.close(link.index)
  2341. callback && callback(data.field)
  2342. })
  2343. },
  2344. })
  2345. link.index = index
  2346. },
  2347. customlink = function (options, callback) {
  2348. var body = this,
  2349. index = layer.open({
  2350. type: 1,
  2351. id: 'LAY_layedit_customlink',
  2352. area: (function () {
  2353. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 350) {
  2354. return ['90%']
  2355. } else {
  2356. return ['350px']
  2357. }
  2358. })(),
  2359. offset: (function () {
  2360. if (/mobile/i.test(navigator.userAgent)) {
  2361. return 'auto'
  2362. } else {
  2363. return '100px'
  2364. }
  2365. })(),
  2366. shade: 0.05,
  2367. shadeClose: true,
  2368. moveType: 1,
  2369. title: options.title,
  2370. skin: 'layui-layer-msg',
  2371. content: [
  2372. '<ul class="layui-form" style="margin: 15px;">',
  2373. '<li class="layui-form-item">',
  2374. '<label class="layui-form-label" style="width: 60px;">名称</label>',
  2375. '<div class="layui-input-block" style="margin-left: 90px">',
  2376. '<input name="text" value="" autofocus="true" autocomplete="off" class="layui-input">',
  2377. '</div>',
  2378. '</li>',
  2379. '<li class="layui-form-item" style="display:none">',
  2380. '<button type="button" lay-submit lay-filter="layedit-link-yes" id="layedit-link-yes"> 确定 </button>',
  2381. '</li>',
  2382. '</ul>',
  2383. ].join(''),
  2384. btn: ['确定', '取消'],
  2385. btnAlign: 'c',
  2386. yes: function (index, layero) {
  2387. $('#layedit-link-yes').click()
  2388. },
  2389. success: function (layero, index) {
  2390. var eventFilter = 'submit(layedit-link-yes)'
  2391. form.render('radio')
  2392. form.on(eventFilter, function (data) {
  2393. callback && callback(data.field)
  2394. layer.close(customlink.index)
  2395. })
  2396. },
  2397. })
  2398. customlink.index = index
  2399. },
  2400. anchors = function (options, callback) {
  2401. var body = this,
  2402. index = layer.open({
  2403. type: 1,
  2404. id: 'LAY_layedit_addmd',
  2405. area: (function () {
  2406. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 350) {
  2407. return ['90%']
  2408. } else {
  2409. return ['350px']
  2410. }
  2411. })(),
  2412. offset: (function () {
  2413. if (/mobile/i.test(navigator.userAgent)) {
  2414. return 'auto'
  2415. } else {
  2416. return '100px'
  2417. }
  2418. })(),
  2419. shade: 0.05,
  2420. shadeClose: true,
  2421. moveType: 1,
  2422. title: '添加锚点',
  2423. skin: 'layui-layer-msg',
  2424. content: [
  2425. '<ul class="layui-form" style="margin: 15px;">',
  2426. '<li class="layui-form-item">',
  2427. '<label class="layui-form-label" style="width: 60px;">名称</label>',
  2428. '<div class="layui-input-block" style="margin-left: 90px">',
  2429. '<input name="text" value="' + (options.name || '') + '" autofocus="true" autocomplete="off" class="layui-input">',
  2430. '</div>',
  2431. '</li>',
  2432. '<button type="button" lay-submit lay-filter="layedit-link-yes" id="layedit-link-yes" class="layui-btn" style="display: none;"> 确定 </button>',
  2433. '</ul>',
  2434. ].join(''),
  2435. btn: ['确定', '取消'],
  2436. btnAlign: 'c',
  2437. yes: function (index, layero) {
  2438. $('#layedit-link-yes').click()
  2439. },
  2440. success: function (layero, index) {
  2441. var eventFilter = 'submit(layedit-link-yes)'
  2442. form.render('radio')
  2443. form.on(eventFilter, function (data) {
  2444. layer.close(anchors.index)
  2445. callback && callback(data.field)
  2446. })
  2447. },
  2448. })
  2449. anchors.index = index
  2450. },
  2451. table = function (options, callback) {
  2452. table.hide =
  2453. table.hide ||
  2454. function (e) {
  2455. if ($(e.target).attr('layedit-event') !== 'table') {
  2456. layer.close(table.index)
  2457. }
  2458. }
  2459. if (!/mobile/i.test(navigator.userAgent)) {
  2460. table.index = layer.tips(
  2461. (function () {
  2462. return (
  2463. '<div style="padding: 5px;border: 1px solid #e6e6e6;"><span id="laytable_label" class="layui-label">0列 x 0行</span>' +
  2464. '<table class="layui-table" lay-size="sm">' +
  2465. '<tbody>' +
  2466. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2467. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2468. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2469. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2470. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2471. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2472. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2473. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2474. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2475. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2476. '</tbody>' +
  2477. '</table></div>'
  2478. )
  2479. })(),
  2480. this,
  2481. {
  2482. tips: 1,
  2483. time: 0,
  2484. skin: 'layui-box layui-util-face',
  2485. maxWidth: 500,
  2486. success: function (layero, index) {
  2487. layero.find('td').on('mouseover', function () {
  2488. layero.find('#laytable_label')[0].innerText = this.cellIndex + 1 + '列X' + (this.parentElement.rowIndex + 1) + '行'
  2489. layero.find('td').removeAttr('style')
  2490. $(this).attr('style', 'background-color:linen;')
  2491. $(this).prevAll().attr('style', 'background-color:linen;')
  2492. for (var i = 0; i < $(this.parentElement).prevAll().length; i++) {
  2493. for (var j = 0; j < $(this.parentElement).prevAll()[i].childNodes.length; j++) {
  2494. if (j <= this.cellIndex) {
  2495. $(this.parentElement).prevAll()[i].children[j].style = 'background-color:linen;'
  2496. }
  2497. }
  2498. }
  2499. })
  2500. layero.find('td').on('click', function () {
  2501. callback &&
  2502. callback({
  2503. cells: this.cellIndex + 1,
  2504. rows: this.parentElement.rowIndex,
  2505. })
  2506. layer.close(index)
  2507. })
  2508. $(document).off('click', table.hide).on('click', table.hide)
  2509. },
  2510. }
  2511. )
  2512. } else {
  2513. table.index = layer.open({
  2514. type: 1,
  2515. title: false,
  2516. closeBtn: 0,
  2517. shade: 0.05,
  2518. shadeClose: true,
  2519. content: (function () {
  2520. return (
  2521. '<div style="padding: 5px;border: 1px solid #e6e6e6;"><span id="laytable_label" class="layui-label">0列 x 0行</span>' +
  2522. '<table class="layui-table" lay-size="sm">' +
  2523. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2524. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2525. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2526. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2527. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2528. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2529. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2530. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2531. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2532. '<tr style="height: 20px;"><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>' +
  2533. '</table></div>'
  2534. )
  2535. })(),
  2536. area: ['85%'],
  2537. skin: 'layui-box layui-util-face',
  2538. success: function (layero, index) {
  2539. layero.find('td').on('touchmove', function (e) {
  2540. var realTarget = getTouchElement(e)
  2541. if (realTarget != null && realTarget.tagName.toUpperCase() === 'TD') {
  2542. layero.find('#laytable_label')[0].innerText = realTarget.cellIndex + 1 + '列X' + (realTarget.parentElement.rowIndex + 1) + '行'
  2543. layero.find('td').removeAttr('style')
  2544. $(realTarget).attr('style', 'background-color:linen;')
  2545. $(realTarget).prevAll().attr('style', 'background-color:linen;')
  2546. for (var i = 0; i < $(realTarget.parentElement).prevAll().length; i++) {
  2547. for (var j = 0; j < $(realTarget.parentElement).prevAll()[i].childNodes.length; j++) {
  2548. if (j <= realTarget.cellIndex) {
  2549. $(realTarget.parentElement).prevAll()[i].children[j].style = 'background-color:linen;'
  2550. }
  2551. }
  2552. }
  2553. }
  2554. })
  2555. layero.find('td').on('touchend', function (e) {
  2556. var realTarget = getTouchElement(e)
  2557. if (realTarget != null && realTarget.tagName.toUpperCase() === 'TD') {
  2558. callback &&
  2559. callback({
  2560. cells: realTarget.cellIndex + 1,
  2561. rows: realTarget.parentElement.rowIndex,
  2562. })
  2563. layer.close(index)
  2564. }
  2565. })
  2566. },
  2567. })
  2568. }
  2569. return table.index
  2570. },
  2571. //表情面板
  2572. face = function (options, callback) {
  2573. //表情库
  2574. var faces = (function () {
  2575. var alt = [
  2576. '[微笑]',
  2577. '[嘻嘻]',
  2578. '[哈哈]',
  2579. '[可爱]',
  2580. '[可怜]',
  2581. '[挖鼻]',
  2582. '[吃惊]',
  2583. '[害羞]',
  2584. '[挤眼]',
  2585. '[闭嘴]',
  2586. '[鄙视]',
  2587. '[爱你]',
  2588. '[泪]',
  2589. '[偷笑]',
  2590. '[亲亲]',
  2591. '[生病]',
  2592. '[太开心]',
  2593. '[白眼]',
  2594. '[右哼哼]',
  2595. '[左哼哼]',
  2596. '[嘘]',
  2597. '[衰]',
  2598. '[委屈]',
  2599. '[吐]',
  2600. '[哈欠]',
  2601. '[抱抱]',
  2602. '[怒]',
  2603. '[疑问]',
  2604. '[馋嘴]',
  2605. '[拜拜]',
  2606. '[思考]',
  2607. '[汗]',
  2608. '[困]',
  2609. '[睡]',
  2610. '[钱]',
  2611. '[失望]',
  2612. '[酷]',
  2613. '[色]',
  2614. '[哼]',
  2615. '[鼓掌]',
  2616. '[晕]',
  2617. '[悲伤]',
  2618. '[抓狂]',
  2619. '[黑线]',
  2620. '[阴险]',
  2621. '[怒骂]',
  2622. '[互粉]',
  2623. '[心]',
  2624. '[伤心]',
  2625. '[猪头]',
  2626. '[熊猫]',
  2627. '[兔子]',
  2628. '[ok]',
  2629. '[耶]',
  2630. '[good]',
  2631. '[NO]',
  2632. '[赞]',
  2633. '[来]',
  2634. '[弱]',
  2635. '[草泥马]',
  2636. '[神马]',
  2637. '[囧]',
  2638. '[浮云]',
  2639. '[给力]',
  2640. '[围观]',
  2641. '[威武]',
  2642. '[奥特曼]',
  2643. '[礼物]',
  2644. '[钟]',
  2645. '[话筒]',
  2646. '[蜡烛]',
  2647. '[蛋糕]',
  2648. ],
  2649. arr = {}
  2650. layui.each(alt, function (index, item) {
  2651. arr[item] = options.facePath + 'images/face/' + index + '.gif'
  2652. })
  2653. return arr
  2654. })()
  2655. face.hide =
  2656. face.hide ||
  2657. function (e) {
  2658. if ($(e.target).attr('layedit-event') !== 'face') {
  2659. layer.close(face.index)
  2660. }
  2661. }
  2662. if (!/mobile/i.test(navigator.userAgent)) {
  2663. face.index = layer.tips(
  2664. (function () {
  2665. var content = []
  2666. layui.each(faces, function (key, item) {
  2667. content.push('<li title="' + key + '"><img src="' + item + '" alt="' + key + '"/></li>')
  2668. })
  2669. return '<ul class="layui-clear" style="width: 279px;">' + content.join('') + '</ul>'
  2670. })(),
  2671. this,
  2672. {
  2673. tips: 1,
  2674. time: 0,
  2675. skin: 'layui-box layui-util-face',
  2676. maxWidth: 500,
  2677. success: function (layero, index) {
  2678. layero
  2679. .css({
  2680. marginTop: -4,
  2681. marginLeft: -10,
  2682. })
  2683. .find('.layui-clear>li')
  2684. .on('click', function () {
  2685. callback &&
  2686. callback({
  2687. src: faces[this.title],
  2688. alt: this.title,
  2689. })
  2690. layer.close(index)
  2691. })
  2692. $(document).off('click', face.hide).on('click', face.hide)
  2693. },
  2694. }
  2695. )
  2696. } else {
  2697. face.index = layer.open({
  2698. type: 1,
  2699. title: false,
  2700. closeBtn: 0,
  2701. shade: 0.05,
  2702. shadeClose: true,
  2703. content: (function () {
  2704. var content = []
  2705. layui.each(faces, function (key, item) {
  2706. content.push('<li title="' + key + '"><img src="' + item + '" alt="' + key + '"/></li>')
  2707. })
  2708. return '<ul class="layui-clear" style="width: 279px;">' + content.join('') + '</ul>'
  2709. })(),
  2710. skin: 'layui-box layui-util-face',
  2711. success: function (layero, index) {
  2712. layero.find('.layui-clear>li').on('click', function () {
  2713. callback &&
  2714. callback({
  2715. src: faces[this.title],
  2716. alt: this.title,
  2717. })
  2718. layer.close(index)
  2719. })
  2720. },
  2721. })
  2722. }
  2723. return face.index
  2724. },
  2725. fontFomatt = function (options, callback) {
  2726. fontFomatt.hide =
  2727. fontFomatt.hide ||
  2728. function (e) {
  2729. if ($(e.target).attr('layedit-event') !== 'fontFomatt' && $(e.target).attr('layedit-event') !== 'fontfamily') {
  2730. layer.close(fontFomatt.index)
  2731. }
  2732. }
  2733. fontFomatt.index = layer.tips(
  2734. (function () {
  2735. var content = []
  2736. layui.each(options.fonts, function (index, item) {
  2737. content.push(
  2738. '<li title="' +
  2739. options.fonts[index] +
  2740. '" style="float: initial;width:100%;"><' +
  2741. options.fonts[index] +
  2742. '>' +
  2743. options.texts[index] +
  2744. '</' +
  2745. options.fonts[index] +
  2746. '></li>'
  2747. )
  2748. })
  2749. return '<ul class="layui-clear" style="width: max-content;width:-moz-max-content;">' + content.join('') + '</ul>'
  2750. })(),
  2751. this,
  2752. {
  2753. tips: 1,
  2754. time: 0,
  2755. skin: 'layui-box layui-util-face',
  2756. success: function (layero, index) {
  2757. layero
  2758. .css({ marginTop: -4, marginLeft: -10 })
  2759. .find('.layui-clear>li')
  2760. .on('click', function () {
  2761. callback && callback(this.title, options.fonts)
  2762. layer.close(index)
  2763. })
  2764. $(document).off('click', fontFomatt.hide).on('click', fontFomatt.hide)
  2765. },
  2766. }
  2767. )
  2768. },
  2769. fontfamily = function (options, callback) {
  2770. fontfamily.hide =
  2771. fontfamily.hide ||
  2772. function (e) {
  2773. if ($(e.target).attr('layedit-event') != 'fontfamily') {
  2774. layer.close(fontfamily.index)
  2775. }
  2776. }
  2777. fontfamily.index = layer.tips(
  2778. (function () {
  2779. var content = []
  2780. layui.each(options.fonts, function (index, item) {
  2781. content.push(
  2782. '<li title="' +
  2783. options.fonts[index] +
  2784. '" style="float: initial;width:100%;' +
  2785. options.fonts[index] +
  2786. '"><' +
  2787. options.fonts[index] +
  2788. '>' +
  2789. options.texts[index] +
  2790. '</' +
  2791. options.fonts[index] +
  2792. '></li>'
  2793. )
  2794. })
  2795. return '<ul class="layui-clear" style="width: max-content;width:-moz-max-content;">' + content.join('') + '</ul>'
  2796. })(),
  2797. this,
  2798. {
  2799. tips: 1,
  2800. time: 0,
  2801. skin: 'layui-box layui-util-face',
  2802. success: function (layero, index) {
  2803. layero
  2804. .css({ marginTop: -4, marginLeft: -10 })
  2805. .find('.layui-clear>li')
  2806. .on('click', function () {
  2807. callback && callback(this.title, options.fonts)
  2808. layer.close(index)
  2809. })
  2810. $(document).off('click', fontfamily.hide).on('click', fontfamily.hide)
  2811. },
  2812. }
  2813. )
  2814. },
  2815. // 字体大小 显示操作
  2816. fontSize = function (options, callback) {
  2817. fontSize.hide =
  2818. fontSize.hide ||
  2819. function (e) {
  2820. if ($(e.target).attr('layedit-event') !== 'fontSize') {
  2821. layer.close(fontSize.index)
  2822. }
  2823. }
  2824. if (!options.last_value) {
  2825. options.last_value = 2
  2826. }
  2827. fontSize.index = layer.tips(
  2828. (function () {
  2829. var content = []
  2830. layui.each(options.fonts, function (index, item) {
  2831. var iHtml = ''
  2832. if (options.last_value == options.fonts[index]) {
  2833. iHtml = '&nbsp;&nbsp;<i class="layui-icon">&#xe605;</i>'
  2834. }
  2835. content.push(
  2836. '<li title="' +
  2837. options.fonts[index] +
  2838. '">' +
  2839. options.fonts[index] +
  2840. ':' +
  2841. options.texts[index] +
  2842. iHtml +
  2843. '</' +
  2844. options.fonts[index] +
  2845. '></li>'
  2846. )
  2847. })
  2848. return '<ul class="layui-clear" style="width: max-content;">' + content.join('') + '</ul>'
  2849. })(),
  2850. this,
  2851. {
  2852. tips: 1,
  2853. time: 0,
  2854. skin: 'layui-box layui-util-font',
  2855. success: function (layero, index) {
  2856. layero
  2857. .css({ marginTop: -4, marginLeft: -10 })
  2858. .find('.layui-clear>li')
  2859. .on('click', function () {
  2860. callback && callback(this.title, options.fonts, options.texts)
  2861. layer.close(index)
  2862. })
  2863. $(document).off('click', fontSize.hide).on('click', fontSize.hide)
  2864. },
  2865. }
  2866. )
  2867. },
  2868. // 间距
  2869. lineHeight = function (options, callback) {
  2870. lineHeight.hide =
  2871. lineHeight.hide ||
  2872. function (e) {
  2873. if ($(e.target).attr('layedit-event') !== 'lineHeight') {
  2874. layer.close(lineHeight.index)
  2875. }
  2876. }
  2877. if (!options.last_value) {
  2878. options.last_value = 1
  2879. }
  2880. lineHeight.index = layer.tips(
  2881. (function () {
  2882. var content = []
  2883. layui.each(options.fonts, function (index, item) {
  2884. var iHtml = ''
  2885. if (options.last_value == options.fonts[index]) {
  2886. iHtml = '&nbsp;&nbsp;&nbsp;&nbsp;<i class="layui-icon">&#xe605;</i>'
  2887. }
  2888. content.push('<li title="' + options.fonts[index] + '">' + options.texts[index] + iHtml + '</' + options.fonts[index] + '></li>')
  2889. })
  2890. return '<ul class="layui-clear" style="width: max-content;">' + content.join('') + '</ul>'
  2891. })(),
  2892. this,
  2893. {
  2894. tips: 1,
  2895. time: 0,
  2896. skin: 'layui-box layui-util-font',
  2897. success: function (layero, index) {
  2898. layero
  2899. .css({ marginTop: -4, marginLeft: -10 })
  2900. .find('.layui-clear>li')
  2901. .on('click', function () {
  2902. callback && callback(this.title, options.fonts)
  2903. layer.close(index)
  2904. })
  2905. $(document).off('click', lineHeight.hide).on('click', lineHeight.hide)
  2906. },
  2907. }
  2908. )
  2909. },
  2910. //插入代码面板
  2911. code = function (options, callback) {
  2912. var objSel = [
  2913. '<li class="layui-form-item objSel">',
  2914. '<label class="layui-form-label">请选择语言</label>',
  2915. '<style>#selectCodeLanguage ~ .layui-form-select > dl {max-height: 192px} </style>',
  2916. '<div class="layui-input-block">',
  2917. '<select name="lang" id="selectCodeLanguage">',
  2918. '<option value="JavaScript">JavaScript</option>',
  2919. '<option value="HTML">HTML</option>',
  2920. '<option value="CSS">CSS</option>',
  2921. '<option value="Java">Java</option>',
  2922. '<option value="PHP">PHP</option>',
  2923. '<option value="C#">C#</option>',
  2924. '<option value="Python">Python</option>',
  2925. '<option value="Ruby">Ruby</option>',
  2926. '<option value="Go">Go</option>',
  2927. '</select>',
  2928. '</div>',
  2929. '</li>',
  2930. ].join('')
  2931. if (options.hide) {
  2932. objSel = [
  2933. '<li class="layui-form-item" style="display:none">',
  2934. '<label class="layui-form-label">请选择语言</label>',
  2935. '<div class="layui-input-block">',
  2936. '<select name="lang">',
  2937. '<option value="' + options.default + '" selected="selected">',
  2938. options.default,
  2939. '</option>',
  2940. '</select>',
  2941. '</div>',
  2942. '</li>',
  2943. ].join('')
  2944. }
  2945. var body = this,
  2946. index = layer.open({
  2947. type: 1,
  2948. id: 'LAY_layedit_code',
  2949. area: (function () {
  2950. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 650) {
  2951. return ['90%']
  2952. } else {
  2953. return ['650px']
  2954. }
  2955. })(),
  2956. offset: (function () {
  2957. if (/mobile/i.test(navigator.userAgent)) {
  2958. return 'auto'
  2959. } else {
  2960. return '100px'
  2961. }
  2962. })(),
  2963. shade: 0.05,
  2964. shadeClose: true,
  2965. moveType: 1,
  2966. title: '插入代码',
  2967. skin: 'layui-layer-msg',
  2968. content: [
  2969. '<ul class="layui-form layui-form-pane" style="margin: 15px;">',
  2970. objSel,
  2971. '<li class="layui-form-item layui-form-text">',
  2972. '<label class="layui-form-label">代码</label>',
  2973. '<div class="layui-input-block">',
  2974. '<textarea name="code" lay-verify="required" autofocus="true" class="layui-textarea" style="height: 200px;"></textarea>',
  2975. '</div>',
  2976. '</li>',
  2977. '<button type="button" id="layedit-code-yes" lay-submit lay-filter="layedit-code-yes" class="layui-btn" style="display: none"> 确定 </button>',
  2978. '</ul>',
  2979. ].join(''),
  2980. btn: ['确定', '取消'],
  2981. btnAlign: 'c',
  2982. yes: function (index, layero) {
  2983. $('#layedit-code-yes').click()
  2984. },
  2985. btn1: function (index, layero) {
  2986. layer.close(index)
  2987. body.focus()
  2988. },
  2989. success: function (layero, index) {
  2990. var eventFilter = 'submit(layedit-code-yes)'
  2991. form.render('select')
  2992. form.on(eventFilter, function (data) {
  2993. layer.close(code.index)
  2994. callback && callback(data.field, options.hide, options.default)
  2995. })
  2996. },
  2997. })
  2998. code.index = index
  2999. },
  3000. //全部工具
  3001. tools = {
  3002. html: '<i class="layui-icon layedit-tool-html" title="HTML源代码" layedit-event="html"">&#xe64b;</i>',
  3003. undo: '<i class="layui-icon layedit-tool-undo" title="撤销" lay-command="undo" layedit-event="undo"">&#xe603;</i>',
  3004. redo: '<i class="layui-icon layedit-tool-redo" title="重做" lay-command="redo" layedit-event="redo"">&#xe602;</i>',
  3005. strong: '<i class="layui-icon layedit-tool-b" title="加粗" lay-command="Bold" layedit-event="b"">&#xe62b;</i>',
  3006. italic: '<i class="layui-icon layedit-tool-i" title="斜体" lay-command="italic" layedit-event="i"">&#xe644;</i>',
  3007. underline: '<i class="layui-icon layedit-tool-u" title="下划线" lay-command="underline" layedit-event="u"">&#xe646;</i>',
  3008. del: '<i class="layui-icon layedit-tool-d" title="删除线" lay-command="strikeThrough" layedit-event="d"">&#xe64f;</i>',
  3009. "|": '<span class="layedit-tool-mid"></span>',
  3010. left: '<i class="layui-icon layedit-tool-left" title="左对齐" lay-command="justifyLeft" layedit-event="left"">&#xe649;</i>',
  3011. center: '<i class="layui-icon layedit-tool-center" title="居中对齐" lay-command="justifyCenter" layedit-event="center"">&#xe647;</i>',
  3012. right: '<i class="layui-icon layedit-tool-right" title="右对齐" lay-command="justifyRight" layedit-event="right"">&#xe648;</i>',
  3013. link: '<i class="layui-icon layedit-tool-link" title="插入链接" layedit-event="link"">&#xe64c;</i>',
  3014. unlink: '<i class="layui-icon layedit-tool-unlink layui-disabled" title="清除链接" lay-command="unlink" layedit-event="unlink"" style="font-size:18px">&#xe64d;</i>',
  3015. face: '<i class="layui-icon layedit-tool-face" title="表情" layedit-event="face"" style="font-size:18px">&#xe650;</i>',
  3016. image: '<i class="layui-icon layedit-tool-image" title="图片" layedit-event="image" style="font-size:18px">&#xe64a;</i>',
  3017. code: '<i class="layui-icon layedit-tool-code" title="插入代码" layedit-event="code" style="font-size:18px">&#xe64e;</i>',
  3018. images: '<i class="layui-icon layedit-tool-images" title="多图上传" layedit-event="images" style="font-size:18px">&#xe634;</i>',
  3019. image_alt: '<i class="layui-icon layedit-tool-image_alt" title="图片" layedit-event="image_alt" style="font-size:18px">&#xe64a;</i>',
  3020. video: '<i class="layui-icon layedit-tool-video" title="插入视频" layedit-event="video" style="font-size:18px">&#xe6ed;</i>',
  3021. fullScreen: '<i class="layui-icon layedit-tool-fullScreen" title="全屏" layedit-event="fullScreen"style="font-size:18px">&#xe638;</i>',
  3022. colorpicker: '<i class="layui-icon" title="字体颜色选择" id="layFontColor_Index">&#xe66a;</i>',
  3023. fontBackColor: '<i class="layui-icon" title="字体背景色选择" id="layBkColor_Index"></i>',
  3024. fontFomatt: '<i class="layui-icon layedit-tool-fontFomatt" title="段落格式" layedit-event="fontFomatt" style="font-size:18px">P</i>',
  3025. fontfamily: '<i class="layui-icon layedit-tool-fontfamily" title="字体" layedit-event="fontfamily" style="font-size:16px">字体</i>',
  3026. fontSize: '<i class="layui-icon layedit-tool-fontSize" title="字体大小" layedit-event="fontSize" style="font-size:16px">字号</i>',
  3027. lineHeight: '<i class="layui-icon layedit-tool-lineHeight" style="font-size:16px;" title="行高" layedit-event="lineHeight"">行高</i>',
  3028. addhr: '<i class="layui-icon layui-icon-chart layedit-tool-addhr" title="添加水平线" layedit-event="addhr" style="font-size:18px"></i>',
  3029. anchors: '<i class="layui-icon layedit-tool-anchors" title="添加锚点" layedit-event="anchors" style="font-size:18px">&#xe60b;</i>',
  3030. customlink: '<i class="layui-icon layedit-tool-customlink" title="添加自定义链接" layedit-event="customlink" style="font-size:18px">&#xe606;</i>',
  3031. table: '<i class="layui-icon layedit-tool-table" title="插入表格" layedit-event="table" style="font-size:18px">&#xe62d;</i>',
  3032. attachment: '<i class="layui-icon layedit-tool-attachment" title="插入附件" layedit-event="attachment" style="font-size:18px">&#xe62f;</i>',
  3033. preview: '<i class="layui-icon layedit-tool-preview" title="预览" layedit-event="preview" style="font-size:18px">&#xe615;</i>',
  3034. removeformat: '<i class="layui-icon layedit-tool-removeformat" title="清除文字样式" layedit-event="removeformat" style="font-size:18px">&#xe639;</i>',
  3035. help: '<i class="layui-icon layedit-tool-help" title="帮助" layedit-event="help">&#xe607;</i>'
  3036. },
  3037. // 打开图片编辑框
  3038. imageEditor = function (options) {
  3039. var context = options.context || {},
  3040. successCallback = options.success,
  3041. beforeUploadCallback = options.beforeUpload,
  3042. initialData = (context.initialData = options.data),
  3043. formId = (context.formId = 'image-upload-' + parseInt(Math.random() * 1000000)),
  3044. formatWidthHeight = function (val) {
  3045. var isNum = val.toString().indexOf('%') == -1
  3046. return {
  3047. value: isNum ? parseInt(val) : val,
  3048. string: isNum ? parseInt(val) + 'px' : val,
  3049. }
  3050. },
  3051. getImageData = (context.getImageData = function () {
  3052. var imageData =
  3053. layui.form.val(formId) ||
  3054. (function () {
  3055. //老版本layui.form.val无法取值
  3056. var itemForm = $('[lay-filter="' + formId + '"]').eq(0),
  3057. field = {}
  3058. layui.each(itemForm.find('input,select,textarea'), function (_, item) {
  3059. field[item.name] = item.value
  3060. })
  3061. return field
  3062. })()
  3063. imageData.style = ''
  3064. if (imageData.width) {
  3065. imageData.width = formatWidthHeight(imageData.width).string
  3066. imageData.style += 'width:' + imageData.width + ';'
  3067. }
  3068. if (imageData.height) {
  3069. imageData.height = formatWidthHeight(imageData.height).string
  3070. imageData.style += 'height:' + imageData.height + ';'
  3071. }
  3072. context.logger && context.logger('getImageData', imageData)
  3073. return imageData
  3074. }),
  3075. setImageData = (context.setImageData = function (imageData) {
  3076. imageData = imageData || {}
  3077. if (!!imageData.width) {
  3078. imageData.width = formatWidthHeight(imageData.width).value
  3079. }
  3080. if (!!imageData.height) {
  3081. imageData.height = formatWidthHeight(imageData.height).value
  3082. }
  3083. form.val(formId, imageData)
  3084. //如果没有指定图片尺寸,尝试获取
  3085. if (imageData.src && !imageData.isInitialData && !imageData.loaded && !imageData.width && !imageData.height) {
  3086. var image = new Image()
  3087. image.src = imageData.src
  3088. image.onload = function () {
  3089. imageData.loaded = true
  3090. imageData.width = image.naturalWidth.toString()
  3091. imageData.height = image.naturalHeight.toString()
  3092. setImageData(imageData)
  3093. }
  3094. }
  3095. }),
  3096. checkImageSrc = (context.checkImageSrc = function (imageData) {
  3097. if (!imageData.src) {
  3098. layer.msg('请先上传图片', { icon: 2, shade: 0.3, time: 1000 })
  3099. }
  3100. return !!imageData.src
  3101. }),
  3102. imagePreview = (context.imagePreview = function (imageData, title, callback) {
  3103. var image = new Image(),
  3104. maxWidth = /mobile/i.test(navigator.userAgent) ? 300 : 640,
  3105. maxHeight = /mobile/i.test(navigator.userAgent) ? 600 : 480
  3106. image.src = imageData.src
  3107. image.onload = function () {
  3108. //获取图片实际尺寸,并根据图片原始尺寸调整预览框大小
  3109. var width = image.naturalWidth,
  3110. height = image.naturalHeight
  3111. if (width > maxWidth) {
  3112. height = (height * maxWidth) / width
  3113. width = maxWidth
  3114. }
  3115. if (height > maxHeight) {
  3116. width = (width * maxHeight) / height
  3117. height = maxHeight
  3118. }
  3119. layer.open({
  3120. type: 1,
  3121. anim: 2,
  3122. icon: 5,
  3123. title: title || null,
  3124. offset: '100px',
  3125. area: [width + 20 + 'px', height + 77 + 'px'],
  3126. content: [
  3127. '<div style="text-align:center;padding:10px;">',
  3128. ' <img src="' + imageData.src + '" style="max-width:640px;max-height:480px"/>',
  3129. '</div>',
  3130. ].join(''),
  3131. btn: ['确定', '取消'],
  3132. btnAlign: 'c',
  3133. yes: function (index) {
  3134. callback && callback(imageData)
  3135. layer.close(index)
  3136. },
  3137. btn2: function (index) {
  3138. layer.close(index)
  3139. },
  3140. })
  3141. }
  3142. }),
  3143. deleteImage = (context.deleteImage = function (uploadImage, initialImage) {
  3144. uploadImage = uploadImage || getImageData()
  3145. initialImage = initialImage || initialData
  3146. if (!uploadImage.src) {
  3147. //图片不存在
  3148. } else if (
  3149. !!initialData &&
  3150. (uploadImage.src.substring(0 - initialImage.src.length) == initialImage.src ||
  3151. initialImage.src.substring(0 - uploadImage.src.length) == uploadImage.src)
  3152. ) {
  3153. //编辑图片时,图片没有做任何修改,不删除
  3154. } else {
  3155. var callDel = context.set.calldel
  3156. $.post(callDel.url, { imgpath: uploadImage.src }, function (res) {
  3157. callDel.done(res)
  3158. })
  3159. }
  3160. }),
  3161. openOptions = {
  3162. type: 1,
  3163. id: 'fly-jie-image-upload',
  3164. title: null,
  3165. shade: 0.05,
  3166. shadeClose: true,
  3167. area: (function () {
  3168. if (/mobile/i.test(navigator.userAgent) || $(window).width() <= 485) {
  3169. return ['90%']
  3170. } else {
  3171. return ['485px']
  3172. }
  3173. })(),
  3174. offset: (function () {
  3175. if (/mobile/i.test(navigator.userAgent)) {
  3176. return 'auto'
  3177. } else {
  3178. return '100px'
  3179. }
  3180. })(),
  3181. skin: 'layui-layer-border',
  3182. content: [
  3183. '<div style="padding:20px">',
  3184. '<form class="layui-form layui-form-pane" lay-filter="' + formId + '">',
  3185. ' <div class="layui-form-item">',
  3186. ' <div class="layui-inline">',
  3187. ' <label class="layui-form-label">图片路径</label>',
  3188. ' <div class="layui-input-inline" style="width:136px;">',
  3189. ' <input type="text" name="src" placeholder="请点击上传图片" class="layui-input" readonly>',
  3190. ' </div>',
  3191. ' </div>',
  3192. ' <div class="layui-inline" style="overflow:hidden;margin-left:-24px;margin-top:-1px;margin-right:0;">',
  3193. ' <div class="layui-btn-group">',
  3194. ' <button type="button" class="layui-btn" id="upload-' +
  3195. formId +
  3196. '"><i class="layui-icon layui-icon-upload"></i>上传图片</button>',
  3197. ' <button type="button" class="layui-btn layui-btn-danger" id="preview-' +
  3198. formId +
  3199. '"><i class="layui-icon layui-icon-picture"></i>预览</button>',
  3200. ' </div>',
  3201. ' </div>',
  3202. ' </div>',
  3203. ' <div class="layui-form-item">',
  3204. ' <div class="layui-inline">',
  3205. ' <label class="layui-form-label">图片宽度</label>',
  3206. ' <div class="layui-input-inline" style="width:95px;">',
  3207. ' <input type="text" required name="width" placeholder="图片宽度" value="" class="layui-input">',
  3208. ' </div>',
  3209. ' </div>',
  3210. ' <div class="layui-inline">',
  3211. ' <label class="layui-form-label">图片高度</label>',
  3212. ' <div class="layui-input-inline" style="width:95px;margin-right:0;">',
  3213. ' <input type="text" required name="height" placeholder="图片高度" value="" class="layui-input">',
  3214. ' </div>',
  3215. ' </div>',
  3216. ' </div>',
  3217. ' <div class="layui-form-item">',
  3218. ' <label class="layui-form-label">图片描述</label>',
  3219. ' <div class="layui-input-block" style="margin-right:10px;">',
  3220. ' <input type="text" required name="alt" placeholder="请输入图片描述,可为空" value="" class="layui-input">',
  3221. ' </div>',
  3222. ' </div>',
  3223. '</form></div>',
  3224. ].join(''),
  3225. btn: ['确定', '取消'],
  3226. yes: function (index, layero) {
  3227. var imageData = getImageData()
  3228. if (checkImageSrc(imageData)) {
  3229. successCallback(imageData, context)
  3230. layer.close(index)
  3231. }
  3232. },
  3233. btn2: function (index) {
  3234. deleteImage()
  3235. layer.close(index)
  3236. },
  3237. success: function (layero, index) {
  3238. //初始化赋值
  3239. initialData && setImageData(initialData)
  3240. //预览
  3241. $('#preview-' + formId).click(function () {
  3242. var imageData = getImageData()
  3243. checkImageSrc(imageData) && imagePreview(imageData)
  3244. })
  3245. //上传
  3246. layui.use('upload', function (upload) {
  3247. var upload = layui.upload,
  3248. loding,
  3249. uploadImage = context.set.uploadImage || {}
  3250. if (!uploadImage.url) {
  3251. layer.msg('上传接口配置错误!')
  3252. }
  3253. //执行实例
  3254. upload.render({
  3255. elem: '#upload-' + formId,
  3256. url: uploadImage.url,
  3257. method: uploadImage.method,
  3258. data: uploadImage.data,
  3259. headers: uploadImage.headers,
  3260. accept: uploadImage.accept || 'image',
  3261. acceptMime: uploadImage.acceptMime || 'image/*',
  3262. exts: uploadImage.exts || 'jpg|png|gif|bmp|jpeg',
  3263. size: uploadImage.size || 1024 * 10,
  3264. field: uploadImage.field,
  3265. before: function (obj) {
  3266. beforeUploadCallback && beforeUploadCallback(getImageData(), context)
  3267. loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 })
  3268. },
  3269. done: function (res) {
  3270. layer.close(loding)
  3271. res.data = res.data || {}
  3272. if (res.code == 0) {
  3273. setImageData(res.data)
  3274. } else if (res.code == 2) {
  3275. imagePreview(res.data, '确定使用该文件吗?', function (imageData) {
  3276. setImageData(imageData)
  3277. })
  3278. } else {
  3279. layer.msg(res.msg || '上传失败')
  3280. }
  3281. },
  3282. })
  3283. })
  3284. },
  3285. }
  3286. //如果是编辑模式,增加初始数据标识
  3287. if (!!initialData) {
  3288. initialData.isInitialData = true
  3289. }
  3290. //通过beforeOpen调整layer.open选项
  3291. options.beforeOpen && options.beforeOpen(openOptions, context)
  3292. //开启编辑器
  3293. layer.open(openOptions)
  3294. },
  3295. edit = new Edit()
  3296. form.render()
  3297. exports(MOD_NAME, edit)
  3298. })
  3299. //Custom Theme Add
  3300. function AddCustomThemes(list, contents, pimgs) {
  3301. var content = []
  3302. layui.each(list, function (index, item) {
  3303. content.push('<option value="' + contents[index] + '" data-img="' + pimgs[index] + '">' + item + '</option>')
  3304. })
  3305. return [
  3306. '<li class="layui-form-item" style="position: relative">',
  3307. '<label class="layui-form-label">主题选择</label>',
  3308. '<div class="layui-input-block">',
  3309. '<select name="theme" style="display:block;height:38px;width:100%;">' + content.join('') + '</select>',
  3310. '</div>',
  3311. '</li>',
  3312. ].join('')
  3313. }
  3314. // 找出当前选中范围的节点
  3315. function getRangeNodes(range) {
  3316. var cls = range.commonAncestorContainer.nodeName == 'BODY' ? range.commonAncestorContainer.children : [range.commonAncestorContainer.parentElement]
  3317. var list = []
  3318. var bool = false
  3319. for (var i = 0; i < cls.length; i++) {
  3320. var start = range.startContainer.parentElement
  3321. if (start.nodeName == 'FONT') {
  3322. start = start.parentElement
  3323. }
  3324. var end = range.endContainer.parentElement
  3325. if (end.nodeName == 'FONT') {
  3326. end = end.parentElement
  3327. }
  3328. if (!bool && cls[i] == start) {
  3329. bool = true
  3330. } else if (bool && cls[i] == end) {
  3331. list.push(cls[i])
  3332. break
  3333. }
  3334. if (bool) {
  3335. list.push(cls[i])
  3336. }
  3337. }
  3338. return list
  3339. }
  3340. //HTML 格式化
  3341. function style_html(html_source, indent_size, indent_character, max_char) {
  3342. var Parser, multi_parser
  3343. function Parser() {
  3344. this.pos = 0
  3345. this.token = ''
  3346. this.current_mode = 'CONTENT'
  3347. this.tags = {
  3348. parent: 'parent1',
  3349. parentcount: 1,
  3350. parent1: '',
  3351. }
  3352. this.tag_type = ''
  3353. this.token_text = this.last_token = this.last_text = this.token_type = ''
  3354. this.Utils = {
  3355. whitespace: '\n\r\t '.split(''),
  3356. single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed'.split(','),
  3357. extra_liners: 'head,body,/html'.split(','),
  3358. in_array: function (what, arr) {
  3359. for (var i = 0; i < arr.length; i++) {
  3360. if (what === arr[i]) {
  3361. return true
  3362. }
  3363. }
  3364. return false
  3365. },
  3366. }
  3367. this.get_content = function () {
  3368. var char = ''
  3369. var content = []
  3370. var space = false
  3371. while (this.input.charAt(this.pos) !== '<') {
  3372. if (this.pos >= this.input.length) {
  3373. return content.length ? content.join('') : ['', 'TK_EOF']
  3374. }
  3375. char = this.input.charAt(this.pos)
  3376. this.pos++
  3377. this.line_char_count++
  3378. if (this.Utils.in_array(char, this.Utils.whitespace)) {
  3379. if (content.length) {
  3380. space = true
  3381. }
  3382. this.line_char_count--
  3383. continue
  3384. } else if (space) {
  3385. if (this.line_char_count >= this.max_char) {
  3386. content.push('\n')
  3387. for (var i = 0; i < this.indent_level; i++) {
  3388. content.push(this.indent_string)
  3389. }
  3390. this.line_char_count = 0
  3391. } else {
  3392. content.push(' ')
  3393. this.line_char_count++
  3394. }
  3395. space = false
  3396. }
  3397. content.push(char)
  3398. }
  3399. return content.length ? content.join('') : ''
  3400. }
  3401. this.get_script = function () {
  3402. var char = ''
  3403. var content = []
  3404. var reg_match = new RegExp('</script>', 'igm') //使用RegExp,无需转义
  3405. reg_match.lastIndex = this.pos
  3406. var reg_array = reg_match.exec(this.input)
  3407. var end_script = reg_array ? reg_array.index : this.input.length
  3408. while (this.pos < end_script) {
  3409. if (this.pos >= this.input.length) {
  3410. return content.length ? content.join('') : ['', 'TK_EOF']
  3411. }
  3412. char = this.input.charAt(this.pos)
  3413. this.pos++
  3414. content.push(char)
  3415. }
  3416. return content.length ? content.join('') : ''
  3417. }
  3418. this.record_tag = function (tag) {
  3419. if (this.tags[tag + 'count']) {
  3420. this.tags[tag + 'count']++
  3421. this.tags[tag + this.tags[tag + 'count']] = this.indent_level
  3422. } else {
  3423. this.tags[tag + 'count'] = 1
  3424. this.tags[tag + this.tags[tag + 'count']] = this.indent_level
  3425. }
  3426. this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent
  3427. this.tags.parent = tag + this.tags[tag + 'count']
  3428. }
  3429. this.retrieve_tag = function (tag) {
  3430. if (this.tags[tag + 'count']) {
  3431. var temp_parent = this.tags.parent
  3432. while (temp_parent) {
  3433. if (tag + this.tags[tag + 'count'] === temp_parent) {
  3434. break
  3435. }
  3436. temp_parent = this.tags[temp_parent + 'parent']
  3437. }
  3438. if (temp_parent) {
  3439. this.indent_level = this.tags[tag + this.tags[tag + 'count']]
  3440. this.tags.parent = this.tags[temp_parent + 'parent']
  3441. }
  3442. delete this.tags[tag + this.tags[tag + 'count'] + 'parent']
  3443. delete this.tags[tag + this.tags[tag + 'count']]
  3444. if (this.tags[tag + 'count'] == 1) {
  3445. delete this.tags[tag + 'count']
  3446. } else {
  3447. this.tags[tag + 'count']--
  3448. }
  3449. }
  3450. }
  3451. this.get_tag = function () {
  3452. var char = ''
  3453. var content = []
  3454. var space = false
  3455. do {
  3456. if (this.pos >= this.input.length) {
  3457. return content.length ? content.join('') : ['', 'TK_EOF']
  3458. }
  3459. char = this.input.charAt(this.pos)
  3460. this.pos++
  3461. this.line_char_count++
  3462. if (this.Utils.in_array(char, this.Utils.whitespace)) {
  3463. space = true
  3464. this.line_char_count--
  3465. continue
  3466. }
  3467. if (char === "'" || char === '"') {
  3468. if (!content[1] || content[1] !== '!') {
  3469. char += this.get_unformatted(char)
  3470. space = true
  3471. }
  3472. }
  3473. if (char === '=') {
  3474. space = false
  3475. }
  3476. if (content.length && content[content.length - 1] !== '=' && char !== '>' && space) {
  3477. if (this.line_char_count >= this.max_char) {
  3478. this.print_newline(false, content)
  3479. this.line_char_count = 0
  3480. } else {
  3481. content.push(' ')
  3482. this.line_char_count++
  3483. }
  3484. space = false
  3485. }
  3486. content.push(char)
  3487. } while (char !== '>')
  3488. var tag_complete = content.join('')
  3489. var tag_index
  3490. if (tag_complete.indexOf(' ') !== -1) {
  3491. tag_index = tag_complete.indexOf(' ')
  3492. } else {
  3493. tag_index = tag_complete.indexOf('>')
  3494. }
  3495. var tag_check = tag_complete.substring(1, tag_index).toLowerCase()
  3496. if (tag_complete.charAt(tag_complete.length - 2) === '/' || this.Utils.in_array(tag_check, this.Utils.single_token)) {
  3497. this.tag_type = 'SINGLE'
  3498. } else if (tag_check === 'script') {
  3499. this.record_tag(tag_check)
  3500. this.tag_type = 'SCRIPT'
  3501. } else if (tag_check === 'style') {
  3502. this.record_tag(tag_check)
  3503. this.tag_type = 'STYLE'
  3504. } else if (tag_check.charAt(0) === '!') {
  3505. if (tag_check.indexOf('[if') !== -1) {
  3506. if (tag_complete.indexOf('!IE') != -1) {
  3507. var comment = this.get_unformatted('-->', tag_complete)
  3508. content.push(comment)
  3509. }
  3510. this.tag_type = 'START'
  3511. } else if (tag_check.indexOf('[endif') !== -1) {
  3512. this.tag_type = 'END'
  3513. this.unindent()
  3514. } else if (tag_check.indexOf('[cdata[') != -1) {
  3515. var comment = this.get_unformatted(']]>', tag_complete)
  3516. content.push(comment)
  3517. this.tag_type = 'SINGLE'
  3518. } else {
  3519. var comment = this.get_unformatted('-->', tag_complete)
  3520. content.push(comment)
  3521. this.tag_type = 'SINGLE'
  3522. }
  3523. } else {
  3524. if (tag_check.charAt(0) === '/') {
  3525. this.retrieve_tag(tag_check.substring(1))
  3526. this.tag_type = 'END'
  3527. } else {
  3528. this.record_tag(tag_check)
  3529. this.tag_type = 'START'
  3530. }
  3531. if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) {
  3532. this.print_newline(true, this.output)
  3533. }
  3534. }
  3535. return content.join('')
  3536. }
  3537. this.get_unformatted = function (delimiter, orig_tag) {
  3538. if (orig_tag && orig_tag.indexOf(delimiter) != -1) {
  3539. return ''
  3540. }
  3541. var char = ''
  3542. var content = ''
  3543. var space = true
  3544. do {
  3545. char = this.input.charAt(this.pos)
  3546. this.pos++
  3547. if (this.Utils.in_array(char, this.Utils.whitespace)) {
  3548. if (!space) {
  3549. this.line_char_count--
  3550. continue
  3551. }
  3552. if (char === '\n' || char === '\r') {
  3553. content += '\n'
  3554. for (var i = 0; i < this.indent_level; i++) {
  3555. content += this.indent_string
  3556. }
  3557. space = false
  3558. this.line_char_count = 0
  3559. continue
  3560. }
  3561. }
  3562. content += char
  3563. this.line_char_count++
  3564. space = true
  3565. } while (content.indexOf(delimiter) == -1)
  3566. return content
  3567. }
  3568. this.get_token = function () {
  3569. var token
  3570. if (this.last_token === 'TK_TAG_SCRIPT') {
  3571. var temp_token = this.get_script()
  3572. if (typeof temp_token !== 'string') {
  3573. return temp_token
  3574. }
  3575. token = js_beautify(temp_token, this.indent_size, this.indent_character, this.indent_level)
  3576. return [token, 'TK_CONTENT']
  3577. }
  3578. if (this.current_mode === 'CONTENT') {
  3579. token = this.get_content()
  3580. if (typeof token !== 'string') {
  3581. return token
  3582. } else {
  3583. return [token, 'TK_CONTENT']
  3584. }
  3585. }
  3586. if (this.current_mode === 'TAG') {
  3587. token = this.get_tag()
  3588. if (typeof token !== 'string') {
  3589. return token
  3590. } else {
  3591. var tag_name_type = 'TK_TAG_' + this.tag_type
  3592. return [token, tag_name_type]
  3593. }
  3594. }
  3595. }
  3596. this.printer = function (js_source, indent_character, indent_size, max_char) {
  3597. this.input = js_source || ''
  3598. this.output = []
  3599. this.indent_character = indent_character || ' '
  3600. this.indent_string = ''
  3601. this.indent_size = indent_size || 2
  3602. this.indent_level = 0
  3603. this.max_char = max_char || 7000
  3604. this.line_char_count = 0
  3605. for (var i = 0; i < this.indent_size; i++) {
  3606. this.indent_string += this.indent_character
  3607. }
  3608. this.print_newline = function (ignore, arr) {
  3609. this.line_char_count = 0
  3610. if (!arr || !arr.length) {
  3611. return
  3612. }
  3613. if (!ignore) {
  3614. while (this.Utils.in_array(arr[arr.length - 1], this.Utils.whitespace)) {
  3615. arr.pop()
  3616. }
  3617. }
  3618. arr.push('\n')
  3619. for (var i = 0; i < this.indent_level; i++) {
  3620. arr.push(this.indent_string)
  3621. }
  3622. }
  3623. this.print_token = function (text) {
  3624. this.output.push(text)
  3625. }
  3626. this.indent = function () {
  3627. this.indent_level++
  3628. }
  3629. this.unindent = function () {
  3630. if (this.indent_level > 0) {
  3631. this.indent_level--
  3632. }
  3633. }
  3634. }
  3635. return this
  3636. }
  3637. multi_parser = new Parser()
  3638. multi_parser.printer(html_source, indent_character, indent_size)
  3639. var f = true
  3640. while (true) {
  3641. var t = multi_parser.get_token()
  3642. multi_parser.token_text = t[0]
  3643. multi_parser.token_type = t[1]
  3644. if (multi_parser.token_type === 'TK_EOF') {
  3645. break
  3646. }
  3647. switch (multi_parser.token_type) {
  3648. case 'TK_TAG_START':
  3649. case 'TK_TAG_SCRIPT':
  3650. case 'TK_TAG_STYLE':
  3651. multi_parser.print_newline(false, multi_parser.output)
  3652. multi_parser.print_token(multi_parser.token_text)
  3653. multi_parser.indent()
  3654. multi_parser.current_mode = 'CONTENT'
  3655. break
  3656. case 'TK_TAG_END':
  3657. if (f) multi_parser.print_newline(true, multi_parser.output)
  3658. multi_parser.print_token(multi_parser.token_text)
  3659. multi_parser.current_mode = 'CONTENT'
  3660. f = true
  3661. break
  3662. case 'TK_TAG_SINGLE':
  3663. multi_parser.print_newline(false, multi_parser.output)
  3664. multi_parser.print_token(multi_parser.token_text)
  3665. multi_parser.current_mode = 'CONTENT'
  3666. break
  3667. case 'TK_CONTENT':
  3668. if (multi_parser.token_text !== '') {
  3669. f = false
  3670. multi_parser.print_token(multi_parser.token_text)
  3671. }
  3672. multi_parser.current_mode = 'TAG'
  3673. break
  3674. }
  3675. multi_parser.last_token = multi_parser.token_type
  3676. multi_parser.last_text = multi_parser.token_text
  3677. }
  3678. return multi_parser.output.join('')
  3679. }
  3680. //JS 格式化
  3681. function js_beautify(js_source_text, indent_size, indent_character, indent_level) {
  3682. var input, output, token_text, last_type, last_text, last_word, current_mode, modes, indent_string
  3683. var whitespace, wordchar, punct, parser_pos, line_starters, in_case
  3684. var prefix, token_type, do_block_just_closed, var_line, var_line_tainted
  3685. function trim_output() {
  3686. while (output.length && (output[output.length - 1] === ' ' || output[output.length - 1] === indent_string)) {
  3687. output.pop()
  3688. }
  3689. }
  3690. function print_newline(ignore_repeated) {
  3691. ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated
  3692. trim_output()
  3693. if (!output.length) {
  3694. return // no newline on start of file
  3695. }
  3696. if (output[output.length - 1] !== '\n' || !ignore_repeated) {
  3697. output.push('\n')
  3698. }
  3699. for (var i = 0; i < indent_level; i++) {
  3700. output.push(indent_string)
  3701. }
  3702. }
  3703. function print_space() {
  3704. var last_output = output.length ? output[output.length - 1] : ' '
  3705. if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) {
  3706. // prevent occassional duplicate space
  3707. output.push(' ')
  3708. }
  3709. }
  3710. function print_token() {
  3711. output.push(token_text)
  3712. }
  3713. function indent() {
  3714. indent_level++
  3715. }
  3716. function unindent() {
  3717. if (indent_level) {
  3718. indent_level--
  3719. }
  3720. }
  3721. function remove_indent() {
  3722. if (output.length && output[output.length - 1] === indent_string) {
  3723. output.pop()
  3724. }
  3725. }
  3726. function set_mode(mode) {
  3727. modes.push(current_mode)
  3728. current_mode = mode
  3729. }
  3730. function restore_mode() {
  3731. do_block_just_closed = current_mode === 'DO_BLOCK'
  3732. current_mode = modes.pop()
  3733. }
  3734. function in_array(what, arr) {
  3735. for (var i = 0; i < arr.length; i++) {
  3736. if (arr[i] === what) {
  3737. return true
  3738. }
  3739. }
  3740. return false
  3741. }
  3742. function get_next_token() {
  3743. var n_newlines = 0
  3744. var c = ''
  3745. do {
  3746. if (parser_pos >= input.length) {
  3747. return ['', 'TK_EOF']
  3748. }
  3749. c = input.charAt(parser_pos)
  3750. parser_pos += 1
  3751. if (c === '\n') {
  3752. n_newlines += 1
  3753. }
  3754. } while (in_array(c, whitespace))
  3755. if (n_newlines > 1) {
  3756. for (var i = 0; i < 2; i++) {
  3757. print_newline(i === 0)
  3758. }
  3759. }
  3760. var wanted_newline = n_newlines === 1
  3761. if (in_array(c, wordchar)) {
  3762. if (parser_pos < input.length) {
  3763. while (in_array(input.charAt(parser_pos), wordchar)) {
  3764. c += input.charAt(parser_pos)
  3765. parser_pos += 1
  3766. if (parser_pos === input.length) {
  3767. break
  3768. }
  3769. }
  3770. }
  3771. // small and surprisingly unugly hack for 1E-10 representation
  3772. if (parser_pos !== input.length && c.match(/^[0-9]+[Ee]$/) && input.charAt(parser_pos) === '-') {
  3773. parser_pos += 1
  3774. var t = get_next_token(parser_pos)
  3775. c += '-' + t[0]
  3776. return [c, 'TK_WORD']
  3777. }
  3778. if (c === 'in') {
  3779. // hack for 'in' operator
  3780. return [c, 'TK_OPERATOR']
  3781. }
  3782. return [c, 'TK_WORD']
  3783. }
  3784. if (c === '(' || c === '[') {
  3785. return [c, 'TK_START_EXPR']
  3786. }
  3787. if (c === ')' || c === ']') {
  3788. return [c, 'TK_END_EXPR']
  3789. }
  3790. if (c === '{') {
  3791. return [c, 'TK_START_BLOCK']
  3792. }
  3793. if (c === '}') {
  3794. return [c, 'TK_END_BLOCK']
  3795. }
  3796. if (c === ';') {
  3797. return [c, 'TK_END_COMMAND']
  3798. }
  3799. if (c === '/') {
  3800. var comment = ''
  3801. // peek for comment /* ... */
  3802. if (input.charAt(parser_pos) === '*') {
  3803. parser_pos += 1
  3804. if (parser_pos < input.length) {
  3805. while (
  3806. !(input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/') &&
  3807. parser_pos < input.length
  3808. ) {
  3809. comment += input.charAt(parser_pos)
  3810. parser_pos += 1
  3811. if (parser_pos >= input.length) {
  3812. break
  3813. }
  3814. }
  3815. }
  3816. parser_pos += 2
  3817. return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT']
  3818. }
  3819. // peek for comment // ...
  3820. if (input.charAt(parser_pos) === '/') {
  3821. comment = c
  3822. while (input.charAt(parser_pos) !== '\x0d' && input.charAt(parser_pos) !== '\x0a') {
  3823. comment += input.charAt(parser_pos)
  3824. parser_pos += 1
  3825. if (parser_pos >= input.length) {
  3826. break
  3827. }
  3828. }
  3829. parser_pos += 1
  3830. if (wanted_newline) {
  3831. print_newline()
  3832. }
  3833. return [comment, 'TK_COMMENT']
  3834. }
  3835. }
  3836. if (
  3837. c === "'" || // string
  3838. c === '"' || // string
  3839. (c === '/' &&
  3840. ((last_type === 'TK_WORD' && last_text === 'return') ||
  3841. last_type === 'TK_START_EXPR' ||
  3842. last_type === 'TK_END_BLOCK' ||
  3843. last_type === 'TK_OPERATOR' ||
  3844. last_type === 'TK_EOF' ||
  3845. last_type === 'TK_END_COMMAND'))
  3846. ) {
  3847. // regexp
  3848. var sep = c
  3849. var esc = false
  3850. c = ''
  3851. if (parser_pos < input.length) {
  3852. while (esc || input.charAt(parser_pos) !== sep) {
  3853. c += input.charAt(parser_pos)
  3854. if (!esc) {
  3855. esc = input.charAt(parser_pos) === '\\'
  3856. } else {
  3857. esc = false
  3858. }
  3859. parser_pos += 1
  3860. if (parser_pos >= input.length) {
  3861. break
  3862. }
  3863. }
  3864. }
  3865. parser_pos += 1
  3866. if (last_type === 'TK_END_COMMAND') {
  3867. print_newline()
  3868. }
  3869. return [sep + c + sep, 'TK_STRING']
  3870. }
  3871. if (in_array(c, punct)) {
  3872. while (parser_pos < input.length && in_array(c + input.charAt(parser_pos), punct)) {
  3873. c += input.charAt(parser_pos)
  3874. parser_pos += 1
  3875. if (parser_pos >= input.length) {
  3876. break
  3877. }
  3878. }
  3879. return [c, 'TK_OPERATOR']
  3880. }
  3881. return [c, 'TK_UNKNOWN']
  3882. }
  3883. //----------------------------------
  3884. indent_character = indent_character || ' '
  3885. indent_size = indent_size || 4
  3886. indent_string = ''
  3887. while (indent_size--) {
  3888. indent_string += indent_character
  3889. }
  3890. input = js_source_text
  3891. last_word = '' // last 'TK_WORD' passed
  3892. last_type = 'TK_START_EXPR' // last token type
  3893. last_text = '' // last token text
  3894. output = []
  3895. do_block_just_closed = false
  3896. var_line = false
  3897. var_line_tainted = false
  3898. whitespace = '\n\r\t '.split('')
  3899. wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split('')
  3900. punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |='.split(' ')
  3901. // words which should always start on new line.
  3902. line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',')
  3903. // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'.
  3904. // some formatting depends on that.
  3905. current_mode = 'BLOCK'
  3906. modes = [current_mode]
  3907. indent_level = indent_level || 0
  3908. parser_pos = 0 // parser position
  3909. in_case = false // flag for parser that case/default has been processed, and next colon needs special attention
  3910. while (true) {
  3911. var t = get_next_token(parser_pos)
  3912. token_text = t[0]
  3913. token_type = t[1]
  3914. if (token_type === 'TK_EOF') {
  3915. break
  3916. }
  3917. switch (token_type) {
  3918. case 'TK_START_EXPR':
  3919. var_line = false
  3920. set_mode('EXPRESSION')
  3921. if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR') {
  3922. // do nothing on (( and )( and ][ and ]( ..
  3923. } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
  3924. print_space()
  3925. } else if (in_array(last_word, line_starters) && last_word !== 'function') {
  3926. print_space()
  3927. }
  3928. print_token()
  3929. break
  3930. case 'TK_END_EXPR':
  3931. print_token()
  3932. restore_mode()
  3933. break
  3934. case 'TK_START_BLOCK':
  3935. if (last_word === 'do') {
  3936. set_mode('DO_BLOCK')
  3937. } else {
  3938. set_mode('BLOCK')
  3939. }
  3940. if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') {
  3941. if (last_type === 'TK_START_BLOCK') {
  3942. print_newline()
  3943. } else {
  3944. print_space()
  3945. }
  3946. }
  3947. print_token()
  3948. indent()
  3949. break
  3950. case 'TK_END_BLOCK':
  3951. if (last_type === 'TK_START_BLOCK') {
  3952. // nothing
  3953. trim_output()
  3954. unindent()
  3955. } else {
  3956. unindent()
  3957. print_newline()
  3958. }
  3959. print_token()
  3960. restore_mode()
  3961. break
  3962. case 'TK_WORD':
  3963. if (do_block_just_closed) {
  3964. print_space()
  3965. print_token()
  3966. print_space()
  3967. break
  3968. }
  3969. if (token_text === 'case' || token_text === 'default') {
  3970. if (last_text === ':') {
  3971. // switch cases following one another
  3972. remove_indent()
  3973. } else {
  3974. // case statement starts in the same line where switch
  3975. unindent()
  3976. print_newline()
  3977. indent()
  3978. }
  3979. print_token()
  3980. in_case = true
  3981. break
  3982. }
  3983. prefix = 'NONE'
  3984. if (last_type === 'TK_END_BLOCK') {
  3985. if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
  3986. prefix = 'NEWLINE'
  3987. } else {
  3988. prefix = 'SPACE'
  3989. print_space()
  3990. }
  3991. } else if (last_type === 'TK_END_COMMAND' && (current_mode === 'BLOCK' || current_mode === 'DO_BLOCK')) {
  3992. prefix = 'NEWLINE'
  3993. } else if (last_type === 'TK_END_COMMAND' && current_mode === 'EXPRESSION') {
  3994. prefix = 'SPACE'
  3995. } else if (last_type === 'TK_WORD') {
  3996. prefix = 'SPACE'
  3997. } else if (last_type === 'TK_START_BLOCK') {
  3998. prefix = 'NEWLINE'
  3999. } else if (last_type === 'TK_END_EXPR') {
  4000. print_space()
  4001. prefix = 'NEWLINE'
  4002. }
  4003. if (last_type !== 'TK_END_BLOCK' && in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
  4004. print_newline()
  4005. } else if (in_array(token_text, line_starters) || prefix === 'NEWLINE') {
  4006. if (last_text === 'else') {
  4007. // no need to force newline on else break
  4008. print_space()
  4009. } else if ((last_type === 'TK_START_EXPR' || last_text === '=') && token_text === 'function') {
  4010. // no need to force newline on 'function': (function
  4011. // DONOTHING
  4012. } else if (last_type === 'TK_WORD' && (last_text === 'return' || last_text === 'throw')) {
  4013. // no newline between 'return nnn'
  4014. print_space()
  4015. } else if (last_type !== 'TK_END_EXPR') {
  4016. if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') {
  4017. // no need to force newline on 'var': for (var x = 0...)
  4018. if (token_text === 'if' && last_type === 'TK_WORD' && last_word === 'else') {
  4019. // no newline for } else if {
  4020. print_space()
  4021. } else {
  4022. print_newline()
  4023. }
  4024. }
  4025. } else {
  4026. if (in_array(token_text, line_starters) && last_text !== ')') {
  4027. print_newline()
  4028. }
  4029. }
  4030. } else if (prefix === 'SPACE') {
  4031. print_space()
  4032. }
  4033. print_token()
  4034. last_word = token_text
  4035. if (token_text === 'var') {
  4036. var_line = true
  4037. var_line_tainted = false
  4038. }
  4039. break
  4040. case 'TK_END_COMMAND':
  4041. print_token()
  4042. var_line = false
  4043. break
  4044. case 'TK_STRING':
  4045. if (last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK') {
  4046. print_newline()
  4047. } else if (last_type === 'TK_WORD') {
  4048. print_space()
  4049. }
  4050. print_token()
  4051. break
  4052. case 'TK_OPERATOR':
  4053. var start_delim = true
  4054. var end_delim = true
  4055. if (var_line && token_text !== ',') {
  4056. var_line_tainted = true
  4057. if (token_text === ':') {
  4058. var_line = false
  4059. }
  4060. }
  4061. if (token_text === ':' && in_case) {
  4062. print_token() // colon really asks for separate treatment
  4063. print_newline()
  4064. break
  4065. }
  4066. in_case = false
  4067. if (token_text === ',') {
  4068. if (var_line) {
  4069. if (var_line_tainted) {
  4070. print_token()
  4071. print_newline()
  4072. var_line_tainted = false
  4073. } else {
  4074. print_token()
  4075. print_space()
  4076. }
  4077. } else if (last_type === 'TK_END_BLOCK') {
  4078. print_token()
  4079. print_newline()
  4080. } else {
  4081. if (current_mode === 'BLOCK') {
  4082. print_token()
  4083. print_newline()
  4084. } else {
  4085. // EXPR od DO_BLOCK
  4086. print_token()
  4087. print_space()
  4088. }
  4089. }
  4090. break
  4091. } else if (token_text === '--' || token_text === '++') {
  4092. // unary operators special case
  4093. if (last_text === ';') {
  4094. // space for (;; ++i)
  4095. start_delim = true
  4096. end_delim = false
  4097. } else {
  4098. start_delim = false
  4099. end_delim = false
  4100. }
  4101. } else if (token_text === '!' && last_type === 'TK_START_EXPR') {
  4102. // special case handling: if (!a)
  4103. start_delim = false
  4104. end_delim = false
  4105. } else if (last_type === 'TK_OPERATOR') {
  4106. start_delim = false
  4107. end_delim = false
  4108. } else if (last_type === 'TK_END_EXPR') {
  4109. start_delim = true
  4110. end_delim = true
  4111. } else if (token_text === '.') {
  4112. // decimal digits or object.property
  4113. start_delim = false
  4114. end_delim = false
  4115. } else if (token_text === ':') {
  4116. // zz: xx
  4117. // can't differentiate ternary op, so for now it's a ? b: c; without space before colon
  4118. if (last_text.match(/^\d+$/)) {
  4119. // a little help for ternary a ? 1 : 0;
  4120. start_delim = true
  4121. } else {
  4122. start_delim = false
  4123. }
  4124. }
  4125. if (start_delim) {
  4126. print_space()
  4127. }
  4128. print_token()
  4129. if (end_delim) {
  4130. print_space()
  4131. }
  4132. break
  4133. case 'TK_BLOCK_COMMENT':
  4134. print_newline()
  4135. print_token()
  4136. print_newline()
  4137. break
  4138. case 'TK_COMMENT':
  4139. // print_newline();
  4140. print_space()
  4141. print_token()
  4142. print_newline()
  4143. break
  4144. case 'TK_UNKNOWN':
  4145. print_token()
  4146. break
  4147. default:
  4148. break
  4149. }
  4150. last_type = token_type
  4151. last_text = token_text
  4152. }
  4153. return output.join('')
  4154. }