neditor.all.js 1.3 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244332453324633247332483324933250332513325233253332543325533256332573325833259332603326133262332633326433265332663326733268332693327033271332723327333274332753327633277332783327933280332813328233283332843328533286332873328833289332903329133292
  1. /*!
  2. * neditor
  3. * version: 2.0.0
  4. * build: Tue Mar 20 2018 04:23:08 GMT+0000 (UTC)
  5. */
  6. (function () {
  7. // editor.js
  8. UEDITOR_CONFIG = window.UEDITOR_CONFIG || {};
  9. var baidu = window.baidu || {};
  10. window.baidu = baidu;
  11. window.UE = baidu.editor = {
  12. plugins: {},
  13. commands: {},
  14. instants: {},
  15. I18N: {},
  16. _customizeUI: {},
  17. version: "1.5.0"
  18. };
  19. var dom = (UE.dom = {});
  20. // core/browser.js
  21. /**
  22. * 浏览器判断模块
  23. * @file
  24. * @module UE.browser
  25. * @since 1.2.6.1
  26. */
  27. /**
  28. * 提供浏览器检测的模块
  29. * @unfile
  30. * @module UE.browser
  31. */
  32. var browser = (UE.browser = (function () {
  33. var agent = navigator.userAgent.toLowerCase(),
  34. opera = window.opera,
  35. browser = {
  36. /**
  37. * @property {boolean} ie 检测当前浏览器是否为IE
  38. * @example
  39. * ```javascript
  40. * if ( UE.browser.ie ) {
  41. * console.log( '当前浏览器是IE' );
  42. * }
  43. * ```
  44. */
  45. ie: /(msie\s|trident.*rv:)([\w.]+)/i.test(agent),
  46. /**
  47. * @property {boolean} opera 检测当前浏览器是否为Opera
  48. * @example
  49. * ```javascript
  50. * if ( UE.browser.opera ) {
  51. * console.log( '当前浏览器是Opera' );
  52. * }
  53. * ```
  54. */
  55. opera: !!opera && opera.version,
  56. /**
  57. * @property {boolean} webkit 检测当前浏览器是否是webkit内核的浏览器
  58. * @example
  59. * ```javascript
  60. * if ( UE.browser.webkit ) {
  61. * console.log( '当前浏览器是webkit内核浏览器' );
  62. * }
  63. * ```
  64. */
  65. webkit: agent.indexOf(" applewebkit/") > -1,
  66. /**
  67. * @property {boolean} mac 检测当前浏览器是否是运行在mac平台下
  68. * @example
  69. * ```javascript
  70. * if ( UE.browser.mac ) {
  71. * console.log( '当前浏览器运行在mac平台下' );
  72. * }
  73. * ```
  74. */
  75. mac: agent.indexOf("macintosh") > -1,
  76. /**
  77. * @property {boolean} quirks 检测当前浏览器是否处于“怪异模式”下
  78. * @example
  79. * ```javascript
  80. * if ( UE.browser.quirks ) {
  81. * console.log( '当前浏览器运行处于“怪异模式”' );
  82. * }
  83. * ```
  84. */
  85. quirks: document.compatMode == "BackCompat"
  86. };
  87. /**
  88. * @property {boolean} gecko 检测当前浏览器内核是否是gecko内核
  89. * @example
  90. * ```javascript
  91. * if ( UE.browser.gecko ) {
  92. * console.log( '当前浏览器内核是gecko内核' );
  93. * }
  94. * ```
  95. */
  96. browser.gecko =
  97. navigator.product == "Gecko" &&
  98. !browser.webkit &&
  99. !browser.opera &&
  100. !browser.ie;
  101. var version = 0;
  102. // Internet Explorer 6.0+
  103. if (browser.ie) {
  104. var v1 = agent.match(/(?:msie\s([\w.]+))/);
  105. var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
  106. if (v1 && v2 && v1[1] && v2[1]) {
  107. version = Math.max(v1[1] * 1, v2[1] * 1);
  108. } else if (v1 && v1[1]) {
  109. version = v1[1] * 1;
  110. } else if (v2 && v2[1]) {
  111. version = v2[1] * 1;
  112. } else {
  113. version = 0;
  114. }
  115. browser.ie11Compat = document.documentMode == 11;
  116. /**
  117. * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式
  118. * @warning 如果浏览器不是IE, 则该值为undefined
  119. * @example
  120. * ```javascript
  121. * if ( UE.browser.ie9Compat ) {
  122. * console.log( '当前浏览器运行在IE9兼容模式下' );
  123. * }
  124. * ```
  125. */
  126. browser.ie9Compat = document.documentMode == 9;
  127. /**
  128. * @property { boolean } ie8 检测浏览器是否是IE8浏览器
  129. * @warning 如果浏览器不是IE, 则该值为undefined
  130. * @example
  131. * ```javascript
  132. * if ( UE.browser.ie8 ) {
  133. * console.log( '当前浏览器是IE8浏览器' );
  134. * }
  135. * ```
  136. */
  137. browser.ie8 = !!document.documentMode;
  138. /**
  139. * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式
  140. * @warning 如果浏览器不是IE, 则该值为undefined
  141. * @example
  142. * ```javascript
  143. * if ( UE.browser.ie8Compat ) {
  144. * console.log( '当前浏览器运行在IE8兼容模式下' );
  145. * }
  146. * ```
  147. */
  148. browser.ie8Compat = document.documentMode == 8;
  149. /**
  150. * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式
  151. * @warning 如果浏览器不是IE, 则该值为undefined
  152. * @example
  153. * ```javascript
  154. * if ( UE.browser.ie7Compat ) {
  155. * console.log( '当前浏览器运行在IE7兼容模式下' );
  156. * }
  157. * ```
  158. */
  159. browser.ie7Compat =
  160. (version == 7 && !document.documentMode) || document.documentMode == 7;
  161. /**
  162. * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式
  163. * @warning 如果浏览器不是IE, 则该值为undefined
  164. * @example
  165. * ```javascript
  166. * if ( UE.browser.ie6Compat ) {
  167. * console.log( '当前浏览器运行在IE6模式或者怪异模式下' );
  168. * }
  169. * ```
  170. */
  171. browser.ie6Compat = version < 7 || browser.quirks;
  172. browser.ie9above = version > 8;
  173. browser.ie9below = version < 9;
  174. browser.ie11above = version > 10;
  175. browser.ie11below = version < 11;
  176. }
  177. // Gecko.
  178. if (browser.gecko) {
  179. var geckoRelease = agent.match(/rv:([\d\.]+)/);
  180. if (geckoRelease) {
  181. geckoRelease = geckoRelease[1].split(".");
  182. version =
  183. geckoRelease[0] * 10000 +
  184. (geckoRelease[1] || 0) * 100 +
  185. (geckoRelease[2] || 0) * 1;
  186. }
  187. }
  188. /**
  189. * @property { Number } chrome 检测当前浏览器是否为Chrome, 如果是,则返回Chrome的大版本号
  190. * @warning 如果浏览器不是chrome, 则该值为undefined
  191. * @example
  192. * ```javascript
  193. * if ( UE.browser.chrome ) {
  194. * console.log( '当前浏览器是Chrome' );
  195. * }
  196. * ```
  197. */
  198. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  199. browser.chrome = +RegExp["\x241"];
  200. }
  201. /**
  202. * @property { Number } safari 检测当前浏览器是否为Safari, 如果是,则返回Safari的大版本号
  203. * @warning 如果浏览器不是safari, 则该值为undefined
  204. * @example
  205. * ```javascript
  206. * if ( UE.browser.safari ) {
  207. * console.log( '当前浏览器是Safari' );
  208. * }
  209. * ```
  210. */
  211. if (
  212. /(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) &&
  213. !/chrome/i.test(agent)
  214. ) {
  215. browser.safari = +(RegExp["\x241"] || RegExp["\x242"]);
  216. }
  217. // Opera 9.50+
  218. if (browser.opera) version = parseFloat(opera.version());
  219. // WebKit 522+ (Safari 3+)
  220. if (browser.webkit)
  221. version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);
  222. /**
  223. * @property { Number } version 检测当前浏览器版本号
  224. * @remind
  225. * <ul>
  226. * <li>IE系列返回值为5,6,7,8,9,10等</li>
  227. * <li>gecko系列会返回10900,158900等</li>
  228. * <li>webkit系列会返回其build号 (如 522等)</li>
  229. * </ul>
  230. * @example
  231. * ```javascript
  232. * console.log( '当前浏览器版本号是: ' + UE.browser.version );
  233. * ```
  234. */
  235. browser.version = version;
  236. /**
  237. * @property { boolean } isCompatible 检测当前浏览器是否能够与UEditor良好兼容
  238. * @example
  239. * ```javascript
  240. * if ( UE.browser.isCompatible ) {
  241. * console.log( '浏览器与UEditor能够良好兼容' );
  242. * }
  243. * ```
  244. */
  245. browser.isCompatible =
  246. !browser.mobile &&
  247. ((browser.ie && version >= 6) ||
  248. (browser.gecko && version >= 10801) ||
  249. (browser.opera && version >= 9.5) ||
  250. (browser.air && version >= 1) ||
  251. (browser.webkit && version >= 522) ||
  252. false);
  253. return browser;
  254. })());
  255. //快捷方式
  256. var ie = browser.ie,
  257. webkit = browser.webkit,
  258. gecko = browser.gecko,
  259. opera = browser.opera;
  260. // core/utils.js
  261. /**
  262. * 工具函数包
  263. * @file
  264. * @module UE.utils
  265. * @since 1.2.6.1
  266. */
  267. /**
  268. * UEditor封装使用的静态工具函数
  269. * @module UE.utils
  270. * @unfile
  271. */
  272. var utils = (UE.utils = {
  273. /**
  274. * 用给定的迭代器遍历对象
  275. * @method each
  276. * @param { Object } obj 需要遍历的对象
  277. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  278. * @example
  279. * ```javascript
  280. * var demoObj = {
  281. * key1: 1,
  282. * key2: 2
  283. * };
  284. *
  285. * //output: key1: 1, key2: 2
  286. * UE.utils.each( demoObj, funciton ( value, key ) {
  287. *
  288. * console.log( key + ":" + value );
  289. *
  290. * } );
  291. * ```
  292. */
  293. /**
  294. * 用给定的迭代器遍历数组或类数组对象
  295. * @method each
  296. * @param { Array } array 需要遍历的数组或者类数组
  297. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  298. * @example
  299. * ```javascript
  300. * var divs = document.getElmentByTagNames( "div" );
  301. *
  302. * //output: 0: DIV, 1: DIV ...
  303. * UE.utils.each( divs, funciton ( value, key ) {
  304. *
  305. * console.log( key + ":" + value.tagName );
  306. *
  307. * } );
  308. * ```
  309. */
  310. each: function (obj, iterator, context) {
  311. if (obj == null) return;
  312. if (obj.length === +obj.length) {
  313. for (var i = 0, l = obj.length; i < l; i++) {
  314. if (iterator.call(context, obj[i], i, obj) === false) return false;
  315. }
  316. } else {
  317. for (var key in obj) {
  318. if (obj.hasOwnProperty(key)) {
  319. if (iterator.call(context, obj[key], key, obj) === false)
  320. return false;
  321. }
  322. }
  323. }
  324. },
  325. /**
  326. * 以给定对象作为原型创建一个新对象
  327. * @method makeInstance
  328. * @param { Object } protoObject 该对象将作为新创建对象的原型
  329. * @return { Object } 新的对象, 该对象的原型是给定的protoObject对象
  330. * @example
  331. * ```javascript
  332. *
  333. * var protoObject = { sayHello: function () { console.log('Hello UEditor!'); } };
  334. *
  335. * var newObject = UE.utils.makeInstance( protoObject );
  336. * //output: Hello UEditor!
  337. * newObject.sayHello();
  338. * ```
  339. */
  340. makeInstance: function (obj) {
  341. var noop = new Function();
  342. noop.prototype = obj;
  343. obj = new noop();
  344. noop.prototype = null;
  345. return obj;
  346. },
  347. /**
  348. * 将source对象中的属性扩展到target对象上
  349. * @method extend
  350. * @remind 该方法将强制把source对象上的属性复制到target对象上
  351. * @see UE.utils.extend(Object,Object,Boolean)
  352. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  353. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  354. * @return { Object } 返回target对象
  355. * @example
  356. * ```javascript
  357. *
  358. * var target = { name: 'target', sex: 1 },
  359. * source = { name: 'source', age: 17 };
  360. *
  361. * UE.utils.extend( target, source );
  362. *
  363. * //output: { name: 'source', sex: 1, age: 17 }
  364. * console.log( target );
  365. *
  366. * ```
  367. */
  368. /**
  369. * 将source对象中的属性扩展到target对象上, 根据指定的isKeepTarget值决定是否保留目标对象中与
  370. * 源对象属性名相同的属性值。
  371. * @method extend
  372. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  373. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  374. * @param { Boolean } isKeepTarget 是否保留目标对象中与源对象中属性名相同的属性
  375. * @return { Object } 返回target对象
  376. * @example
  377. * ```javascript
  378. *
  379. * var target = { name: 'target', sex: 1 },
  380. * source = { name: 'source', age: 17 };
  381. *
  382. * UE.utils.extend( target, source, true );
  383. *
  384. * //output: { name: 'target', sex: 1, age: 17 }
  385. * console.log( target );
  386. *
  387. * ```
  388. */
  389. extend: function (t, s, b) {
  390. if (s) {
  391. for (var k in s) {
  392. if (!b || !t.hasOwnProperty(k)) {
  393. t[k] = s[k];
  394. }
  395. }
  396. }
  397. return t;
  398. },
  399. /**
  400. * 将给定的多个对象的属性复制到目标对象target上
  401. * @method extend2
  402. * @remind 该方法将强制把源对象上的属性复制到target对象上
  403. * @remind 该方法支持两个及以上的参数, 从第二个参数开始, 其属性都会被复制到第一个参数上。 如果遇到同名的属性,
  404. * 将会覆盖掉之前的值。
  405. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  406. * @param { Object... } source 源对象, 支持多个对象, 该对象的属性会被附加到target对象上
  407. * @return { Object } 返回target对象
  408. * @example
  409. * ```javascript
  410. *
  411. * var target = {},
  412. * source1 = { name: 'source', age: 17 },
  413. * source2 = { title: 'dev' };
  414. *
  415. * UE.utils.extend2( target, source1, source2 );
  416. *
  417. * //output: { name: 'source', age: 17, title: 'dev' }
  418. * console.log( target );
  419. *
  420. * ```
  421. */
  422. extend2: function (t) {
  423. var a = arguments;
  424. for (var i = 1; i < a.length; i++) {
  425. var x = a[i];
  426. for (var k in x) {
  427. if (!t.hasOwnProperty(k)) {
  428. t[k] = x[k];
  429. }
  430. }
  431. }
  432. return t;
  433. },
  434. /**
  435. * 模拟继承机制, 使得subClass继承自superClass
  436. * @method inherits
  437. * @param { Object } subClass 子类对象
  438. * @param { Object } superClass 超类对象
  439. * @warning 该方法只能让subClass继承超类的原型, subClass对象自身的属性和方法不会被继承
  440. * @return { Object } 继承superClass后的子类对象
  441. * @example
  442. * ```javascript
  443. * function SuperClass(){
  444. * this.name = "小李";
  445. * }
  446. *
  447. * SuperClass.prototype = {
  448. * hello:function(str){
  449. * console.log(this.name + str);
  450. * }
  451. * }
  452. *
  453. * function SubClass(){
  454. * this.name = "小张";
  455. * }
  456. *
  457. * UE.utils.inherits(SubClass,SuperClass);
  458. *
  459. * var sub = new SubClass();
  460. * //output: '小张早上好!
  461. * sub.hello("早上好!");
  462. * ```
  463. */
  464. inherits: function (subClass, superClass) {
  465. var oldP = subClass.prototype,
  466. newP = utils.makeInstance(superClass.prototype);
  467. utils.extend(newP, oldP, true);
  468. subClass.prototype = newP;
  469. return (newP.constructor = subClass);
  470. },
  471. /**
  472. * 用指定的context对象作为函数fn的上下文
  473. * @method bind
  474. * @param { Function } fn 需要绑定上下文的函数对象
  475. * @param { Object } content 函数fn新的上下文对象
  476. * @return { Function } 一个新的函数, 该函数作为原始函数fn的代理, 将完成fn的上下文调换工作。
  477. * @example
  478. * ```javascript
  479. *
  480. * var name = 'window',
  481. * newTest = null;
  482. *
  483. * function test () {
  484. * console.log( this.name );
  485. * }
  486. *
  487. * newTest = UE.utils.bind( test, { name: 'object' } );
  488. *
  489. * //output: object
  490. * newTest();
  491. *
  492. * //output: window
  493. * test();
  494. *
  495. * ```
  496. */
  497. bind: function (fn, context) {
  498. return function () {
  499. return fn.apply(context, arguments);
  500. };
  501. },
  502. /**
  503. * 创建延迟指定时间后执行的函数fn
  504. * @method defer
  505. * @param { Function } fn 需要延迟执行的函数对象
  506. * @param { int } delay 延迟的时间, 单位是毫秒
  507. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  508. * 而不能保证刚好到达延迟时间时执行。
  509. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  510. * @example
  511. * ```javascript
  512. * var start = 0;
  513. *
  514. * function test(){
  515. * console.log( new Date() - start );
  516. * }
  517. *
  518. * var testDefer = UE.utils.defer( test, 1000 );
  519. * //
  520. * start = new Date();
  521. * //output: (大约在1000毫秒之后输出) 1000
  522. * testDefer();
  523. * ```
  524. */
  525. /**
  526. * 创建延迟指定时间后执行的函数fn, 如果在延迟时间内再次执行该方法, 将会根据指定的exclusion的值,
  527. * 决定是否取消前一次函数的执行, 如果exclusion的值为true, 则取消执行,反之,将继续执行前一个方法。
  528. * @method defer
  529. * @param { Function } fn 需要延迟执行的函数对象
  530. * @param { int } delay 延迟的时间, 单位是毫秒
  531. * @param { Boolean } exclusion 如果在延迟时间内再次执行该函数,该值将决定是否取消执行前一次函数的执行,
  532. * 值为true表示取消执行, 反之则将在执行前一次函数之后才执行本次函数调用。
  533. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  534. * 而不能保证刚好到达延迟时间时执行。
  535. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  536. * @example
  537. * ```javascript
  538. *
  539. * function test(){
  540. * console.log(1);
  541. * }
  542. *
  543. * var testDefer = UE.utils.defer( test, 1000, true );
  544. *
  545. * //output: (两次调用仅有一次输出) 1
  546. * testDefer();
  547. * testDefer();
  548. * ```
  549. */
  550. defer: function (fn, delay, exclusion) {
  551. var timerID;
  552. return function () {
  553. if (exclusion) {
  554. clearTimeout(timerID);
  555. }
  556. timerID = setTimeout(fn, delay);
  557. };
  558. },
  559. /**
  560. * 获取元素item在数组array中首次出现的位置, 如果未找到item, 则返回-1
  561. * @method indexOf
  562. * @remind 该方法的匹配过程使用的是恒等“===”
  563. * @param { Array } array 需要查找的数组对象
  564. * @param { * } item 需要在目标数组中查找的值
  565. * @return { int } 返回item在目标数组array中首次出现的位置, 如果在数组中未找到item, 则返回-1
  566. * @example
  567. * ```javascript
  568. * var item = 1,
  569. * arr = [ 3, 4, 6, 8, 1, 1, 2 ];
  570. *
  571. * //output: 4
  572. * console.log( UE.utils.indexOf( arr, item ) );
  573. * ```
  574. */
  575. /**
  576. * 获取元素item数组array中首次出现的位置, 如果未找到item, 则返回-1。通过start的值可以指定搜索的起始位置。
  577. * @method indexOf
  578. * @remind 该方法的匹配过程使用的是恒等“===”
  579. * @param { Array } array 需要查找的数组对象
  580. * @param { * } item 需要在目标数组中查找的值
  581. * @param { int } start 搜索的起始位置
  582. * @return { int } 返回item在目标数组array中的start位置之后首次出现的位置, 如果在数组中未找到item, 则返回-1
  583. * @example
  584. * ```javascript
  585. * var item = 1,
  586. * arr = [ 3, 4, 6, 8, 1, 2, 8, 3, 2, 1, 1, 4 ];
  587. *
  588. * //output: 9
  589. * console.log( UE.utils.indexOf( arr, item, 5 ) );
  590. * ```
  591. */
  592. indexOf: function (array, item, start) {
  593. var index = -1;
  594. start = this.isNumber(start) ? start : 0;
  595. this.each(array, function (v, i) {
  596. if (i >= start && v === item) {
  597. index = i;
  598. return false;
  599. }
  600. });
  601. return index;
  602. },
  603. /**
  604. * 移除数组array中所有的元素item
  605. * @method removeItem
  606. * @param { Array } array 要移除元素的目标数组
  607. * @param { * } item 将要被移除的元素
  608. * @remind 该方法的匹配过程使用的是恒等“===”
  609. * @example
  610. * ```javascript
  611. * var arr = [ 4, 5, 7, 1, 3, 4, 6 ];
  612. *
  613. * UE.utils.removeItem( arr, 4 );
  614. * //output: [ 5, 7, 1, 3, 6 ]
  615. * console.log( arr );
  616. *
  617. * ```
  618. */
  619. removeItem: function (array, item) {
  620. for (var i = 0, l = array.length; i < l; i++) {
  621. if (array[i] === item) {
  622. array.splice(i, 1);
  623. i--;
  624. }
  625. }
  626. },
  627. /**
  628. * 删除字符串str的首尾空格
  629. * @method trim
  630. * @param { String } str 需要删除首尾空格的字符串
  631. * @return { String } 删除了首尾的空格后的字符串
  632. * @example
  633. * ```javascript
  634. *
  635. * var str = " UEdtior ";
  636. *
  637. * //output: 9
  638. * console.log( str.length );
  639. *
  640. * //output: 7
  641. * console.log( UE.utils.trim( " UEdtior " ).length );
  642. *
  643. * //output: 9
  644. * console.log( str.length );
  645. *
  646. * ```
  647. */
  648. trim: function (str) {
  649. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, "");
  650. },
  651. /**
  652. * 将字符串str以','分隔成数组后,将该数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  653. * @method listToMap
  654. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  655. * @param { String } str 该字符串将被以','分割为数组, 然后进行转化
  656. * @return { Object } 转化之后的hash对象
  657. * @example
  658. * ```javascript
  659. *
  660. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  661. * console.log( UE.utils.listToMap( 'UEdtior,Hello' ) );
  662. *
  663. * ```
  664. */
  665. /**
  666. * 将字符串数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  667. * @method listToMap
  668. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  669. * @param { Array } arr 字符串数组
  670. * @return { Object } 转化之后的hash对象
  671. * @example
  672. * ```javascript
  673. *
  674. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  675. * console.log( UE.utils.listToMap( [ 'UEdtior', 'Hello' ] ) );
  676. *
  677. * ```
  678. */
  679. listToMap: function (list) {
  680. if (!list) return {};
  681. list = utils.isArray(list) ? list : list.split(",");
  682. for (var i = 0, ci, obj = {}; (ci = list[i++]);) {
  683. obj[ci.toUpperCase()] = obj[ci] = 1;
  684. }
  685. return obj;
  686. },
  687. /**
  688. * 将str中的html符号转义,将转义“',&,<,",>,”,“”七个字符
  689. * @method unhtml
  690. * @param { String } str 需要转义的字符串
  691. * @return { String } 转义后的字符串
  692. * @example
  693. * ```javascript
  694. * var html = '<body>&</body>';
  695. *
  696. * //output: &lt;body&gt;&amp;&lt;/body&gt;
  697. * console.log( UE.utils.unhtml( html ) );
  698. *
  699. * ```
  700. */
  701. unhtml: function (str, reg) {
  702. return str
  703. ? str.replace(
  704. reg || /[&<">'](?:(amp|lt|ldquo|rdquo|quot|gt|#39|nbsp|#\d+);)?/g,
  705. function (a, b) {
  706. if (b) {
  707. return a;
  708. } else {
  709. return {
  710. "<": "&lt;",
  711. "&": "&amp;",
  712. '"': "&quot;",
  713. "“": "&ldquo;",
  714. "”": "&rdquo;",
  715. ">": "&gt;",
  716. "'": "&#39;"
  717. }[a];
  718. }
  719. }
  720. )
  721. : "";
  722. },
  723. /**
  724. * 将str中的转义字符还原成html字符
  725. * @see UE.utils.unhtml(String);
  726. * @method html
  727. * @param { String } str 需要逆转义的字符串
  728. * @return { String } 逆转义后的字符串
  729. * @example
  730. * ```javascript
  731. *
  732. * var str = '&lt;body&gt;&amp;&lt;/body&gt;';
  733. *
  734. * //output: <body>&</body>
  735. * console.log( UE.utils.html( str ) );
  736. *
  737. * ```
  738. */
  739. html: function (str) {
  740. return str
  741. ? str.replace(/&((g|l|quo|ldquo|rdquo)t|amp|#39|nbsp);/g, function (m) {
  742. return {
  743. "&lt;": "<",
  744. "&amp;": "&",
  745. "&quot;": '"',
  746. "&ldquo;": "“",
  747. "&rdquo;": "”",
  748. "&gt;": ">",
  749. "&#39;": "'",
  750. "&nbsp;": " "
  751. }[m];
  752. })
  753. : "";
  754. },
  755. /**
  756. * 将css样式转换为驼峰的形式
  757. * @method cssStyleToDomStyle
  758. * @param { String } cssName 需要转换的css样式名
  759. * @return { String } 转换成驼峰形式后的css样式名
  760. * @example
  761. * ```javascript
  762. *
  763. * var str = 'border-top';
  764. *
  765. * //output: borderTop
  766. * console.log( UE.utils.cssStyleToDomStyle( str ) );
  767. *
  768. * ```
  769. */
  770. cssStyleToDomStyle: (function () {
  771. var test = document.createElement("div").style,
  772. cache = {
  773. float: test.cssFloat != undefined
  774. ? "cssFloat"
  775. : test.styleFloat != undefined ? "styleFloat" : "float"
  776. };
  777. return function (cssName) {
  778. return (
  779. cache[cssName] ||
  780. (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) {
  781. return match.charAt(1).toUpperCase();
  782. }))
  783. );
  784. };
  785. })(),
  786. /**
  787. * 动态加载文件到doc中
  788. * @method loadFile
  789. * @param { DomDocument } document 需要加载资源文件的文档对象
  790. * @param { Object } options 加载资源文件的属性集合, 取值请参考代码示例
  791. * @example
  792. * ```javascript
  793. *
  794. * UE.utils.loadFile( document, {
  795. * src:"test.js",
  796. * tag:"script",
  797. * type:"text/javascript",
  798. * defer:"defer"
  799. * } );
  800. *
  801. * ```
  802. */
  803. /**
  804. * 动态加载文件到doc中,加载成功后执行的回调函数fn
  805. * @method loadFile
  806. * @param { DomDocument } document 需要加载资源文件的文档对象
  807. * @param { Object } options 加载资源文件的属性集合, 该集合支持的值是script标签和style标签支持的所有属性。
  808. * @param { Function } fn 资源文件加载成功之后执行的回调
  809. * @warning 对于在同一个文档中多次加载同一URL的文件, 该方法会在第一次加载之后缓存该请求,
  810. * 在此之后的所有同一URL的请求, 将会直接触发回调。
  811. * @example
  812. * ```javascript
  813. *
  814. * UE.utils.loadFile( document, {
  815. * src:"test.js",
  816. * tag:"script",
  817. * type:"text/javascript",
  818. * defer:"defer"
  819. * }, function () {
  820. * console.log('加载成功');
  821. * } );
  822. *
  823. * ```
  824. */
  825. loadFile: (function () {
  826. var tmpList = [];
  827. function getItem(doc, obj) {
  828. try {
  829. for (var i = 0, ci; (ci = tmpList[i++]);) {
  830. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  831. return ci;
  832. }
  833. }
  834. } catch (e) {
  835. return null;
  836. }
  837. }
  838. return function (doc, obj, fn) {
  839. var item = getItem(doc, obj);
  840. if (item) {
  841. if (item.ready) {
  842. fn && fn();
  843. } else {
  844. item.funs.push(fn);
  845. }
  846. return;
  847. }
  848. tmpList.push({
  849. doc: doc,
  850. url: obj.src || obj.href,
  851. funs: [fn]
  852. });
  853. if (!doc.body) {
  854. var html = [];
  855. for (var p in obj) {
  856. if (p == "tag") continue;
  857. html.push(p + '="' + obj[p] + '"');
  858. }
  859. doc.write(
  860. "<" + obj.tag + " " + html.join(" ") + " ></" + obj.tag + ">"
  861. );
  862. return;
  863. }
  864. if (obj.id && doc.getElementById(obj.id)) {
  865. return;
  866. }
  867. var element = doc.createElement(obj.tag);
  868. delete obj.tag;
  869. for (var p in obj) {
  870. element.setAttribute(p, obj[p]);
  871. }
  872. element.onload = element.onreadystatechange = function () {
  873. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  874. item = getItem(doc, obj);
  875. if (item.funs.length > 0) {
  876. item.ready = 1;
  877. for (var fi; (fi = item.funs.pop());) {
  878. fi();
  879. }
  880. }
  881. element.onload = element.onreadystatechange = null;
  882. }
  883. };
  884. element.onerror = function () {
  885. throw Error(
  886. "The load " +
  887. (obj.href || obj.src) +
  888. " fails,check the url settings of file neditor.config.js "
  889. );
  890. };
  891. doc.getElementsByTagName("head")[0].appendChild(element);
  892. };
  893. })(),
  894. /**
  895. * 判断obj对象是否为空
  896. * @method isEmptyObject
  897. * @param { * } obj 需要判断的对象
  898. * @remind 如果判断的对象是NULL, 将直接返回true, 如果是数组且为空, 返回true, 如果是字符串, 且字符串为空,
  899. * 返回true, 如果是普通对象, 且该对象没有任何实例属性, 返回true
  900. * @return { Boolean } 对象是否为空
  901. * @example
  902. * ```javascript
  903. *
  904. * //output: true
  905. * console.log( UE.utils.isEmptyObject( {} ) );
  906. *
  907. * //output: true
  908. * console.log( UE.utils.isEmptyObject( [] ) );
  909. *
  910. * //output: true
  911. * console.log( UE.utils.isEmptyObject( "" ) );
  912. *
  913. * //output: false
  914. * console.log( UE.utils.isEmptyObject( { key: 1 } ) );
  915. *
  916. * //output: false
  917. * console.log( UE.utils.isEmptyObject( [1] ) );
  918. *
  919. * //output: false
  920. * console.log( UE.utils.isEmptyObject( "1" ) );
  921. *
  922. * ```
  923. */
  924. isEmptyObject: function (obj) {
  925. if (obj == null) return true;
  926. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
  927. for (var key in obj) if (obj.hasOwnProperty(key)) return false;
  928. return true;
  929. },
  930. /**
  931. * 把rgb格式的颜色值转换成16进制格式
  932. * @method fixColor
  933. * @param { String } rgb格式的颜色值
  934. * @param { String }
  935. * @example
  936. * rgb(255,255,255) => "#ffffff"
  937. */
  938. fixColor: function (name, value) {
  939. if (/color/i.test(name) && /rgba?/.test(value)) {
  940. var array = value.split(",");
  941. if (array.length > 3) return "";
  942. value = "#";
  943. for (var i = 0, color; (color = array[i++]);) {
  944. color = parseInt(color.replace(/[^\d]/gi, ""), 10).toString(16);
  945. value += color.length == 1 ? "0" + color : color;
  946. }
  947. value = value.toUpperCase();
  948. }
  949. return value;
  950. },
  951. /**
  952. * 只针对border,padding,margin做了处理,因为性能问题
  953. * @public
  954. * @function
  955. * @param {String} val style字符串
  956. */
  957. optCss: function (val) {
  958. var padding, margin, border;
  959. val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function (
  960. str,
  961. key,
  962. name,
  963. val
  964. ) {
  965. if (val.split(" ").length == 1) {
  966. switch (key) {
  967. case "padding":
  968. !padding && (padding = {});
  969. padding[name] = val;
  970. return "";
  971. case "margin":
  972. !margin && (margin = {});
  973. margin[name] = val;
  974. return "";
  975. case "border":
  976. return val == "initial" ? "" : str;
  977. }
  978. }
  979. return str;
  980. });
  981. function opt(obj, name) {
  982. if (!obj) {
  983. return "";
  984. }
  985. var t = obj.top,
  986. b = obj.bottom,
  987. l = obj.left,
  988. r = obj.right,
  989. val = "";
  990. if (!t || !l || !b || !r) {
  991. for (var p in obj) {
  992. val += ";" + name + "-" + p + ":" + obj[p] + ";";
  993. }
  994. } else {
  995. val +=
  996. ";" +
  997. name +
  998. ":" +
  999. (t == b && b == l && l == r
  1000. ? t
  1001. : t == b && l == r
  1002. ? t + " " + l
  1003. : l == r
  1004. ? t + " " + l + " " + b
  1005. : t + " " + r + " " + b + " " + l) +
  1006. ";";
  1007. }
  1008. return val;
  1009. }
  1010. val += opt(padding, "padding") + opt(margin, "margin");
  1011. return val
  1012. .replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, "")
  1013. .replace(/;([ \n\r\t]+)|\1;/g, ";")
  1014. .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function (a, b) {
  1015. return b ? b + ";;" : ";";
  1016. });
  1017. },
  1018. /**
  1019. * 克隆对象
  1020. * @method clone
  1021. * @param { Object } source 源对象
  1022. * @return { Object } source的一个副本
  1023. */
  1024. /**
  1025. * 深度克隆对象,将source的属性克隆到target对象, 会覆盖target重名的属性。
  1026. * @method clone
  1027. * @param { Object } source 源对象
  1028. * @param { Object } target 目标对象
  1029. * @return { Object } 附加了source对象所有属性的target对象
  1030. */
  1031. clone: function (source, target) {
  1032. var tmp;
  1033. target = target || {};
  1034. for (var i in source) {
  1035. if (source.hasOwnProperty(i)) {
  1036. tmp = source[i];
  1037. if (typeof tmp == "object") {
  1038. target[i] = utils.isArray(tmp) ? [] : {};
  1039. utils.clone(source[i], target[i]);
  1040. } else {
  1041. target[i] = tmp;
  1042. }
  1043. }
  1044. }
  1045. return target;
  1046. },
  1047. /**
  1048. * 把cm/pt为单位的值转换为px为单位的值
  1049. * @method transUnitToPx
  1050. * @param { String } 待转换的带单位的字符串
  1051. * @return { String } 转换为px为计量单位的值的字符串
  1052. * @example
  1053. * ```javascript
  1054. *
  1055. * //output: 500px
  1056. * console.log( UE.utils.transUnitToPx( '20cm' ) );
  1057. *
  1058. * //output: 27px
  1059. * console.log( UE.utils.transUnitToPx( '20pt' ) );
  1060. *
  1061. * ```
  1062. */
  1063. transUnitToPx: function (val) {
  1064. if (!/(pt|cm)/.test(val)) {
  1065. return val;
  1066. }
  1067. var unit;
  1068. val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
  1069. val = v;
  1070. unit = u;
  1071. });
  1072. switch (unit) {
  1073. case "cm":
  1074. val = parseFloat(val) * 25;
  1075. break;
  1076. case "pt":
  1077. val = Math.round(parseFloat(val) * 96 / 72);
  1078. }
  1079. return val + (val ? "px" : "");
  1080. },
  1081. /**
  1082. * 在dom树ready之后执行给定的回调函数
  1083. * @method domReady
  1084. * @remind 如果在执行该方法的时候, dom树已经ready, 那么回调函数将立刻执行
  1085. * @param { Function } fn dom树ready之后的回调函数
  1086. * @example
  1087. * ```javascript
  1088. *
  1089. * UE.utils.domReady( function () {
  1090. *
  1091. * console.log('123');
  1092. *
  1093. * } );
  1094. *
  1095. * ```
  1096. */
  1097. domReady: (function () {
  1098. var fnArr = [];
  1099. function doReady(doc) {
  1100. //确保onready只执行一次
  1101. doc.isReady = true;
  1102. for (var ci; (ci = fnArr.pop()); ci()) {
  1103. }
  1104. }
  1105. return function (onready, win) {
  1106. win = win || window;
  1107. var doc = win.document;
  1108. onready && fnArr.push(onready);
  1109. if (doc.readyState === "complete") {
  1110. doReady(doc);
  1111. } else {
  1112. doc.isReady && doReady(doc);
  1113. if (browser.ie && browser.version != 11) {
  1114. (function () {
  1115. if (doc.isReady) return;
  1116. try {
  1117. doc.documentElement.doScroll("left");
  1118. } catch (error) {
  1119. setTimeout(arguments.callee, 0);
  1120. return;
  1121. }
  1122. doReady(doc);
  1123. })();
  1124. win.attachEvent("onload", function () {
  1125. doReady(doc);
  1126. });
  1127. } else {
  1128. doc.addEventListener(
  1129. "DOMContentLoaded",
  1130. function () {
  1131. doc.removeEventListener(
  1132. "DOMContentLoaded",
  1133. arguments.callee,
  1134. false
  1135. );
  1136. doReady(doc);
  1137. },
  1138. false
  1139. );
  1140. win.addEventListener(
  1141. "load",
  1142. function () {
  1143. doReady(doc);
  1144. },
  1145. false
  1146. );
  1147. }
  1148. }
  1149. };
  1150. })(),
  1151. /**
  1152. * 动态添加css样式
  1153. * @method cssRule
  1154. * @param { String } 节点名称
  1155. * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  1156. * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  1157. * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  1158. * @grammar UE.utils.cssRule('body',document) => 返回指定key的样式,并且指定是哪个document
  1159. * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  1160. */
  1161. cssRule: browser.ie && browser.version != 11
  1162. ? function (key, style, doc) {
  1163. var indexList, index;
  1164. if (
  1165. style === undefined ||
  1166. (style && style.nodeType && style.nodeType == 9)
  1167. ) {
  1168. //获取样式
  1169. doc = style && style.nodeType && style.nodeType == 9
  1170. ? style
  1171. : doc || document;
  1172. indexList = doc.indexList || (doc.indexList = {});
  1173. index = indexList[key];
  1174. if (index !== undefined) {
  1175. return doc.styleSheets[index].cssText;
  1176. }
  1177. return undefined;
  1178. }
  1179. doc = doc || document;
  1180. indexList = doc.indexList || (doc.indexList = {});
  1181. index = indexList[key];
  1182. //清除样式
  1183. if (style === "") {
  1184. if (index !== undefined) {
  1185. doc.styleSheets[index].cssText = "";
  1186. delete indexList[key];
  1187. return true;
  1188. }
  1189. return false;
  1190. }
  1191. //添加样式
  1192. if (index !== undefined) {
  1193. sheetStyle = doc.styleSheets[index];
  1194. } else {
  1195. sheetStyle = doc.createStyleSheet(
  1196. "",
  1197. (index = doc.styleSheets.length)
  1198. );
  1199. indexList[key] = index;
  1200. }
  1201. sheetStyle.cssText = style;
  1202. }
  1203. : function (key, style, doc) {
  1204. var head, node;
  1205. if (
  1206. style === undefined ||
  1207. (style && style.nodeType && style.nodeType == 9)
  1208. ) {
  1209. //获取样式
  1210. doc = style && style.nodeType && style.nodeType == 9
  1211. ? style
  1212. : doc || document;
  1213. node = doc.getElementById(key);
  1214. return node ? node.innerHTML : undefined;
  1215. }
  1216. doc = doc || document;
  1217. node = doc.getElementById(key);
  1218. //清除样式
  1219. if (style === "") {
  1220. if (node) {
  1221. node.parentNode.removeChild(node);
  1222. return true;
  1223. }
  1224. return false;
  1225. }
  1226. //添加样式
  1227. if (node) {
  1228. node.innerHTML = style;
  1229. } else {
  1230. node = doc.createElement("style");
  1231. node.id = key;
  1232. node.innerHTML = style;
  1233. doc.getElementsByTagName("head")[0].appendChild(node);
  1234. }
  1235. },
  1236. sort: function (array, compareFn) {
  1237. compareFn =
  1238. compareFn ||
  1239. function (item1, item2) {
  1240. return item1.localeCompare(item2);
  1241. };
  1242. for (var i = 0, len = array.length; i < len; i++) {
  1243. for (var j = i, length = array.length; j < length; j++) {
  1244. if (compareFn(array[i], array[j]) > 0) {
  1245. var t = array[i];
  1246. array[i] = array[j];
  1247. array[j] = t;
  1248. }
  1249. }
  1250. }
  1251. return array;
  1252. },
  1253. serializeParam: function (json) {
  1254. var strArr = [];
  1255. for (var i in json) {
  1256. //忽略默认的几个参数
  1257. if (i == "method" || i == "timeout" || i == "async") continue;
  1258. //传递过来的对象和函数不在提交之列
  1259. if (
  1260. !(
  1261. (typeof json[i]).toLowerCase() == "function" ||
  1262. (typeof json[i]).toLowerCase() == "object"
  1263. )
  1264. ) {
  1265. strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]));
  1266. } else if (utils.isArray(json[i])) {
  1267. //支持传数组内容
  1268. for (var j = 0; j < json[i].length; j++) {
  1269. strArr.push(
  1270. encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])
  1271. );
  1272. }
  1273. }
  1274. }
  1275. return strArr.join("&");
  1276. },
  1277. formatUrl: function (url) {
  1278. var u = url.replace(/&&/g, "&");
  1279. u = u.replace(/\?&/g, "?");
  1280. u = u.replace(/&$/g, "");
  1281. u = u.replace(/&#/g, "#");
  1282. u = u.replace(/&+/g, "&");
  1283. return u;
  1284. },
  1285. isCrossDomainUrl: function (url) {
  1286. var a = document.createElement("a");
  1287. a.href = url;
  1288. if (browser.ie) {
  1289. a.href = a.href;
  1290. }
  1291. return !(
  1292. a.protocol == location.protocol &&
  1293. a.hostname == location.hostname &&
  1294. (a.port == location.port ||
  1295. (a.port == "80" && location.port == "") ||
  1296. (a.port == "" && location.port == "80"))
  1297. );
  1298. },
  1299. clearEmptyAttrs: function (obj) {
  1300. for (var p in obj) {
  1301. if (obj[p] === "") {
  1302. delete obj[p];
  1303. }
  1304. }
  1305. return obj;
  1306. },
  1307. str2json: function (s) {
  1308. if (!utils.isString(s)) return null;
  1309. if (window.JSON) {
  1310. return JSON.parse(s);
  1311. } else {
  1312. return new Function("return " + utils.trim(s || ""))();
  1313. }
  1314. },
  1315. json2str: (function () {
  1316. if (window.JSON) {
  1317. return JSON.stringify;
  1318. } else {
  1319. var escapeMap = {
  1320. "\b": "\\b",
  1321. "\t": "\\t",
  1322. "\n": "\\n",
  1323. "\f": "\\f",
  1324. "\r": "\\r",
  1325. '"': '\\"',
  1326. "\\": "\\\\"
  1327. };
  1328. function encodeString(source) {
  1329. if (/["\\\x00-\x1f]/.test(source)) {
  1330. source = source.replace(/["\\\x00-\x1f]/g, function (match) {
  1331. var c = escapeMap[match];
  1332. if (c) {
  1333. return c;
  1334. }
  1335. c = match.charCodeAt();
  1336. return (
  1337. "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16)
  1338. );
  1339. });
  1340. }
  1341. return '"' + source + '"';
  1342. }
  1343. function encodeArray(source) {
  1344. var result = ["["],
  1345. l = source.length,
  1346. preComma,
  1347. i,
  1348. item;
  1349. for (i = 0; i < l; i++) {
  1350. item = source[i];
  1351. switch (typeof item) {
  1352. case "undefined":
  1353. case "function":
  1354. case "unknown":
  1355. break;
  1356. default:
  1357. if (preComma) {
  1358. result.push(",");
  1359. }
  1360. result.push(utils.json2str(item));
  1361. preComma = 1;
  1362. }
  1363. }
  1364. result.push("]");
  1365. return result.join("");
  1366. }
  1367. function pad(source) {
  1368. return source < 10 ? "0" + source : source;
  1369. }
  1370. function encodeDate(source) {
  1371. return (
  1372. '"' +
  1373. source.getFullYear() +
  1374. "-" +
  1375. pad(source.getMonth() + 1) +
  1376. "-" +
  1377. pad(source.getDate()) +
  1378. "T" +
  1379. pad(source.getHours()) +
  1380. ":" +
  1381. pad(source.getMinutes()) +
  1382. ":" +
  1383. pad(source.getSeconds()) +
  1384. '"'
  1385. );
  1386. }
  1387. return function (value) {
  1388. switch (typeof value) {
  1389. case "undefined":
  1390. return "undefined";
  1391. case "number":
  1392. return isFinite(value) ? String(value) : "null";
  1393. case "string":
  1394. return encodeString(value);
  1395. case "boolean":
  1396. return String(value);
  1397. default:
  1398. if (value === null) {
  1399. return "null";
  1400. } else if (utils.isArray(value)) {
  1401. return encodeArray(value);
  1402. } else if (utils.isDate(value)) {
  1403. return encodeDate(value);
  1404. } else {
  1405. var result = ["{"],
  1406. encode = utils.json2str,
  1407. preComma,
  1408. item;
  1409. for (var key in value) {
  1410. if (Object.prototype.hasOwnProperty.call(value, key)) {
  1411. item = value[key];
  1412. switch (typeof item) {
  1413. case "undefined":
  1414. case "unknown":
  1415. case "function":
  1416. break;
  1417. default:
  1418. if (preComma) {
  1419. result.push(",");
  1420. }
  1421. preComma = 1;
  1422. result.push(encode(key) + ":" + encode(item));
  1423. }
  1424. }
  1425. }
  1426. result.push("}");
  1427. return result.join("");
  1428. }
  1429. }
  1430. };
  1431. }
  1432. })()
  1433. });
  1434. /**
  1435. * 判断给定的对象是否是字符串
  1436. * @method isString
  1437. * @param { * } object 需要判断的对象
  1438. * @return { Boolean } 给定的对象是否是字符串
  1439. */
  1440. /**
  1441. * 判断给定的对象是否是数组
  1442. * @method isArray
  1443. * @param { * } object 需要判断的对象
  1444. * @return { Boolean } 给定的对象是否是数组
  1445. */
  1446. /**
  1447. * 判断给定的对象是否是一个Function
  1448. * @method isFunction
  1449. * @param { * } object 需要判断的对象
  1450. * @return { Boolean } 给定的对象是否是Function
  1451. */
  1452. /**
  1453. * 判断给定的对象是否是Number
  1454. * @method isNumber
  1455. * @param { * } object 需要判断的对象
  1456. * @return { Boolean } 给定的对象是否是Number
  1457. */
  1458. /**
  1459. * 判断给定的对象是否是一个正则表达式
  1460. * @method isRegExp
  1461. * @param { * } object 需要判断的对象
  1462. * @return { Boolean } 给定的对象是否是正则表达式
  1463. */
  1464. /**
  1465. * 判断给定的对象是否是一个普通对象
  1466. * @method isObject
  1467. * @param { * } object 需要判断的对象
  1468. * @return { Boolean } 给定的对象是否是普通对象
  1469. */
  1470. utils.each(
  1471. ["String", "Function", "Array", "Number", "RegExp", "Object", "Date"],
  1472. function (v) {
  1473. UE.utils["is" + v] = function (obj) {
  1474. return Object.prototype.toString.apply(obj) == "[object " + v + "]";
  1475. };
  1476. }
  1477. );
  1478. // core/EventBase.js
  1479. /**
  1480. * UE采用的事件基类
  1481. * @file
  1482. * @module UE
  1483. * @class EventBase
  1484. * @since 1.2.6.1
  1485. */
  1486. /**
  1487. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  1488. * @unfile
  1489. * @module UE
  1490. */
  1491. /**
  1492. * UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
  1493. * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
  1494. * @unfile
  1495. * @module UE
  1496. * @class EventBase
  1497. */
  1498. /**
  1499. * 通过此构造器,子类可以继承EventBase获取事件监听的方法
  1500. * @constructor
  1501. * @example
  1502. * ```javascript
  1503. * UE.EventBase.call(editor);
  1504. * ```
  1505. */
  1506. var EventBase = (UE.EventBase = function () {
  1507. });
  1508. EventBase.prototype = {
  1509. /**
  1510. * 注册事件监听器
  1511. * @method addListener
  1512. * @param { String } types 监听的事件名称,同时监听多个事件使用空格分隔
  1513. * @param { Function } fn 监听的事件被触发时,会执行该回调函数
  1514. * @waining 事件被触发时,监听的函数假如返回的值恒等于true,回调函数的队列中后面的函数将不执行
  1515. * @example
  1516. * ```javascript
  1517. * editor.addListener('selectionchange',function(){
  1518. * console.log("选区已经变化!");
  1519. * })
  1520. * editor.addListener('beforegetcontent aftergetcontent',function(type){
  1521. * if(type == 'beforegetcontent'){
  1522. * //do something
  1523. * }else{
  1524. * //do something
  1525. * }
  1526. * console.log(this.getContent) // this是注册的事件的编辑器实例
  1527. * })
  1528. * ```
  1529. * @see UE.EventBase:fireEvent(String)
  1530. */
  1531. addListener: function (types, listener) {
  1532. types = utils.trim(types).split(/\s+/);
  1533. for (var i = 0, ti; (ti = types[i++]);) {
  1534. getListener(this, ti, true).push(listener);
  1535. }
  1536. },
  1537. on: function (types, listener) {
  1538. return this.addListener(types, listener);
  1539. },
  1540. off: function (types, listener) {
  1541. return this.removeListener(types, listener);
  1542. },
  1543. trigger: function () {
  1544. return this.fireEvent.apply(this, arguments);
  1545. },
  1546. /**
  1547. * 移除事件监听器
  1548. * @method removeListener
  1549. * @param { String } types 移除的事件名称,同时移除多个事件使用空格分隔
  1550. * @param { Function } fn 移除监听事件的函数引用
  1551. * @example
  1552. * ```javascript
  1553. * //changeCallback为方法体
  1554. * editor.removeListener("selectionchange",changeCallback);
  1555. * ```
  1556. */
  1557. removeListener: function (types, listener) {
  1558. types = utils.trim(types).split(/\s+/);
  1559. for (var i = 0, ti; (ti = types[i++]);) {
  1560. utils.removeItem(getListener(this, ti) || [], listener);
  1561. }
  1562. },
  1563. /**
  1564. * 触发事件
  1565. * @method fireEvent
  1566. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1567. * @remind 该方法会触发addListener
  1568. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1569. * @example
  1570. * ```javascript
  1571. * editor.fireEvent("selectionchange");
  1572. * ```
  1573. */
  1574. /**
  1575. * 触发事件
  1576. * @method fireEvent
  1577. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1578. * @param { *... } options 可选参数,可以传入一个或多个参数,会传给事件触发的回调函数
  1579. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1580. * @example
  1581. * ```javascript
  1582. *
  1583. * editor.addListener( "selectionchange", function ( type, arg1, arg2 ) {
  1584. *
  1585. * console.log( arg1 + " " + arg2 );
  1586. *
  1587. * } );
  1588. *
  1589. * //触发selectionchange事件, 会执行上面的事件监听器
  1590. * //output: Hello World
  1591. * editor.fireEvent("selectionchange", "Hello", "World");
  1592. * ```
  1593. */
  1594. fireEvent: function () {
  1595. var types = arguments[0];
  1596. types = utils.trim(types).split(" ");
  1597. for (var i = 0, ti; (ti = types[i++]);) {
  1598. var listeners = getListener(this, ti),
  1599. r,
  1600. t,
  1601. k;
  1602. if (listeners) {
  1603. k = listeners.length;
  1604. while (k--) {
  1605. if (!listeners[k]) continue;
  1606. t = listeners[k].apply(this, arguments);
  1607. if (t === true) {
  1608. return t;
  1609. }
  1610. if (t !== undefined) {
  1611. r = t;
  1612. }
  1613. }
  1614. }
  1615. if ((t = this["on" + ti.toLowerCase()])) {
  1616. r = t.apply(this, arguments);
  1617. }
  1618. }
  1619. return r;
  1620. }
  1621. };
  1622. /**
  1623. * 获得对象所拥有监听类型的所有监听器
  1624. * @unfile
  1625. * @module UE
  1626. * @since 1.2.6.1
  1627. * @method getListener
  1628. * @public
  1629. * @param { Object } obj 查询监听器的对象
  1630. * @param { String } type 事件类型
  1631. * @param { Boolean } force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  1632. * @return { Array } 监听器数组
  1633. */
  1634. function getListener(obj, type, force) {
  1635. var allListeners;
  1636. type = type.toLowerCase();
  1637. return (
  1638. (allListeners =
  1639. obj.__allListeners || (force && (obj.__allListeners = {}))) &&
  1640. (allListeners[type] || (force && (allListeners[type] = [])))
  1641. );
  1642. }
  1643. // core/dtd.js
  1644. ///import editor.js
  1645. ///import core/dom/dom.js
  1646. ///import core/utils.js
  1647. /**
  1648. * dtd html语义化的体现类
  1649. * @constructor
  1650. * @namespace dtd
  1651. */
  1652. var dtd = (dom.dtd = (function () {
  1653. function _(s) {
  1654. for (var k in s) {
  1655. s[k.toUpperCase()] = s[k];
  1656. }
  1657. return s;
  1658. }
  1659. var X = utils.extend2;
  1660. var A = _({isindex: 1, fieldset: 1}),
  1661. B = _({input: 1, button: 1, select: 1, textarea: 1, label: 1}),
  1662. C = X(_({a: 1}), B),
  1663. D = X({iframe: 1}, C),
  1664. E = _({
  1665. hr: 1,
  1666. ul: 1,
  1667. menu: 1,
  1668. div: 1,
  1669. blockquote: 1,
  1670. noscript: 1,
  1671. table: 1,
  1672. center: 1,
  1673. address: 1,
  1674. dir: 1,
  1675. pre: 1,
  1676. h5: 1,
  1677. dl: 1,
  1678. h4: 1,
  1679. noframes: 1,
  1680. h6: 1,
  1681. ol: 1,
  1682. h1: 1,
  1683. h3: 1,
  1684. h2: 1
  1685. }),
  1686. F = _({ins: 1, del: 1, script: 1, style: 1}),
  1687. G = X(
  1688. _({
  1689. mark: 1,
  1690. b: 1,
  1691. acronym: 1,
  1692. bdo: 1,
  1693. var: 1,
  1694. "#": 1,
  1695. abbr: 1,
  1696. code: 1,
  1697. br: 1,
  1698. i: 1,
  1699. cite: 1,
  1700. kbd: 1,
  1701. u: 1,
  1702. strike: 1,
  1703. s: 1,
  1704. tt: 1,
  1705. strong: 1,
  1706. q: 1,
  1707. samp: 1,
  1708. em: 1,
  1709. dfn: 1,
  1710. span: 1
  1711. }),
  1712. F
  1713. ),
  1714. H = X(
  1715. _({
  1716. sub: 1,
  1717. img: 1,
  1718. embed: 1,
  1719. object: 1,
  1720. sup: 1,
  1721. basefont: 1,
  1722. map: 1,
  1723. applet: 1,
  1724. font: 1,
  1725. big: 1,
  1726. small: 1
  1727. }),
  1728. G
  1729. ),
  1730. I = X(_({p: 1}), H),
  1731. J = X(_({iframe: 1}), H, B),
  1732. K = _({
  1733. img: 1,
  1734. embed: 1,
  1735. noscript: 1,
  1736. br: 1,
  1737. kbd: 1,
  1738. center: 1,
  1739. button: 1,
  1740. basefont: 1,
  1741. h5: 1,
  1742. h4: 1,
  1743. samp: 1,
  1744. h6: 1,
  1745. ol: 1,
  1746. h1: 1,
  1747. h3: 1,
  1748. h2: 1,
  1749. form: 1,
  1750. font: 1,
  1751. "#": 1,
  1752. select: 1,
  1753. menu: 1,
  1754. ins: 1,
  1755. abbr: 1,
  1756. label: 1,
  1757. code: 1,
  1758. table: 1,
  1759. script: 1,
  1760. cite: 1,
  1761. input: 1,
  1762. iframe: 1,
  1763. strong: 1,
  1764. textarea: 1,
  1765. noframes: 1,
  1766. big: 1,
  1767. small: 1,
  1768. span: 1,
  1769. hr: 1,
  1770. sub: 1,
  1771. bdo: 1,
  1772. var: 1,
  1773. div: 1,
  1774. object: 1,
  1775. sup: 1,
  1776. strike: 1,
  1777. dir: 1,
  1778. map: 1,
  1779. dl: 1,
  1780. applet: 1,
  1781. del: 1,
  1782. isindex: 1,
  1783. fieldset: 1,
  1784. ul: 1,
  1785. b: 1,
  1786. acronym: 1,
  1787. a: 1,
  1788. blockquote: 1,
  1789. i: 1,
  1790. u: 1,
  1791. s: 1,
  1792. tt: 1,
  1793. address: 1,
  1794. q: 1,
  1795. pre: 1,
  1796. p: 1,
  1797. em: 1,
  1798. dfn: 1
  1799. }),
  1800. L = X(_({a: 0}), J), //a不能被切开,所以把他
  1801. M = _({tr: 1}),
  1802. N = _({"#": 1}),
  1803. O = X(_({param: 1}), K),
  1804. P = X(_({form: 1}), A, D, E, I),
  1805. Q = _({li: 1, ol: 1, ul: 1}),
  1806. R = _({style: 1, script: 1}),
  1807. S = _({base: 1, link: 1, meta: 1, title: 1}),
  1808. T = X(S, R),
  1809. U = _({head: 1, body: 1}),
  1810. V = _({html: 1});
  1811. var block = _({
  1812. address: 1,
  1813. blockquote: 1,
  1814. center: 1,
  1815. dir: 1,
  1816. div: 1,
  1817. dl: 1,
  1818. fieldset: 1,
  1819. form: 1,
  1820. h1: 1,
  1821. h2: 1,
  1822. h3: 1,
  1823. h4: 1,
  1824. h5: 1,
  1825. h6: 1,
  1826. hr: 1,
  1827. isindex: 1,
  1828. menu: 1,
  1829. noframes: 1,
  1830. ol: 1,
  1831. p: 1,
  1832. pre: 1,
  1833. table: 1,
  1834. ul: 1
  1835. }),
  1836. empty = _({
  1837. area: 1,
  1838. base: 1,
  1839. basefont: 1,
  1840. br: 1,
  1841. col: 1,
  1842. command: 1,
  1843. dialog: 1,
  1844. embed: 1,
  1845. hr: 1,
  1846. img: 1,
  1847. input: 1,
  1848. isindex: 1,
  1849. keygen: 1,
  1850. link: 1,
  1851. meta: 1,
  1852. param: 1,
  1853. source: 1,
  1854. track: 1,
  1855. wbr: 1
  1856. });
  1857. return _({
  1858. // $ 表示自定的属性
  1859. // body外的元素列表.
  1860. $nonBodyContent: X(V, U, S),
  1861. //块结构元素列表
  1862. $block: block,
  1863. //内联元素列表
  1864. $inline: L,
  1865. $inlineWithA: X(_({a: 1}), L),
  1866. $body: X(_({script: 1, style: 1}), block),
  1867. $cdata: _({script: 1, style: 1}),
  1868. //自闭和元素
  1869. $empty: empty,
  1870. //不是自闭合,但不能让range选中里边
  1871. $nonChild: _({iframe: 1, textarea: 1}),
  1872. //列表元素列表
  1873. $listItem: _({dd: 1, dt: 1, li: 1}),
  1874. //列表根元素列表
  1875. $list: _({ul: 1, ol: 1, dl: 1}),
  1876. //不能认为是空的元素
  1877. $isNotEmpty: _({
  1878. table: 1,
  1879. ul: 1,
  1880. ol: 1,
  1881. dl: 1,
  1882. iframe: 1,
  1883. area: 1,
  1884. base: 1,
  1885. col: 1,
  1886. hr: 1,
  1887. img: 1,
  1888. embed: 1,
  1889. input: 1,
  1890. textarea: 1,
  1891. link: 1,
  1892. meta: 1,
  1893. param: 1,
  1894. h1: 1,
  1895. h2: 1,
  1896. h3: 1,
  1897. h4: 1,
  1898. h5: 1,
  1899. h6: 1
  1900. }),
  1901. //如果没有子节点就可以删除的元素列表,像span,a
  1902. $removeEmpty: _({
  1903. a: 1,
  1904. abbr: 1,
  1905. acronym: 1,
  1906. address: 1,
  1907. b: 1,
  1908. bdo: 1,
  1909. big: 1,
  1910. cite: 1,
  1911. code: 1,
  1912. del: 1,
  1913. dfn: 1,
  1914. em: 1,
  1915. font: 1,
  1916. i: 1,
  1917. ins: 1,
  1918. label: 1,
  1919. kbd: 1,
  1920. q: 1,
  1921. s: 1,
  1922. samp: 1,
  1923. small: 1,
  1924. span: 1,
  1925. strike: 1,
  1926. strong: 1,
  1927. sub: 1,
  1928. sup: 1,
  1929. tt: 1,
  1930. u: 1,
  1931. var: 1
  1932. }),
  1933. $removeEmptyBlock: _({p: 1, div: 1}),
  1934. //在table元素里的元素列表
  1935. $tableContent: _({
  1936. caption: 1,
  1937. col: 1,
  1938. colgroup: 1,
  1939. tbody: 1,
  1940. td: 1,
  1941. tfoot: 1,
  1942. th: 1,
  1943. thead: 1,
  1944. tr: 1,
  1945. table: 1
  1946. }),
  1947. //不转换的标签
  1948. $notTransContent: _({pre: 1, script: 1, style: 1, textarea: 1}),
  1949. html: U,
  1950. head: T,
  1951. style: N,
  1952. script: N,
  1953. body: P,
  1954. base: {},
  1955. link: {},
  1956. meta: {},
  1957. title: N,
  1958. col: {},
  1959. tr: _({td: 1, th: 1}),
  1960. img: {},
  1961. embed: {},
  1962. colgroup: _({thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1}),
  1963. noscript: P,
  1964. td: P,
  1965. br: {},
  1966. th: P,
  1967. center: P,
  1968. kbd: L,
  1969. button: X(I, E),
  1970. basefont: {},
  1971. h5: L,
  1972. h4: L,
  1973. samp: L,
  1974. h6: L,
  1975. ol: Q,
  1976. h1: L,
  1977. h3: L,
  1978. option: N,
  1979. h2: L,
  1980. form: X(A, D, E, I),
  1981. select: _({optgroup: 1, option: 1}),
  1982. font: L,
  1983. ins: L,
  1984. menu: Q,
  1985. abbr: L,
  1986. label: L,
  1987. table: _({
  1988. thead: 1,
  1989. col: 1,
  1990. tbody: 1,
  1991. tr: 1,
  1992. colgroup: 1,
  1993. caption: 1,
  1994. tfoot: 1
  1995. }),
  1996. code: L,
  1997. tfoot: M,
  1998. cite: L,
  1999. li: P,
  2000. input: {},
  2001. iframe: P,
  2002. strong: L,
  2003. textarea: N,
  2004. noframes: P,
  2005. big: L,
  2006. small: L,
  2007. //trace:
  2008. span: _({
  2009. "#": 1,
  2010. br: 1,
  2011. b: 1,
  2012. strong: 1,
  2013. u: 1,
  2014. i: 1,
  2015. em: 1,
  2016. sub: 1,
  2017. sup: 1,
  2018. strike: 1,
  2019. span: 1
  2020. }),
  2021. hr: L,
  2022. dt: L,
  2023. sub: L,
  2024. optgroup: _({option: 1}),
  2025. param: {},
  2026. bdo: L,
  2027. var: L,
  2028. div: P,
  2029. object: O,
  2030. sup: L,
  2031. dd: P,
  2032. strike: L,
  2033. area: {},
  2034. dir: Q,
  2035. map: X(_({area: 1, form: 1, p: 1}), A, F, E),
  2036. applet: O,
  2037. dl: _({dt: 1, dd: 1}),
  2038. del: L,
  2039. isindex: {},
  2040. fieldset: X(_({legend: 1}), K),
  2041. thead: M,
  2042. ul: Q,
  2043. acronym: L,
  2044. b: L,
  2045. a: X(_({a: 1}), J),
  2046. blockquote: X(_({td: 1, tr: 1, tbody: 1, li: 1}), P),
  2047. caption: L,
  2048. i: L,
  2049. u: L,
  2050. tbody: M,
  2051. s: L,
  2052. address: X(D, I),
  2053. tt: L,
  2054. legend: L,
  2055. q: L,
  2056. pre: X(G, C),
  2057. p: X(_({a: 1}), L),
  2058. em: L,
  2059. dfn: L,
  2060. mark: L
  2061. });
  2062. })());
  2063. // core/domUtils.js
  2064. /**
  2065. * Dom操作工具包
  2066. * @file
  2067. * @module UE.dom.domUtils
  2068. * @since 1.2.6.1
  2069. */
  2070. /**
  2071. * Dom操作工具包
  2072. * @unfile
  2073. * @module UE.dom.domUtils
  2074. */
  2075. function getDomNode(node, start, ltr, startFromChild, fn, guard) {
  2076. var tmpNode = startFromChild && node[start],
  2077. parent;
  2078. !tmpNode && (tmpNode = node[ltr]);
  2079. while (!tmpNode && (parent = (parent || node).parentNode)) {
  2080. if (parent.tagName == "BODY" || (guard && !guard(parent))) {
  2081. return null;
  2082. }
  2083. tmpNode = parent[ltr];
  2084. }
  2085. if (tmpNode && fn && !fn(tmpNode)) {
  2086. return getDomNode(tmpNode, start, ltr, false, fn);
  2087. }
  2088. return tmpNode;
  2089. }
  2090. var attrFix = ie && browser.version < 9
  2091. ? {
  2092. tabindex: "tabIndex",
  2093. readonly: "readOnly",
  2094. for: "htmlFor",
  2095. class: "className",
  2096. maxlength: "maxLength",
  2097. cellspacing: "cellSpacing",
  2098. cellpadding: "cellPadding",
  2099. rowspan: "rowSpan",
  2100. colspan: "colSpan",
  2101. usemap: "useMap",
  2102. frameborder: "frameBorder"
  2103. }
  2104. : {
  2105. tabindex: "tabIndex",
  2106. readonly: "readOnly"
  2107. },
  2108. styleBlock = utils.listToMap([
  2109. "-webkit-box",
  2110. "-moz-box",
  2111. "block",
  2112. "list-item",
  2113. "table",
  2114. "table-row-group",
  2115. "table-header-group",
  2116. "table-footer-group",
  2117. "table-row",
  2118. "table-column-group",
  2119. "table-column",
  2120. "table-cell",
  2121. "table-caption"
  2122. ]);
  2123. var domUtils = (dom.domUtils = {
  2124. //节点常量
  2125. NODE_ELEMENT: 1,
  2126. NODE_DOCUMENT: 9,
  2127. NODE_TEXT: 3,
  2128. NODE_COMMENT: 8,
  2129. NODE_DOCUMENT_FRAGMENT: 11,
  2130. //位置关系
  2131. POSITION_IDENTICAL: 0,
  2132. POSITION_DISCONNECTED: 1,
  2133. POSITION_FOLLOWING: 2,
  2134. POSITION_PRECEDING: 4,
  2135. POSITION_IS_CONTAINED: 8,
  2136. POSITION_CONTAINS: 16,
  2137. //ie6使用其他的会有一段空白出现
  2138. fillChar: ie && browser.version == "6" ? "\ufeff" : "\u200B",
  2139. //-------------------------Node部分--------------------------------
  2140. keys: {
  2141. /*Backspace*/ 8: 1,
  2142. /*Delete*/ 46: 1,
  2143. /*Shift*/ 16: 1,
  2144. /*Ctrl*/ 17: 1,
  2145. /*Alt*/ 18: 1,
  2146. 37: 1,
  2147. 38: 1,
  2148. 39: 1,
  2149. 40: 1,
  2150. 13: 1 /*enter*/
  2151. },
  2152. /**
  2153. * 获取节点A相对于节点B的位置关系
  2154. * @method getPosition
  2155. * @param { Node } nodeA 需要查询位置关系的节点A
  2156. * @param { Node } nodeB 需要查询位置关系的节点B
  2157. * @return { Number } 节点A与节点B的关系
  2158. * @example
  2159. * ```javascript
  2160. * //output: 20
  2161. * var position = UE.dom.domUtils.getPosition( document.documentElement, document.body );
  2162. *
  2163. * switch ( position ) {
  2164. *
  2165. * //0
  2166. * case UE.dom.domUtils.POSITION_IDENTICAL:
  2167. * console.log('元素相同');
  2168. * break;
  2169. * //1
  2170. * case UE.dom.domUtils.POSITION_DISCONNECTED:
  2171. * console.log('两个节点在不同的文档中');
  2172. * break;
  2173. * //2
  2174. * case UE.dom.domUtils.POSITION_FOLLOWING:
  2175. * console.log('节点A在节点B之后');
  2176. * break;
  2177. * //4
  2178. * case UE.dom.domUtils.POSITION_PRECEDING;
  2179. * console.log('节点A在节点B之前');
  2180. * break;
  2181. * //8
  2182. * case UE.dom.domUtils.POSITION_IS_CONTAINED:
  2183. * console.log('节点A被节点B包含');
  2184. * break;
  2185. * case 10:
  2186. * console.log('节点A被节点B包含且节点A在节点B之后');
  2187. * break;
  2188. * //16
  2189. * case UE.dom.domUtils.POSITION_CONTAINS:
  2190. * console.log('节点A包含节点B');
  2191. * break;
  2192. * case 20:
  2193. * console.log('节点A包含节点B且节点A在节点B之前');
  2194. * break;
  2195. *
  2196. * }
  2197. * ```
  2198. */
  2199. getPosition: function (nodeA, nodeB) {
  2200. // 如果两个节点是同一个节点
  2201. if (nodeA === nodeB) {
  2202. // domUtils.POSITION_IDENTICAL
  2203. return 0;
  2204. }
  2205. var node,
  2206. parentsA = [nodeA],
  2207. parentsB = [nodeB];
  2208. node = nodeA;
  2209. while ((node = node.parentNode)) {
  2210. // 如果nodeB是nodeA的祖先节点
  2211. if (node === nodeB) {
  2212. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  2213. return 10;
  2214. }
  2215. parentsA.push(node);
  2216. }
  2217. node = nodeB;
  2218. while ((node = node.parentNode)) {
  2219. // 如果nodeA是nodeB的祖先节点
  2220. if (node === nodeA) {
  2221. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  2222. return 20;
  2223. }
  2224. parentsB.push(node);
  2225. }
  2226. parentsA.reverse();
  2227. parentsB.reverse();
  2228. if (parentsA[0] !== parentsB[0]) {
  2229. // domUtils.POSITION_DISCONNECTED
  2230. return 1;
  2231. }
  2232. var i = -1;
  2233. while ((i++, parentsA[i] === parentsB[i])) {
  2234. }
  2235. nodeA = parentsA[i];
  2236. nodeB = parentsB[i];
  2237. while ((nodeA = nodeA.nextSibling)) {
  2238. if (nodeA === nodeB) {
  2239. // domUtils.POSITION_PRECEDING
  2240. return 4;
  2241. }
  2242. }
  2243. // domUtils.POSITION_FOLLOWING
  2244. return 2;
  2245. },
  2246. /**
  2247. * 检测节点node在父节点中的索引位置
  2248. * @method getNodeIndex
  2249. * @param { Node } node 需要检测的节点对象
  2250. * @return { Number } 该节点在父节点中的位置
  2251. * @see UE.dom.domUtils.getNodeIndex(Node,Boolean)
  2252. */
  2253. /**
  2254. * 检测节点node在父节点中的索引位置, 根据给定的mergeTextNode参数决定是否要合并多个连续的文本节点为一个节点
  2255. * @method getNodeIndex
  2256. * @param { Node } node 需要检测的节点对象
  2257. * @param { Boolean } mergeTextNode 是否合并多个连续的文本节点为一个节点
  2258. * @return { Number } 该节点在父节点中的位置
  2259. * @example
  2260. * ```javascript
  2261. *
  2262. * var node = document.createElement("div");
  2263. *
  2264. * node.appendChild( document.createTextNode( "hello" ) );
  2265. * node.appendChild( document.createTextNode( "world" ) );
  2266. * node.appendChild( node = document.createElement( "div" ) );
  2267. *
  2268. * //output: 2
  2269. * console.log( UE.dom.domUtils.getNodeIndex( node ) );
  2270. *
  2271. * //output: 1
  2272. * console.log( UE.dom.domUtils.getNodeIndex( node, true ) );
  2273. *
  2274. * ```
  2275. */
  2276. getNodeIndex: function (node, ignoreTextNode) {
  2277. var preNode = node,
  2278. i = 0;
  2279. while ((preNode = preNode.previousSibling)) {
  2280. if (ignoreTextNode && preNode.nodeType == 3) {
  2281. if (preNode.nodeType != preNode.nextSibling.nodeType) {
  2282. i++;
  2283. }
  2284. continue;
  2285. }
  2286. i++;
  2287. }
  2288. return i;
  2289. },
  2290. /**
  2291. * 检测节点node是否在给定的document对象上
  2292. * @method inDoc
  2293. * @param { Node } node 需要检测的节点对象
  2294. * @param { DomDocument } doc 需要检测的document对象
  2295. * @return { Boolean } 该节点node是否在给定的document的dom树上
  2296. * @example
  2297. * ```javascript
  2298. *
  2299. * var node = document.createElement("div");
  2300. *
  2301. * //output: false
  2302. * console.log( UE.do.domUtils.inDoc( node, document ) );
  2303. *
  2304. * document.body.appendChild( node );
  2305. *
  2306. * //output: true
  2307. * console.log( UE.do.domUtils.inDoc( node, document ) );
  2308. *
  2309. * ```
  2310. */
  2311. inDoc: function (node, doc) {
  2312. return domUtils.getPosition(node, doc) == 10;
  2313. },
  2314. /**
  2315. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  2316. * 查找的起点是给定node节点的父节点。
  2317. * @method findParent
  2318. * @param { Node } node 需要查找的节点
  2319. * @param { Function } filterFn 自定义的过滤方法。
  2320. * @warning 查找的终点是到body节点为止
  2321. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  2322. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  2323. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  2324. * @example
  2325. * ```javascript
  2326. * var filterNode = UE.dom.domUtils.findParent( document.body.firstChild, function ( node ) {
  2327. *
  2328. * //由于查找的终点是body节点, 所以永远也不会匹配当前过滤器的条件, 即这里永远会返回false
  2329. * return node.tagName === "HTML";
  2330. *
  2331. * } );
  2332. *
  2333. * //output: true
  2334. * console.log( filterNode === null );
  2335. * ```
  2336. */
  2337. /**
  2338. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  2339. * 如果includeSelf的值为true,则查找的起点是给定的节点node, 否则, 起点是node的父节点
  2340. * @method findParent
  2341. * @param { Node } node 需要查找的节点
  2342. * @param { Function } filterFn 自定义的过滤方法。
  2343. * @param { Boolean } includeSelf 查找过程是否包含自身
  2344. * @warning 查找的终点是到body节点为止
  2345. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  2346. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  2347. * @remind 如果includeSelf为true, 则过滤器第一次执行时的参数会是节点本身。
  2348. * 反之, 过滤器第一次执行时的参数将是该节点的父节点。
  2349. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  2350. * @example
  2351. * ```html
  2352. * <body>
  2353. *
  2354. * <div id="test">
  2355. * </div>
  2356. *
  2357. * <script type="text/javascript">
  2358. *
  2359. * //output: DIV, BODY
  2360. * var filterNode = UE.dom.domUtils.findParent( document.getElementById( "test" ), function ( node ) {
  2361. *
  2362. * console.log( node.tagName );
  2363. * return false;
  2364. *
  2365. * }, true );
  2366. *
  2367. * </script>
  2368. * </body>
  2369. * ```
  2370. */
  2371. findParent: function (node, filterFn, includeSelf) {
  2372. if (node && !domUtils.isBody(node)) {
  2373. node = includeSelf ? node : node.parentNode;
  2374. while (node) {
  2375. if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
  2376. return filterFn && !filterFn(node) && domUtils.isBody(node)
  2377. ? null
  2378. : node;
  2379. }
  2380. node = node.parentNode;
  2381. }
  2382. }
  2383. return null;
  2384. },
  2385. /**
  2386. * 查找node的节点名为tagName的第一个祖先节点, 查找的起点是node节点的父节点。
  2387. * @method findParentByTagName
  2388. * @param { Node } node 需要查找的节点对象
  2389. * @param { Array } tagNames 需要查找的父节点的名称数组
  2390. * @warning 查找的终点是到body节点为止
  2391. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2392. * @example
  2393. * ```javascript
  2394. * var node = UE.dom.domUtils.findParentByTagName( document.getElementsByTagName("div")[0], [ "BODY" ] );
  2395. * //output: BODY
  2396. * console.log( node.tagName );
  2397. * ```
  2398. */
  2399. /**
  2400. * 查找node的节点名为tagName的祖先节点, 如果includeSelf的值为true,则查找的起点是给定的节点node,
  2401. * 否则, 起点是node的父节点。
  2402. * @method findParentByTagName
  2403. * @param { Node } node 需要查找的节点对象
  2404. * @param { Array } tagNames 需要查找的父节点的名称数组
  2405. * @param { Boolean } includeSelf 查找过程是否包含node节点自身
  2406. * @warning 查找的终点是到body节点为止
  2407. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2408. * @example
  2409. * ```javascript
  2410. * var queryTarget = document.getElementsByTagName("div")[0];
  2411. * var node = UE.dom.domUtils.findParentByTagName( queryTarget, [ "DIV" ], true );
  2412. * //output: true
  2413. * console.log( queryTarget === node );
  2414. * ```
  2415. */
  2416. findParentByTagName: function (node, tagNames, includeSelf, excludeFn) {
  2417. tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
  2418. return domUtils.findParent(
  2419. node,
  2420. function (node) {
  2421. return tagNames[node.tagName] && !(excludeFn && excludeFn(node));
  2422. },
  2423. includeSelf
  2424. );
  2425. },
  2426. /**
  2427. * 查找节点node的祖先节点集合, 查找的起点是给定节点的父节点,结果集中不包含给定的节点。
  2428. * @method findParents
  2429. * @param { Node } node 需要查找的节点对象
  2430. * @return { Array } 给定节点的祖先节点数组
  2431. * @grammar UE.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
  2432. * @grammar UE.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
  2433. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
  2434. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
  2435. */
  2436. /**
  2437. * 查找节点node的祖先节点集合, 如果includeSelf的值为true,
  2438. * 则返回的结果集中允许出现当前给定的节点, 否则, 该节点不会出现在其结果集中。
  2439. * @method findParents
  2440. * @param { Node } node 需要查找的节点对象
  2441. * @param { Boolean } includeSelf 查找的结果中是否允许包含当前查找的节点对象
  2442. * @return { Array } 给定节点的祖先节点数组
  2443. */
  2444. findParents: function (node, includeSelf, filterFn, closerFirst) {
  2445. var parents = includeSelf && ((filterFn && filterFn(node)) || !filterFn)
  2446. ? [node]
  2447. : [];
  2448. while ((node = domUtils.findParent(node, filterFn))) {
  2449. parents.push(node);
  2450. }
  2451. return closerFirst ? parents : parents.reverse();
  2452. },
  2453. /**
  2454. * 在节点node后面插入新节点newNode
  2455. * @method insertAfter
  2456. * @param { Node } node 目标节点
  2457. * @param { Node } newNode 新插入的节点, 该节点将置于目标节点之后
  2458. * @return { Node } 新插入的节点
  2459. */
  2460. insertAfter: function (node, newNode) {
  2461. return node.nextSibling
  2462. ? node.parentNode.insertBefore(newNode, node.nextSibling)
  2463. : node.parentNode.appendChild(newNode);
  2464. },
  2465. /**
  2466. * 删除节点node及其下属的所有节点
  2467. * @method remove
  2468. * @param { Node } node 需要删除的节点对象
  2469. * @return { Node } 返回刚删除的节点对象
  2470. * @example
  2471. * ```html
  2472. * <div id="test">
  2473. * <div id="child">你好</div>
  2474. * </div>
  2475. * <script>
  2476. * UE.dom.domUtils.remove( document.body, false );
  2477. * //output: false
  2478. * console.log( document.getElementById( "child" ) !== null );
  2479. * </script>
  2480. * ```
  2481. */
  2482. /**
  2483. * 删除节点node,并根据keepChildren的值决定是否保留子节点
  2484. * @method remove
  2485. * @param { Node } node 需要删除的节点对象
  2486. * @param { Boolean } keepChildren 是否需要保留子节点
  2487. * @return { Node } 返回刚删除的节点对象
  2488. * @example
  2489. * ```html
  2490. * <div id="test">
  2491. * <div id="child">你好</div>
  2492. * </div>
  2493. * <script>
  2494. * UE.dom.domUtils.remove( document.body, true );
  2495. * //output: true
  2496. * console.log( document.getElementById( "child" ) !== null );
  2497. * </script>
  2498. * ```
  2499. */
  2500. remove: function (node, keepChildren) {
  2501. var parent = node.parentNode,
  2502. child;
  2503. if (parent) {
  2504. if (keepChildren && node.hasChildNodes()) {
  2505. while ((child = node.firstChild)) {
  2506. parent.insertBefore(child, node);
  2507. }
  2508. }
  2509. parent.removeChild(node);
  2510. }
  2511. return node;
  2512. },
  2513. /**
  2514. * 取得node节点的下一个兄弟节点, 如果该节点其后没有兄弟节点, 则递归查找其父节点之后的第一个兄弟节点,
  2515. * 直到找到满足条件的节点或者递归到BODY节点之后才会结束。
  2516. * @method getNextDomNode
  2517. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2518. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2519. * @example
  2520. * ```html
  2521. * <body>
  2522. * <div id="test">
  2523. * <span></span>
  2524. * </div>
  2525. * <i>xxx</i>
  2526. * </body>
  2527. * <script>
  2528. *
  2529. * //output: i节点
  2530. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2531. *
  2532. * </script>
  2533. * ```
  2534. * @example
  2535. * ```html
  2536. * <body>
  2537. * <div>
  2538. * <span></span>
  2539. * <i id="test">xxx</i>
  2540. * </div>
  2541. * <b>xxx</b>
  2542. * </body>
  2543. * <script>
  2544. *
  2545. * //由于id为test的i节点之后没有兄弟节点, 则查找其父节点(div)后面的兄弟节点
  2546. * //output: b节点
  2547. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2548. *
  2549. * </script>
  2550. * ```
  2551. */
  2552. /**
  2553. * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点,
  2554. * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false,
  2555. * 则执行<a href="#UE.dom.domUtils.getNextDomNode(Node)">getNextDomNode(Node node)</a>的查找过程。
  2556. * @method getNextDomNode
  2557. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2558. * @param { Boolean } startFromChild 查找过程是否从其子节点开始
  2559. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2560. * @see UE.dom.domUtils.getNextDomNode(Node)
  2561. */
  2562. getNextDomNode: function (node, startFromChild, filterFn, guard) {
  2563. return getDomNode(
  2564. node,
  2565. "firstChild",
  2566. "nextSibling",
  2567. startFromChild,
  2568. filterFn,
  2569. guard
  2570. );
  2571. },
  2572. getPreDomNode: function (node, startFromChild, filterFn, guard) {
  2573. return getDomNode(
  2574. node,
  2575. "lastChild",
  2576. "previousSibling",
  2577. startFromChild,
  2578. filterFn,
  2579. guard
  2580. );
  2581. },
  2582. /**
  2583. * 检测节点node是否属是UEditor定义的bookmark节点
  2584. * @method isBookmarkNode
  2585. * @private
  2586. * @param { Node } node 需要检测的节点对象
  2587. * @return { Boolean } 是否是bookmark节点
  2588. * @example
  2589. * ```html
  2590. * <span id="_baidu_bookmark_1"></span>
  2591. * <script>
  2592. * var bookmarkNode = document.getElementById("_baidu_bookmark_1");
  2593. * //output: true
  2594. * console.log( UE.dom.domUtils.isBookmarkNode( bookmarkNode ) );
  2595. * </script>
  2596. * ```
  2597. */
  2598. isBookmarkNode: function (node) {
  2599. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id);
  2600. },
  2601. /**
  2602. * 获取节点node所属的window对象
  2603. * @method getWindow
  2604. * @param { Node } node 节点对象
  2605. * @return { Window } 当前节点所属的window对象
  2606. * @example
  2607. * ```javascript
  2608. * //output: true
  2609. * console.log( UE.dom.domUtils.getWindow( document.body ) === window );
  2610. * ```
  2611. */
  2612. getWindow: function (node) {
  2613. var doc = node.ownerDocument || node;
  2614. return doc.defaultView || doc.parentWindow;
  2615. },
  2616. /**
  2617. * 获取离nodeA与nodeB最近的公共的祖先节点
  2618. * @method getCommonAncestor
  2619. * @param { Node } nodeA 第一个节点
  2620. * @param { Node } nodeB 第二个节点
  2621. * @remind 如果给定的两个节点是同一个节点, 将直接返回该节点。
  2622. * @return { Node | NULL } 如果未找到公共节点, 返回NULL, 否则返回最近的公共祖先节点。
  2623. * @example
  2624. * ```javascript
  2625. * var commonAncestor = UE.dom.domUtils.getCommonAncestor( document.body, document.body.firstChild );
  2626. * //output: true
  2627. * console.log( commonAncestor.tagName.toLowerCase() === 'body' );
  2628. * ```
  2629. */
  2630. getCommonAncestor: function (nodeA, nodeB) {
  2631. if (nodeA === nodeB) return nodeA;
  2632. var parentsA = [nodeA],
  2633. parentsB = [nodeB],
  2634. parent = nodeA,
  2635. i = -1;
  2636. while ((parent = parent.parentNode)) {
  2637. if (parent === nodeB) {
  2638. return parent;
  2639. }
  2640. parentsA.push(parent);
  2641. }
  2642. parent = nodeB;
  2643. while ((parent = parent.parentNode)) {
  2644. if (parent === nodeA) return parent;
  2645. parentsB.push(parent);
  2646. }
  2647. parentsA.reverse();
  2648. parentsB.reverse();
  2649. while ((i++, parentsA[i] === parentsB[i])) {
  2650. }
  2651. return i == 0 ? null : parentsA[i - 1];
  2652. },
  2653. /**
  2654. * 清除node节点左右连续为空的兄弟inline节点
  2655. * @method clearEmptySibling
  2656. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2657. * 则这些兄弟节点将被删除
  2658. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
  2659. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
  2660. * @example
  2661. * ```html
  2662. * <body>
  2663. * <div></div>
  2664. * <span id="test"></span>
  2665. * <i></i>
  2666. * <b></b>
  2667. * <em>xxx</em>
  2668. * <span></span>
  2669. * </body>
  2670. * <script>
  2671. *
  2672. * UE.dom.domUtils.clearEmptySibling( document.getElementById( "test" ) );
  2673. *
  2674. * //output: <div></div><span id="test"></span><em>xxx</em><span></span>
  2675. * console.log( document.body.innerHTML );
  2676. *
  2677. * </script>
  2678. * ```
  2679. */
  2680. /**
  2681. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2682. * 则忽略对右边兄弟节点的操作。
  2683. * @method clearEmptySibling
  2684. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2685. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2686. * 则这些兄弟节点将被删除
  2687. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2688. */
  2689. /**
  2690. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2691. * 则忽略对右边兄弟节点的操作, 如果ignorePre的值为true,则忽略对左边兄弟节点的操作。
  2692. * @method clearEmptySibling
  2693. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2694. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2695. * @param { Boolean } ignorePre 是否忽略忽略对左边的兄弟节点的操作
  2696. * 则这些兄弟节点将被删除
  2697. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2698. */
  2699. clearEmptySibling: function (node, ignoreNext, ignorePre) {
  2700. function clear(next, dir) {
  2701. var tmpNode;
  2702. while (
  2703. next &&
  2704. !domUtils.isBookmarkNode(next) &&
  2705. (domUtils.isEmptyInlineElement(next) ||
  2706. //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
  2707. !new RegExp("[^\t\n\r" + domUtils.fillChar + "]").test(
  2708. next.nodeValue
  2709. ))
  2710. ) {
  2711. tmpNode = next[dir];
  2712. domUtils.remove(next);
  2713. next = tmpNode;
  2714. }
  2715. }
  2716. !ignoreNext && clear(node.nextSibling, "nextSibling");
  2717. !ignorePre && clear(node.previousSibling, "previousSibling");
  2718. },
  2719. /**
  2720. * 将一个文本节点textNode拆分成两个文本节点,offset指定拆分位置
  2721. * @method split
  2722. * @param { Node } textNode 需要拆分的文本节点对象
  2723. * @param { int } offset 需要拆分的位置, 位置计算从0开始
  2724. * @return { Node } 拆分后形成的新节点
  2725. * @example
  2726. * ```html
  2727. * <div id="test">abcdef</div>
  2728. * <script>
  2729. * var newNode = UE.dom.domUtils.split( document.getElementById( "test" ).firstChild, 3 );
  2730. * //output: def
  2731. * console.log( newNode.nodeValue );
  2732. * </script>
  2733. * ```
  2734. */
  2735. split: function (node, offset) {
  2736. var doc = node.ownerDocument;
  2737. if (browser.ie && offset == node.nodeValue.length) {
  2738. var next = doc.createTextNode("");
  2739. return domUtils.insertAfter(node, next);
  2740. }
  2741. var retval = node.splitText(offset);
  2742. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  2743. if (browser.ie8) {
  2744. var tmpNode = doc.createTextNode("");
  2745. domUtils.insertAfter(retval, tmpNode);
  2746. domUtils.remove(tmpNode);
  2747. }
  2748. return retval;
  2749. },
  2750. /**
  2751. * 检测文本节点textNode是否为空节点(包括空格、换行、占位符等字符)
  2752. * @method isWhitespace
  2753. * @param { Node } node 需要检测的节点对象
  2754. * @return { Boolean } 检测的节点是否为空
  2755. * @example
  2756. * ```html
  2757. * <div id="test">
  2758. *
  2759. * </div>
  2760. * <script>
  2761. * //output: true
  2762. * console.log( UE.dom.domUtils.isWhitespace( document.getElementById("test").firstChild ) );
  2763. * </script>
  2764. * ```
  2765. */
  2766. isWhitespace: function (node) {
  2767. return !new RegExp("[^ \t\n\r" + domUtils.fillChar + "]").test(
  2768. node.nodeValue
  2769. );
  2770. },
  2771. /**
  2772. * 获取元素element相对于viewport的位置坐标
  2773. * @method getXY
  2774. * @param { Node } element 需要计算位置的节点对象
  2775. * @return { Object } 返回形如{x:left,y:top}的一个key-value映射对象, 其中键x代表水平偏移距离,
  2776. * y代表垂直偏移距离。
  2777. *
  2778. * @example
  2779. * ```javascript
  2780. * var location = UE.dom.domUtils.getXY( document.getElementById("test") );
  2781. * //output: test的坐标为: 12, 24
  2782. * console.log( 'test的坐标为: ', location.x, ',', location.y );
  2783. * ```
  2784. */
  2785. getXY: function (element) {
  2786. var x = 0,
  2787. y = 0;
  2788. while (element.offsetParent) {
  2789. y += element.offsetTop;
  2790. x += element.offsetLeft;
  2791. element = element.offsetParent;
  2792. }
  2793. return {x: x, y: y};
  2794. },
  2795. /**
  2796. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2797. * @method on
  2798. * @param { Node } element 需要绑定事件的节点对象
  2799. * @param { String } type 绑定的事件类型
  2800. * @param { Function } handler 事件处理器
  2801. * @example
  2802. * ```javascript
  2803. * UE.dom.domUtils.on(document.body,"click",function(e){
  2804. * //e为事件对象,this为被点击元素对戏那个
  2805. * });
  2806. * ```
  2807. */
  2808. /**
  2809. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2810. * @method on
  2811. * @param { Node } element 需要绑定事件的节点对象
  2812. * @param { Array } type 绑定的事件类型数组
  2813. * @param { Function } handler 事件处理器
  2814. * @example
  2815. * ```javascript
  2816. * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
  2817. * //evt为事件对象,this为被点击元素对象
  2818. * });
  2819. * ```
  2820. */
  2821. on: function (element, type, handler) {
  2822. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2823. k = types.length;
  2824. if (k)
  2825. while (k--) {
  2826. type = types[k];
  2827. if (element.addEventListener) {
  2828. element.addEventListener(type, handler, false);
  2829. } else {
  2830. if (!handler._d) {
  2831. handler._d = {
  2832. els: []
  2833. };
  2834. }
  2835. var key = type + handler.toString(),
  2836. index = utils.indexOf(handler._d.els, element);
  2837. if (!handler._d[key] || index == -1) {
  2838. if (index == -1) {
  2839. handler._d.els.push(element);
  2840. }
  2841. if (!handler._d[key]) {
  2842. handler._d[key] = function (evt) {
  2843. return handler.call(evt.srcElement, evt || window.event);
  2844. };
  2845. }
  2846. element.attachEvent("on" + type, handler._d[key]);
  2847. }
  2848. }
  2849. }
  2850. element = null;
  2851. },
  2852. /**
  2853. * 解除DOM事件绑定
  2854. * @method un
  2855. * @param { Node } element 需要解除事件绑定的节点对象
  2856. * @param { String } type 需要接触绑定的事件类型
  2857. * @param { Function } handler 对应的事件处理器
  2858. * @example
  2859. * ```javascript
  2860. * UE.dom.domUtils.un(document.body,"click",function(evt){
  2861. * //evt为事件对象,this为被点击元素对象
  2862. * });
  2863. * ```
  2864. */
  2865. /**
  2866. * 解除DOM事件绑定
  2867. * @method un
  2868. * @param { Node } element 需要解除事件绑定的节点对象
  2869. * @param { Array } type 需要接触绑定的事件类型数组
  2870. * @param { Function } handler 对应的事件处理器
  2871. * @example
  2872. * ```javascript
  2873. * UE.dom.domUtils.un(document.body, ["click","mousedown"],function(evt){
  2874. * //evt为事件对象,this为被点击元素对象
  2875. * });
  2876. * ```
  2877. */
  2878. un: function (element, type, handler) {
  2879. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2880. k = types.length;
  2881. if (k)
  2882. while (k--) {
  2883. type = types[k];
  2884. if (element.removeEventListener) {
  2885. element.removeEventListener(type, handler, false);
  2886. } else {
  2887. var key = type + handler.toString();
  2888. try {
  2889. element.detachEvent(
  2890. "on" + type,
  2891. handler._d ? handler._d[key] : handler
  2892. );
  2893. } catch (e) {
  2894. }
  2895. if (handler._d && handler._d[key]) {
  2896. var index = utils.indexOf(handler._d.els, element);
  2897. if (index != -1) {
  2898. handler._d.els.splice(index, 1);
  2899. }
  2900. handler._d.els.length == 0 && delete handler._d[key];
  2901. }
  2902. }
  2903. }
  2904. },
  2905. /**
  2906. * 比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值
  2907. * @method isSameElement
  2908. * @param { Node } nodeA 需要比较的节点
  2909. * @param { Node } nodeB 需要比较的节点
  2910. * @return { Boolean } 两个节点是否具有相同的标签名、属性名以及属性值
  2911. * @example
  2912. * ```html
  2913. * <span style="font-size:12px">ssss</span>
  2914. * <span style="font-size:12px">bbbbb</span>
  2915. * <span style="font-size:13px">ssss</span>
  2916. * <span style="font-size:14px">bbbbb</span>
  2917. *
  2918. * <script>
  2919. *
  2920. * var nodes = document.getElementsByTagName( "span" );
  2921. *
  2922. * //output: true
  2923. * console.log( UE.dom.domUtils.isSameElement( nodes[0], nodes[1] ) );
  2924. *
  2925. * //output: false
  2926. * console.log( UE.dom.domUtils.isSameElement( nodes[2], nodes[3] ) );
  2927. *
  2928. * </script>
  2929. * ```
  2930. */
  2931. isSameElement: function (nodeA, nodeB) {
  2932. if (nodeA.tagName != nodeB.tagName) {
  2933. return false;
  2934. }
  2935. var thisAttrs = nodeA.attributes,
  2936. otherAttrs = nodeB.attributes;
  2937. if (!ie && thisAttrs.length != otherAttrs.length) {
  2938. return false;
  2939. }
  2940. var attrA,
  2941. attrB,
  2942. al = 0,
  2943. bl = 0;
  2944. for (var i = 0; (attrA = thisAttrs[i++]);) {
  2945. if (attrA.nodeName == "style") {
  2946. if (attrA.specified) {
  2947. al++;
  2948. }
  2949. if (domUtils.isSameStyle(nodeA, nodeB)) {
  2950. continue;
  2951. } else {
  2952. return false;
  2953. }
  2954. }
  2955. if (ie) {
  2956. if (attrA.specified) {
  2957. al++;
  2958. attrB = otherAttrs.getNamedItem(attrA.nodeName);
  2959. } else {
  2960. continue;
  2961. }
  2962. } else {
  2963. attrB = nodeB.attributes[attrA.nodeName];
  2964. }
  2965. if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) {
  2966. return false;
  2967. }
  2968. }
  2969. // 有可能attrB的属性包含了attrA的属性之外还有自己的属性
  2970. if (ie) {
  2971. for (i = 0; (attrB = otherAttrs[i++]);) {
  2972. if (attrB.specified) {
  2973. bl++;
  2974. }
  2975. }
  2976. if (al != bl) {
  2977. return false;
  2978. }
  2979. }
  2980. return true;
  2981. },
  2982. /**
  2983. * 判断节点nodeA与节点nodeB的元素的style属性是否一致
  2984. * @method isSameStyle
  2985. * @param { Node } nodeA 需要比较的节点
  2986. * @param { Node } nodeB 需要比较的节点
  2987. * @return { Boolean } 两个节点是否具有相同的style属性值
  2988. * @example
  2989. * ```html
  2990. * <span style="font-size:12px">ssss</span>
  2991. * <span style="font-size:12px">bbbbb</span>
  2992. * <span style="font-size:13px">ssss</span>
  2993. * <span style="font-size:14px">bbbbb</span>
  2994. *
  2995. * <script>
  2996. *
  2997. * var nodes = document.getElementsByTagName( "span" );
  2998. *
  2999. * //output: true
  3000. * console.log( UE.dom.domUtils.isSameStyle( nodes[0], nodes[1] ) );
  3001. *
  3002. * //output: false
  3003. * console.log( UE.dom.domUtils.isSameStyle( nodes[2], nodes[3] ) );
  3004. *
  3005. * </script>
  3006. * ```
  3007. */
  3008. isSameStyle: function (nodeA, nodeB) {
  3009. var styleA = nodeA.style.cssText
  3010. .replace(/( ?; ?)/g, ";")
  3011. .replace(/( ?: ?)/g, ":"),
  3012. styleB = nodeB.style.cssText
  3013. .replace(/( ?; ?)/g, ";")
  3014. .replace(/( ?: ?)/g, ":");
  3015. if (browser.opera) {
  3016. styleA = nodeA.style;
  3017. styleB = nodeB.style;
  3018. if (styleA.length != styleB.length) return false;
  3019. for (var p in styleA) {
  3020. if (/^(\d+|csstext)$/i.test(p)) {
  3021. continue;
  3022. }
  3023. if (styleA[p] != styleB[p]) {
  3024. return false;
  3025. }
  3026. }
  3027. return true;
  3028. }
  3029. if (!styleA || !styleB) {
  3030. return styleA == styleB;
  3031. }
  3032. styleA = styleA.split(";");
  3033. styleB = styleB.split(";");
  3034. if (styleA.length != styleB.length) {
  3035. return false;
  3036. }
  3037. for (var i = 0, ci; (ci = styleA[i++]);) {
  3038. if (utils.indexOf(styleB, ci) == -1) {
  3039. return false;
  3040. }
  3041. }
  3042. return true;
  3043. },
  3044. /**
  3045. * 检查节点node是否为block元素
  3046. * @method isBlockElm
  3047. * @param { Node } node 需要检测的节点对象
  3048. * @return { Boolean } 是否是block元素节点
  3049. * @warning 该方法的判断规则如下: 如果该元素原本是block元素, 则不论该元素当前的css样式是什么都会返回true;
  3050. * 否则,检测该元素的css样式, 如果该元素当前是block元素, 则返回true。 其余情况下都返回false。
  3051. * @example
  3052. * ```html
  3053. * <span id="test1" style="display: block"></span>
  3054. * <span id="test2"></span>
  3055. * <div id="test3" style="display: inline"></div>
  3056. *
  3057. * <script>
  3058. *
  3059. * //output: true
  3060. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test1") ) );
  3061. *
  3062. * //output: false
  3063. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test2") ) );
  3064. *
  3065. * //output: true
  3066. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test3") ) );
  3067. *
  3068. * </script>
  3069. * ```
  3070. */
  3071. isBlockElm: function (node) {
  3072. return (
  3073. node.nodeType == 1 &&
  3074. (dtd.$block[node.tagName] ||
  3075. styleBlock[domUtils.getComputedStyle(node, "display")]) &&
  3076. !dtd.$nonChild[node.tagName]
  3077. );
  3078. },
  3079. /**
  3080. * 检测node节点是否为body节点
  3081. * @method isBody
  3082. * @param { Element } node 需要检测的dom元素
  3083. * @return { Boolean } 给定的元素是否是body元素
  3084. * @example
  3085. * ```javascript
  3086. * //output: true
  3087. * console.log( UE.dom.domUtils.isBody( document.body ) );
  3088. * ```
  3089. */
  3090. isBody: function (node) {
  3091. return node && node.nodeType == 1 && node.tagName.toLowerCase() == "body";
  3092. },
  3093. /**
  3094. * 以node节点为分界,将该节点的指定祖先节点parent拆分成两个独立的节点,
  3095. * 拆分形成的两个节点之间是node节点
  3096. * @method breakParent
  3097. * @param { Node } node 作为分界的节点对象
  3098. * @param { Node } parent 该节点必须是node节点的祖先节点, 且是block节点。
  3099. * @return { Node } 给定的node分界节点
  3100. * @example
  3101. * ```javascript
  3102. *
  3103. * var node = document.createElement("span"),
  3104. * wrapNode = document.createElement( "div" ),
  3105. * parent = document.createElement("p");
  3106. *
  3107. * parent.appendChild( node );
  3108. * wrapNode.appendChild( parent );
  3109. *
  3110. * //拆分前
  3111. * //output: <p><span></span></p>
  3112. * console.log( wrapNode.innerHTML );
  3113. *
  3114. *
  3115. * UE.dom.domUtils.breakParent( node, parent );
  3116. * //拆分后
  3117. * //output: <p></p><span></span><p></p>
  3118. * console.log( wrapNode.innerHTML );
  3119. *
  3120. * ```
  3121. */
  3122. breakParent: function (node, parent) {
  3123. var tmpNode,
  3124. parentClone = node,
  3125. clone = node,
  3126. leftNodes,
  3127. rightNodes;
  3128. do {
  3129. parentClone = parentClone.parentNode;
  3130. if (leftNodes) {
  3131. tmpNode = parentClone.cloneNode(false);
  3132. tmpNode.appendChild(leftNodes);
  3133. leftNodes = tmpNode;
  3134. tmpNode = parentClone.cloneNode(false);
  3135. tmpNode.appendChild(rightNodes);
  3136. rightNodes = tmpNode;
  3137. } else {
  3138. leftNodes = parentClone.cloneNode(false);
  3139. rightNodes = leftNodes.cloneNode(false);
  3140. }
  3141. while ((tmpNode = clone.previousSibling)) {
  3142. leftNodes.insertBefore(tmpNode, leftNodes.firstChild);
  3143. }
  3144. while ((tmpNode = clone.nextSibling)) {
  3145. rightNodes.appendChild(tmpNode);
  3146. }
  3147. clone = parentClone;
  3148. } while (parent !== parentClone);
  3149. tmpNode = parent.parentNode;
  3150. tmpNode.insertBefore(leftNodes, parent);
  3151. tmpNode.insertBefore(rightNodes, parent);
  3152. tmpNode.insertBefore(node, rightNodes);
  3153. domUtils.remove(parent);
  3154. return node;
  3155. },
  3156. /**
  3157. * 检查节点node是否是空inline节点
  3158. * @method isEmptyInlineElement
  3159. * @param { Node } node 需要检测的节点对象
  3160. * @return { Number } 如果给定的节点是空的inline节点, 则返回1, 否则返回0。
  3161. * @example
  3162. * ```html
  3163. * <b><i></i></b> => 1
  3164. * <b><i></i><u></u></b> => 1
  3165. * <b></b> => 1
  3166. * <b>xx<i></i></b> => 0
  3167. * ```
  3168. */
  3169. isEmptyInlineElement: function (node) {
  3170. if (node.nodeType != 1 || !dtd.$removeEmpty[node.tagName]) {
  3171. return 0;
  3172. }
  3173. node = node.firstChild;
  3174. while (node) {
  3175. //如果是创建的bookmark就跳过
  3176. if (domUtils.isBookmarkNode(node)) {
  3177. return 0;
  3178. }
  3179. if (
  3180. (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node)) ||
  3181. (node.nodeType == 3 && !domUtils.isWhitespace(node))
  3182. ) {
  3183. return 0;
  3184. }
  3185. node = node.nextSibling;
  3186. }
  3187. return 1;
  3188. },
  3189. /**
  3190. * 删除node节点下首尾两端的空白文本子节点
  3191. * @method trimWhiteTextNode
  3192. * @param { Element } node 需要执行删除操作的元素对象
  3193. * @example
  3194. * ```javascript
  3195. * var node = document.createElement("div");
  3196. *
  3197. * node.appendChild( document.createTextNode( "" ) );
  3198. *
  3199. * node.appendChild( document.createElement("div") );
  3200. *
  3201. * node.appendChild( document.createTextNode( "" ) );
  3202. *
  3203. * //3
  3204. * console.log( node.childNodes.length );
  3205. *
  3206. * UE.dom.domUtils.trimWhiteTextNode( node );
  3207. *
  3208. * //1
  3209. * console.log( node.childNodes.length );
  3210. * ```
  3211. */
  3212. trimWhiteTextNode: function (node) {
  3213. function remove(dir) {
  3214. var child;
  3215. while (
  3216. (child = node[dir]) &&
  3217. child.nodeType == 3 &&
  3218. domUtils.isWhitespace(child)
  3219. ) {
  3220. node.removeChild(child);
  3221. }
  3222. }
  3223. remove("firstChild");
  3224. remove("lastChild");
  3225. },
  3226. /**
  3227. * 合并node节点下相同的子节点
  3228. * @name mergeChild
  3229. * @desc
  3230. * UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签
  3231. * @example
  3232. * <p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xx</span></p>
  3233. * ==> UE.dom.domUtils.mergeChild(node,'span')
  3234. * <p><span style="font-size:12px;">xxaaxx</span></p>
  3235. */
  3236. mergeChild: function (node, tagName, attrs) {
  3237. var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase());
  3238. for (var i = 0, ci; (ci = list[i++]);) {
  3239. if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
  3240. continue;
  3241. }
  3242. //span单独处理
  3243. if (ci.tagName.toLowerCase() == "span") {
  3244. if (node === ci.parentNode) {
  3245. domUtils.trimWhiteTextNode(node);
  3246. if (node.childNodes.length == 1) {
  3247. node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
  3248. domUtils.remove(ci, true);
  3249. continue;
  3250. }
  3251. }
  3252. ci.style.cssText = node.style.cssText + ";" + ci.style.cssText;
  3253. if (attrs) {
  3254. var style = attrs.style;
  3255. if (style) {
  3256. style = style.split(";");
  3257. for (var j = 0, s; (s = style[j++]);) {
  3258. ci.style[utils.cssStyleToDomStyle(s.split(":")[0])] = s.split(
  3259. ":"
  3260. )[1];
  3261. }
  3262. }
  3263. }
  3264. if (domUtils.isSameStyle(ci, node)) {
  3265. domUtils.remove(ci, true);
  3266. }
  3267. continue;
  3268. }
  3269. if (domUtils.isSameElement(node, ci)) {
  3270. domUtils.remove(ci, true);
  3271. }
  3272. }
  3273. },
  3274. /**
  3275. * 原生方法getElementsByTagName的封装
  3276. * @method getElementsByTagName
  3277. * @param { Node } node 目标节点对象
  3278. * @param { String } tagName 需要查找的节点的tagName, 多个tagName以空格分割
  3279. * @return { Array } 符合条件的节点集合
  3280. */
  3281. getElementsByTagName: function (node, name, filter) {
  3282. if (filter && utils.isString(filter)) {
  3283. var className = filter;
  3284. filter = function (node) {
  3285. return domUtils.hasClass(node, className);
  3286. };
  3287. }
  3288. name = utils.trim(name).replace(/[ ]{2,}/g, " ").split(" ");
  3289. var arr = [];
  3290. for (var n = 0, ni; (ni = name[n++]);) {
  3291. var list = node.getElementsByTagName(ni);
  3292. for (var i = 0, ci; (ci = list[i++]);) {
  3293. if (!filter || filter(ci)) arr.push(ci);
  3294. }
  3295. }
  3296. return arr;
  3297. },
  3298. /**
  3299. * 将节点node提取到父节点上
  3300. * @method mergeToParent
  3301. * @param { Element } node 需要提取的元素对象
  3302. * @example
  3303. * ```html
  3304. * <div id="parent">
  3305. * <div id="sub">
  3306. * <span id="child"></span>
  3307. * </div>
  3308. * </div>
  3309. *
  3310. * <script>
  3311. *
  3312. * var child = document.getElementById( "child" );
  3313. *
  3314. * //output: sub
  3315. * console.log( child.parentNode.id );
  3316. *
  3317. * UE.dom.domUtils.mergeToParent( child );
  3318. *
  3319. * //output: parent
  3320. * console.log( child.parentNode.id );
  3321. *
  3322. * </script>
  3323. * ```
  3324. */
  3325. mergeToParent: function (node) {
  3326. var parent = node.parentNode;
  3327. while (parent && dtd.$removeEmpty[parent.tagName]) {
  3328. if (parent.tagName == node.tagName || parent.tagName == "A") {
  3329. //针对a标签单独处理
  3330. domUtils.trimWhiteTextNode(parent);
  3331. //span需要特殊处理 不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
  3332. if (
  3333. (parent.tagName == "SPAN" && !domUtils.isSameStyle(parent, node)) ||
  3334. (parent.tagName == "A" && node.tagName == "SPAN")
  3335. ) {
  3336. if (parent.childNodes.length > 1 || parent !== node.parentNode) {
  3337. node.style.cssText =
  3338. parent.style.cssText + ";" + node.style.cssText;
  3339. parent = parent.parentNode;
  3340. continue;
  3341. } else {
  3342. parent.style.cssText += ";" + node.style.cssText;
  3343. //trace:952 a标签要保持下划线
  3344. if (parent.tagName == "A") {
  3345. parent.style.textDecoration = "underline";
  3346. }
  3347. }
  3348. }
  3349. if (parent.tagName != "A") {
  3350. parent === node.parentNode && domUtils.remove(node, true);
  3351. break;
  3352. }
  3353. }
  3354. parent = parent.parentNode;
  3355. }
  3356. },
  3357. /**
  3358. * 合并节点node的左右兄弟节点
  3359. * @method mergeSibling
  3360. * @param { Element } node 需要合并的目标节点
  3361. * @example
  3362. * ```html
  3363. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3364. *
  3365. * <script>
  3366. * var demoNode = document.getElementById("test");
  3367. * UE.dom.domUtils.mergeSibling( demoNode );
  3368. * //output: xxxxoooxxxx
  3369. * console.log( demoNode.innerHTML );
  3370. * </script>
  3371. * ```
  3372. */
  3373. /**
  3374. * 合并节点node的左右兄弟节点, 可以根据给定的条件选择是否忽略合并左节点。
  3375. * @method mergeSibling
  3376. * @param { Element } node 需要合并的目标节点
  3377. * @param { Boolean } ignorePre 是否忽略合并左节点
  3378. * @example
  3379. * ```html
  3380. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3381. *
  3382. * <script>
  3383. * var demoNode = document.getElementById("test");
  3384. * UE.dom.domUtils.mergeSibling( demoNode, true );
  3385. * //output: oooxxxx
  3386. * console.log( demoNode.innerHTML );
  3387. * </script>
  3388. * ```
  3389. */
  3390. /**
  3391. * 合并节点node的左右兄弟节点,可以根据给定的条件选择是否忽略合并左右节点。
  3392. * @method mergeSibling
  3393. * @param { Element } node 需要合并的目标节点
  3394. * @param { Boolean } ignorePre 是否忽略合并左节点
  3395. * @param { Boolean } ignoreNext 是否忽略合并右节点
  3396. * @remind 如果同时忽略左右节点, 则该操作什么也不会做
  3397. * @example
  3398. * ```html
  3399. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3400. *
  3401. * <script>
  3402. * var demoNode = document.getElementById("test");
  3403. * UE.dom.domUtils.mergeSibling( demoNode, false, true );
  3404. * //output: xxxxooo
  3405. * console.log( demoNode.innerHTML );
  3406. * </script>
  3407. * ```
  3408. */
  3409. mergeSibling: function (node, ignorePre, ignoreNext) {
  3410. function merge(rtl, start, node) {
  3411. var next;
  3412. if (
  3413. (next = node[rtl]) &&
  3414. !domUtils.isBookmarkNode(next) &&
  3415. next.nodeType == 1 &&
  3416. domUtils.isSameElement(node, next)
  3417. ) {
  3418. while (next.firstChild) {
  3419. if (start == "firstChild") {
  3420. node.insertBefore(next.lastChild, node.firstChild);
  3421. } else {
  3422. node.appendChild(next.firstChild);
  3423. }
  3424. }
  3425. domUtils.remove(next);
  3426. }
  3427. }
  3428. !ignorePre && merge("previousSibling", "firstChild", node);
  3429. !ignoreNext && merge("nextSibling", "lastChild", node);
  3430. },
  3431. /**
  3432. * 设置节点node及其子节点不会被选中
  3433. * @method unSelectable
  3434. * @param { Element } node 需要执行操作的dom元素
  3435. * @remind 执行该操作后的节点, 将不能被鼠标选中
  3436. * @example
  3437. * ```javascript
  3438. * UE.dom.domUtils.unSelectable( document.body );
  3439. * ```
  3440. */
  3441. unSelectable: (ie && browser.ie9below) || browser.opera
  3442. ? function (node) {
  3443. //for ie9
  3444. node.onselectstart = function () {
  3445. return false;
  3446. };
  3447. node.onclick = node.onkeyup = node.onkeydown = function () {
  3448. return false;
  3449. };
  3450. node.unselectable = "on";
  3451. node.setAttribute("unselectable", "on");
  3452. for (var i = 0, ci; (ci = node.all[i++]);) {
  3453. switch (ci.tagName.toLowerCase()) {
  3454. case "iframe":
  3455. case "textarea":
  3456. case "input":
  3457. case "select":
  3458. break;
  3459. default:
  3460. ci.unselectable = "on";
  3461. node.setAttribute("unselectable", "on");
  3462. }
  3463. }
  3464. }
  3465. : function (node) {
  3466. node.style.MozUserSelect = node.style.webkitUserSelect = node.style.msUserSelect = node.style.KhtmlUserSelect =
  3467. "none";
  3468. },
  3469. /**
  3470. * 删除节点node上的指定属性名称的属性
  3471. * @method removeAttributes
  3472. * @param { Node } node 需要删除属性的节点对象
  3473. * @param { String } attrNames 可以是空格隔开的多个属性名称,该操作将会依次删除相应的属性
  3474. * @example
  3475. * ```html
  3476. * <div id="wrap">
  3477. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3478. * </div>
  3479. *
  3480. * <script>
  3481. *
  3482. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), "id name" );
  3483. *
  3484. * //output: <span style="font-size:14px;">xxxxx</span>
  3485. * console.log( document.getElementById("wrap").innerHTML );
  3486. *
  3487. * </script>
  3488. * ```
  3489. */
  3490. /**
  3491. * 删除节点node上的指定属性名称的属性
  3492. * @method removeAttributes
  3493. * @param { Node } node 需要删除属性的节点对象
  3494. * @param { Array } attrNames 需要删除的属性名数组
  3495. * @example
  3496. * ```html
  3497. * <div id="wrap">
  3498. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3499. * </div>
  3500. *
  3501. * <script>
  3502. *
  3503. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), ["id", "name"] );
  3504. *
  3505. * //output: <span style="font-size:14px;">xxxxx</span>
  3506. * console.log( document.getElementById("wrap").innerHTML );
  3507. *
  3508. * </script>
  3509. * ```
  3510. */
  3511. removeAttributes: function (node, attrNames) {
  3512. attrNames = utils.isArray(attrNames)
  3513. ? attrNames
  3514. : utils.trim(attrNames).replace(/[ ]{2,}/g, " ").split(" ");
  3515. for (var i = 0, ci; (ci = attrNames[i++]);) {
  3516. ci = attrFix[ci] || ci;
  3517. switch (ci) {
  3518. case "className":
  3519. node[ci] = "";
  3520. break;
  3521. case "style":
  3522. node.style.cssText = "";
  3523. var val = node.getAttributeNode("style");
  3524. !browser.ie && val && node.removeAttributeNode(val);
  3525. }
  3526. node.removeAttribute(ci);
  3527. }
  3528. },
  3529. /**
  3530. * 在doc下创建一个标签名为tag,属性为attrs的元素
  3531. * @method createElement
  3532. * @param { DomDocument } doc 新创建的元素属于该document节点创建
  3533. * @param { String } tagName 需要创建的元素的标签名
  3534. * @param { Object } attrs 新创建的元素的属性key-value集合
  3535. * @return { Element } 新创建的元素对象
  3536. * @example
  3537. * ```javascript
  3538. * var ele = UE.dom.domUtils.createElement( document, 'div', {
  3539. * id: 'test'
  3540. * } );
  3541. *
  3542. * //output: DIV
  3543. * console.log( ele.tagName );
  3544. *
  3545. * //output: test
  3546. * console.log( ele.id );
  3547. *
  3548. * ```
  3549. */
  3550. createElement: function (doc, tag, attrs) {
  3551. return domUtils.setAttributes(doc.createElement(tag), attrs);
  3552. },
  3553. /**
  3554. * 为节点node添加属性attrs,attrs为属性键值对
  3555. * @method setAttributes
  3556. * @param { Element } node 需要设置属性的元素对象
  3557. * @param { Object } attrs 需要设置的属性名-值对
  3558. * @return { Element } 设置属性的元素对象
  3559. * @example
  3560. * ```html
  3561. * <span id="test"></span>
  3562. *
  3563. * <script>
  3564. *
  3565. * var testNode = UE.dom.domUtils.setAttributes( document.getElementById( "test" ), {
  3566. * id: 'demo'
  3567. * } );
  3568. *
  3569. * //output: demo
  3570. * console.log( testNode.id );
  3571. *
  3572. * </script>
  3573. *
  3574. */
  3575. setAttributes: function (node, attrs) {
  3576. for (var attr in attrs) {
  3577. if (attrs.hasOwnProperty(attr)) {
  3578. var value = attrs[attr];
  3579. switch (attr) {
  3580. case "class":
  3581. //ie下要这样赋值,setAttribute不起作用
  3582. node.className = value;
  3583. break;
  3584. case "style":
  3585. node.style.cssText = node.style.cssText + ";" + value;
  3586. break;
  3587. case "innerHTML":
  3588. node[attr] = value;
  3589. break;
  3590. case "value":
  3591. node.value = value;
  3592. break;
  3593. default:
  3594. node.setAttribute(attrFix[attr] || attr, value);
  3595. }
  3596. }
  3597. }
  3598. return node;
  3599. },
  3600. /**
  3601. * 获取元素element经过计算后的样式值
  3602. * @method getComputedStyle
  3603. * @param { Element } element 需要获取样式的元素对象
  3604. * @param { String } styleName 需要获取的样式名
  3605. * @return { String } 获取到的样式值
  3606. * @example
  3607. * ```html
  3608. * <style type="text/css">
  3609. * #test {
  3610. * font-size: 15px;
  3611. * }
  3612. * </style>
  3613. *
  3614. * <span id="test"></span>
  3615. *
  3616. * <script>
  3617. * //output: 15px
  3618. * console.log( UE.dom.domUtils.getComputedStyle( document.getElementById( "test" ), 'font-size' ) );
  3619. * </script>
  3620. * ```
  3621. */
  3622. getComputedStyle: function (element, styleName) {
  3623. //一下的属性单独处理
  3624. var pros = "width height top left";
  3625. if (pros.indexOf(styleName) > -1) {
  3626. return (
  3627. element[
  3628. "offset" +
  3629. styleName.replace(/^\w/, function (s) {
  3630. return s.toUpperCase();
  3631. })
  3632. ] + "px"
  3633. );
  3634. }
  3635. //忽略文本节点
  3636. if (element.nodeType == 3) {
  3637. element = element.parentNode;
  3638. }
  3639. //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改.
  3640. if (
  3641. browser.ie &&
  3642. browser.version < 9 &&
  3643. styleName == "font-size" &&
  3644. !element.style.fontSize &&
  3645. !dtd.$empty[element.tagName] &&
  3646. !dtd.$nonChild[element.tagName]
  3647. ) {
  3648. var span = element.ownerDocument.createElement("span");
  3649. span.style.cssText = "padding:0;border:0;font-family:simsun;";
  3650. span.innerHTML = ".";
  3651. element.appendChild(span);
  3652. var result = span.offsetHeight;
  3653. element.removeChild(span);
  3654. span = null;
  3655. return result + "px";
  3656. }
  3657. try {
  3658. var value =
  3659. domUtils.getStyle(element, styleName) ||
  3660. (window.getComputedStyle
  3661. ? domUtils
  3662. .getWindow(element)
  3663. .getComputedStyle(element, "")
  3664. .getPropertyValue(styleName)
  3665. : (element.currentStyle || element.style)[
  3666. utils.cssStyleToDomStyle(styleName)
  3667. ]);
  3668. } catch (e) {
  3669. return "";
  3670. }
  3671. return utils.transUnitToPx(utils.fixColor(styleName, value));
  3672. },
  3673. /**
  3674. * 删除元素element指定的className
  3675. * @method removeClasses
  3676. * @param { Element } ele 需要删除class的元素节点
  3677. * @param { String } classNames 需要删除的className, 多个className之间以空格分开
  3678. * @example
  3679. * ```html
  3680. * <span id="test" class="test1 test2 test3">xxx</span>
  3681. *
  3682. * <script>
  3683. *
  3684. * var testNode = document.getElementById( "test" );
  3685. * UE.dom.domUtils.removeClasses( testNode, "test1 test2" );
  3686. *
  3687. * //output: test3
  3688. * console.log( testNode.className );
  3689. *
  3690. * </script>
  3691. * ```
  3692. */
  3693. /**
  3694. * 删除元素element指定的className
  3695. * @method removeClasses
  3696. * @param { Element } ele 需要删除class的元素节点
  3697. * @param { Array } classNames 需要删除的className数组
  3698. * @example
  3699. * ```html
  3700. * <span id="test" class="test1 test2 test3">xxx</span>
  3701. *
  3702. * <script>
  3703. *
  3704. * var testNode = document.getElementById( "test" );
  3705. * UE.dom.domUtils.removeClasses( testNode, ["test1", "test2"] );
  3706. *
  3707. * //output: test3
  3708. * console.log( testNode.className );
  3709. *
  3710. * </script>
  3711. * ```
  3712. */
  3713. removeClasses: function (elm, classNames) {
  3714. classNames = utils.isArray(classNames)
  3715. ? classNames
  3716. : utils.trim(classNames).replace(/[ ]{2,}/g, " ").split(" ");
  3717. for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]);) {
  3718. cls = cls.replace(new RegExp("\\b" + ci + "\\b"), "");
  3719. }
  3720. cls = utils.trim(cls).replace(/[ ]{2,}/g, " ");
  3721. if (cls) {
  3722. elm.className = cls;
  3723. } else {
  3724. domUtils.removeAttributes(elm, ["class"]);
  3725. }
  3726. },
  3727. /**
  3728. * 给元素element添加className
  3729. * @method addClass
  3730. * @param { Node } ele 需要增加className的元素
  3731. * @param { String } classNames 需要添加的className, 多个className之间以空格分割
  3732. * @remind 相同的类名不会被重复添加
  3733. * @example
  3734. * ```html
  3735. * <span id="test" class="cls1 cls2"></span>
  3736. *
  3737. * <script>
  3738. * var testNode = document.getElementById("test");
  3739. *
  3740. * UE.dom.domUtils.addClass( testNode, "cls2 cls3 cls4" );
  3741. *
  3742. * //output: cl1 cls2 cls3 cls4
  3743. * console.log( testNode.className );
  3744. *
  3745. * <script>
  3746. * ```
  3747. */
  3748. /**
  3749. * 给元素element添加className
  3750. * @method addClass
  3751. * @param { Node } ele 需要增加className的元素
  3752. * @param { Array } classNames 需要添加的className的数组
  3753. * @remind 相同的类名不会被重复添加
  3754. * @example
  3755. * ```html
  3756. * <span id="test" class="cls1 cls2"></span>
  3757. *
  3758. * <script>
  3759. * var testNode = document.getElementById("test");
  3760. *
  3761. * UE.dom.domUtils.addClass( testNode, ["cls2", "cls3", "cls4"] );
  3762. *
  3763. * //output: cl1 cls2 cls3 cls4
  3764. * console.log( testNode.className );
  3765. *
  3766. * <script>
  3767. * ```
  3768. */
  3769. addClass: function (elm, classNames) {
  3770. if (!elm) return;
  3771. classNames = utils.trim(classNames).replace(/[ ]{2,}/g, " ").split(" ");
  3772. for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]);) {
  3773. if (!new RegExp("\\b" + ci + "\\b").test(cls)) {
  3774. cls += " " + ci;
  3775. }
  3776. }
  3777. elm.className = utils.trim(cls);
  3778. },
  3779. /**
  3780. * 判断元素element是否包含给定的样式类名className
  3781. * @method hasClass
  3782. * @param { Node } ele 需要检测的元素
  3783. * @param { String } classNames 需要检测的className, 多个className之间用空格分割
  3784. * @return { Boolean } 元素是否包含所有给定的className
  3785. * @example
  3786. * ```html
  3787. * <span id="test1" class="cls1 cls2"></span>
  3788. *
  3789. * <script>
  3790. * var test1 = document.getElementById("test1");
  3791. *
  3792. * //output: false
  3793. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1 cls3" ) );
  3794. *
  3795. * //output: true
  3796. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1" ) );
  3797. * </script>
  3798. * ```
  3799. */
  3800. /**
  3801. * 判断元素element是否包含给定的样式类名className
  3802. * @method hasClass
  3803. * @param { Node } ele 需要检测的元素
  3804. * @param { Array } classNames 需要检测的className数组
  3805. * @return { Boolean } 元素是否包含所有给定的className
  3806. * @example
  3807. * ```html
  3808. * <span id="test1" class="cls1 cls2"></span>
  3809. *
  3810. * <script>
  3811. * var test1 = document.getElementById("test1");
  3812. *
  3813. * //output: false
  3814. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1", "cls3" ] ) );
  3815. *
  3816. * //output: true
  3817. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1" ]) );
  3818. * </script>
  3819. * ```
  3820. */
  3821. hasClass: function (element, className) {
  3822. if (utils.isRegExp(className)) {
  3823. return className.test(element.className);
  3824. }
  3825. className = utils.trim(className).replace(/[ ]{2,}/g, " ").split(" ");
  3826. for (var i = 0, ci, cls = element.className; (ci = className[i++]);) {
  3827. if (!new RegExp("\\b" + ci + "\\b", "i").test(cls)) {
  3828. return false;
  3829. }
  3830. }
  3831. return i - 1 == className.length;
  3832. },
  3833. /**
  3834. * 阻止事件默认行为
  3835. * @method preventDefault
  3836. * @param { Event } evt 需要阻止默认行为的事件对象
  3837. * @example
  3838. * ```javascript
  3839. * UE.dom.domUtils.preventDefault( evt );
  3840. * ```
  3841. */
  3842. preventDefault: function (evt) {
  3843. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  3844. },
  3845. /**
  3846. * 删除元素element指定的样式
  3847. * @method removeStyle
  3848. * @param { Element } element 需要删除样式的元素
  3849. * @param { String } styleName 需要删除的样式名
  3850. * @example
  3851. * ```html
  3852. * <span id="test" style="color: red; background: blue;"></span>
  3853. *
  3854. * <script>
  3855. *
  3856. * var testNode = document.getElementById("test");
  3857. *
  3858. * UE.dom.domUtils.removeStyle( testNode, 'color' );
  3859. *
  3860. * //output: background: blue;
  3861. * console.log( testNode.style.cssText );
  3862. *
  3863. * </script>
  3864. * ```
  3865. */
  3866. removeStyle: function (element, name) {
  3867. if (browser.ie) {
  3868. //针对color先单独处理一下
  3869. if (name == "color") {
  3870. name = "(^|;)" + name;
  3871. }
  3872. element.style.cssText = element.style.cssText.replace(
  3873. new RegExp(name + "[^:]*:[^;]+;?", "ig"),
  3874. ""
  3875. );
  3876. } else {
  3877. if (element.style.removeProperty) {
  3878. element.style.removeProperty(name);
  3879. } else {
  3880. element.style.removeAttribute(utils.cssStyleToDomStyle(name));
  3881. }
  3882. }
  3883. if (!element.style.cssText) {
  3884. domUtils.removeAttributes(element, ["style"]);
  3885. }
  3886. },
  3887. /**
  3888. * 获取元素element的style属性的指定值
  3889. * @method getStyle
  3890. * @param { Element } element 需要获取属性值的元素
  3891. * @param { String } styleName 需要获取的style的名称
  3892. * @warning 该方法仅获取元素style属性中所标明的值
  3893. * @return { String } 该元素包含指定的style属性值
  3894. * @example
  3895. * ```html
  3896. * <div id="test" style="color: red;"></div>
  3897. *
  3898. * <script>
  3899. *
  3900. * var testNode = document.getElementById( "test" );
  3901. *
  3902. * //output: red
  3903. * console.log( UE.dom.domUtils.getStyle( testNode, "color" ) );
  3904. *
  3905. * //output: ""
  3906. * console.log( UE.dom.domUtils.getStyle( testNode, "background" ) );
  3907. *
  3908. * </script>
  3909. * ```
  3910. */
  3911. getStyle: function (element, name) {
  3912. var value = element.style[utils.cssStyleToDomStyle(name)];
  3913. return utils.fixColor(name, value);
  3914. },
  3915. /**
  3916. * 为元素element设置样式属性值
  3917. * @method setStyle
  3918. * @param { Element } element 需要设置样式的元素
  3919. * @param { String } styleName 样式名
  3920. * @param { String } styleValue 样式值
  3921. * @example
  3922. * ```html
  3923. * <div id="test"></div>
  3924. *
  3925. * <script>
  3926. *
  3927. * var testNode = document.getElementById( "test" );
  3928. *
  3929. * //output: ""
  3930. * console.log( testNode.style.color );
  3931. *
  3932. * UE.dom.domUtils.setStyle( testNode, 'color', 'red' );
  3933. * //output: "red"
  3934. * console.log( testNode.style.color );
  3935. *
  3936. * </script>
  3937. * ```
  3938. */
  3939. setStyle: function (element, name, value) {
  3940. element.style[utils.cssStyleToDomStyle(name)] = value;
  3941. if (!utils.trim(element.style.cssText)) {
  3942. this.removeAttributes(element, "style");
  3943. }
  3944. },
  3945. /**
  3946. * 为元素element设置多个样式属性值
  3947. * @method setStyles
  3948. * @param { Element } element 需要设置样式的元素
  3949. * @param { Object } styles 样式名值对
  3950. * @example
  3951. * ```html
  3952. * <div id="test"></div>
  3953. *
  3954. * <script>
  3955. *
  3956. * var testNode = document.getElementById( "test" );
  3957. *
  3958. * //output: ""
  3959. * console.log( testNode.style.color );
  3960. *
  3961. * UE.dom.domUtils.setStyles( testNode, {
  3962. * 'color': 'red'
  3963. * } );
  3964. * //output: "red"
  3965. * console.log( testNode.style.color );
  3966. *
  3967. * </script>
  3968. * ```
  3969. */
  3970. setStyles: function (element, styles) {
  3971. for (var name in styles) {
  3972. if (styles.hasOwnProperty(name)) {
  3973. domUtils.setStyle(element, name, styles[name]);
  3974. }
  3975. }
  3976. },
  3977. /**
  3978. * 删除_moz_dirty属性
  3979. * @private
  3980. * @method removeDirtyAttr
  3981. */
  3982. removeDirtyAttr: function (node) {
  3983. for (
  3984. var i = 0, ci, nodes = node.getElementsByTagName("*");
  3985. (ci = nodes[i++]);
  3986. ) {
  3987. ci.removeAttribute("_moz_dirty");
  3988. }
  3989. node.removeAttribute("_moz_dirty");
  3990. },
  3991. /**
  3992. * 获取子节点的数量
  3993. * @method getChildCount
  3994. * @param { Element } node 需要检测的元素
  3995. * @return { Number } 给定的node元素的子节点数量
  3996. * @example
  3997. * ```html
  3998. * <div id="test">
  3999. * <span></span>
  4000. * </div>
  4001. *
  4002. * <script>
  4003. *
  4004. * //output: 3
  4005. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test") ) );
  4006. *
  4007. * </script>
  4008. * ```
  4009. */
  4010. /**
  4011. * 根据给定的过滤规则, 获取符合条件的子节点的数量
  4012. * @method getChildCount
  4013. * @param { Element } node 需要检测的元素
  4014. * @param { Function } fn 过滤器, 要求对符合条件的子节点返回true, 反之则要求返回false
  4015. * @return { Number } 符合过滤条件的node元素的子节点数量
  4016. * @example
  4017. * ```html
  4018. * <div id="test">
  4019. * <span></span>
  4020. * </div>
  4021. *
  4022. * <script>
  4023. *
  4024. * //output: 1
  4025. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test"), function ( node ) {
  4026. *
  4027. * return node.nodeType === 1;
  4028. *
  4029. * } ) );
  4030. *
  4031. * </script>
  4032. * ```
  4033. */
  4034. getChildCount: function (node, fn) {
  4035. var count = 0,
  4036. first = node.firstChild;
  4037. fn =
  4038. fn ||
  4039. function () {
  4040. return 1;
  4041. };
  4042. while (first) {
  4043. if (fn(first)) {
  4044. count++;
  4045. }
  4046. first = first.nextSibling;
  4047. }
  4048. return count;
  4049. },
  4050. /**
  4051. * 判断给定节点是否为空节点
  4052. * @method isEmptyNode
  4053. * @param { Node } node 需要检测的节点对象
  4054. * @return { Boolean } 节点是否为空
  4055. * @example
  4056. * ```javascript
  4057. * UE.dom.domUtils.isEmptyNode( document.body );
  4058. * ```
  4059. */
  4060. isEmptyNode: function (node) {
  4061. return (
  4062. !node.firstChild ||
  4063. domUtils.getChildCount(node, function (node) {
  4064. return (
  4065. !domUtils.isBr(node) &&
  4066. !domUtils.isBookmarkNode(node) &&
  4067. !domUtils.isWhitespace(node)
  4068. );
  4069. }) == 0
  4070. );
  4071. },
  4072. clearSelectedArr: function (nodes) {
  4073. var node;
  4074. while ((node = nodes.pop())) {
  4075. domUtils.removeAttributes(node, ["class"]);
  4076. }
  4077. },
  4078. /**
  4079. * 将显示区域滚动到指定节点的位置
  4080. * @method scrollToView
  4081. * @param {Node} node 节点
  4082. * @param {window} win window对象
  4083. * @param {Number} offsetTop 距离上方的偏移量
  4084. */
  4085. scrollToView: function (node, win, offsetTop) {
  4086. var getViewPaneSize = function () {
  4087. var doc = win.document,
  4088. mode = doc.compatMode == "CSS1Compat";
  4089. return {
  4090. width:
  4091. (mode ? doc.documentElement.clientWidth : doc.body.clientWidth) || 0,
  4092. height:
  4093. (mode ? doc.documentElement.clientHeight : doc.body.clientHeight) || 0
  4094. };
  4095. },
  4096. getScrollPosition = function (win) {
  4097. if ("pageXOffset" in win) {
  4098. return {
  4099. x: win.pageXOffset || 0,
  4100. y: win.pageYOffset || 0
  4101. };
  4102. } else {
  4103. var doc = win.document;
  4104. return {
  4105. x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
  4106. y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
  4107. };
  4108. }
  4109. };
  4110. var winHeight = getViewPaneSize().height,
  4111. offset = winHeight * -1 + offsetTop;
  4112. offset += node.offsetHeight || 0;
  4113. var elementPosition = domUtils.getXY(node);
  4114. offset += elementPosition.y;
  4115. var currentScroll = getScrollPosition(win).y;
  4116. // offset += 50;
  4117. if (offset > currentScroll || offset < currentScroll - winHeight) {
  4118. win.scrollTo(0, offset + (offset < 0 ? -20 : 20));
  4119. }
  4120. },
  4121. /**
  4122. * 判断给定节点是否为br
  4123. * @method isBr
  4124. * @param { Node } node 需要判断的节点对象
  4125. * @return { Boolean } 给定的节点是否是br节点
  4126. */
  4127. isBr: function (node) {
  4128. return node.nodeType == 1 && node.tagName == "BR";
  4129. },
  4130. /**
  4131. * 判断给定的节点是否是一个“填充”节点
  4132. * @private
  4133. * @method isFillChar
  4134. * @param { Node } node 需要判断的节点
  4135. * @param { Boolean } isInStart 是否从节点内容的开始位置匹配
  4136. * @returns { Boolean } 节点是否是填充节点
  4137. */
  4138. isFillChar: function (node, isInStart) {
  4139. if (node.nodeType != 3) return false;
  4140. var text = node.nodeValue;
  4141. if (isInStart) {
  4142. return new RegExp("^" + domUtils.fillChar).test(text);
  4143. }
  4144. return !text.replace(new RegExp(domUtils.fillChar, "g"), "").length;
  4145. },
  4146. isStartInblock: function (range) {
  4147. var tmpRange = range.cloneRange(),
  4148. flag = 0,
  4149. start = tmpRange.startContainer,
  4150. tmp;
  4151. if (start.nodeType == 1 && start.childNodes[tmpRange.startOffset]) {
  4152. start = start.childNodes[tmpRange.startOffset];
  4153. var pre = start.previousSibling;
  4154. while (pre && domUtils.isFillChar(pre)) {
  4155. start = pre;
  4156. pre = pre.previousSibling;
  4157. }
  4158. }
  4159. if (this.isFillChar(start, true) && tmpRange.startOffset == 1) {
  4160. tmpRange.setStartBefore(start);
  4161. start = tmpRange.startContainer;
  4162. }
  4163. while (start && domUtils.isFillChar(start)) {
  4164. tmp = start;
  4165. start = start.previousSibling;
  4166. }
  4167. if (tmp) {
  4168. tmpRange.setStartBefore(tmp);
  4169. start = tmpRange.startContainer;
  4170. }
  4171. if (
  4172. start.nodeType == 1 &&
  4173. domUtils.isEmptyNode(start) &&
  4174. tmpRange.startOffset == 1
  4175. ) {
  4176. tmpRange.setStart(start, 0).collapse(true);
  4177. }
  4178. while (!tmpRange.startOffset) {
  4179. start = tmpRange.startContainer;
  4180. if (domUtils.isBlockElm(start) || domUtils.isBody(start)) {
  4181. flag = 1;
  4182. break;
  4183. }
  4184. var pre = tmpRange.startContainer.previousSibling,
  4185. tmpNode;
  4186. if (!pre) {
  4187. tmpRange.setStartBefore(tmpRange.startContainer);
  4188. } else {
  4189. while (pre && domUtils.isFillChar(pre)) {
  4190. tmpNode = pre;
  4191. pre = pre.previousSibling;
  4192. }
  4193. if (tmpNode) {
  4194. tmpRange.setStartBefore(tmpNode);
  4195. } else {
  4196. tmpRange.setStartBefore(tmpRange.startContainer);
  4197. }
  4198. }
  4199. }
  4200. return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0;
  4201. },
  4202. /**
  4203. * 判断给定的元素是否是一个空元素
  4204. * @method isEmptyBlock
  4205. * @param { Element } node 需要判断的元素
  4206. * @return { Boolean } 是否是空元素
  4207. * @example
  4208. * ```html
  4209. * <div id="test"></div>
  4210. *
  4211. * <script>
  4212. * //output: true
  4213. * console.log( UE.dom.domUtils.isEmptyBlock( document.getElementById("test") ) );
  4214. * </script>
  4215. * ```
  4216. */
  4217. /**
  4218. * 根据指定的判断规则判断给定的元素是否是一个空元素
  4219. * @method isEmptyBlock
  4220. * @param { Element } node 需要判断的元素
  4221. * @param { RegExp } reg 对内容执行判断的正则表达式对象
  4222. * @return { Boolean } 是否是空元素
  4223. */
  4224. isEmptyBlock: function (node, reg) {
  4225. if (node.nodeType != 1) return 0;
  4226. reg = reg || new RegExp("[ \xa0\t\r\n" + domUtils.fillChar + "]", "g");
  4227. if (
  4228. node[browser.ie ? "innerText" : "textContent"].replace(reg, "").length > 0
  4229. ) {
  4230. return 0;
  4231. }
  4232. for (var n in dtd.$isNotEmpty) {
  4233. if (node.getElementsByTagName(n).length) {
  4234. return 0;
  4235. }
  4236. }
  4237. return 1;
  4238. },
  4239. /**
  4240. * 移动元素使得该元素的位置移动指定的偏移量的距离
  4241. * @method setViewportOffset
  4242. * @param { Element } element 需要设置偏移量的元素
  4243. * @param { Object } offset 偏移量, 形如{ left: 100, top: 50 }的一个键值对, 表示该元素将在
  4244. * 现有的位置上向水平方向偏移offset.left的距离, 在竖直方向上偏移
  4245. * offset.top的距离
  4246. * @example
  4247. * ```html
  4248. * <div id="test" style="top: 100px; left: 50px; position: absolute;"></div>
  4249. *
  4250. * <script>
  4251. *
  4252. * var testNode = document.getElementById("test");
  4253. *
  4254. * UE.dom.domUtils.setViewportOffset( testNode, {
  4255. * left: 200,
  4256. * top: 50
  4257. * } );
  4258. *
  4259. * //output: top: 300px; left: 100px; position: absolute;
  4260. * console.log( testNode.style.cssText );
  4261. *
  4262. * </script>
  4263. * ```
  4264. */
  4265. setViewportOffset: function (element, offset) {
  4266. var left = parseInt(element.style.left) | 0;
  4267. var top = parseInt(element.style.top) | 0;
  4268. var rect = element.getBoundingClientRect();
  4269. var offsetLeft = offset.left - rect.left;
  4270. var offsetTop = offset.top - rect.top;
  4271. if (offsetLeft) {
  4272. element.style.left = left + offsetLeft + "px";
  4273. }
  4274. if (offsetTop) {
  4275. element.style.top = top + offsetTop + "px";
  4276. }
  4277. },
  4278. /**
  4279. * 用“填充字符”填充节点
  4280. * @method fillNode
  4281. * @private
  4282. * @param { DomDocument } doc 填充的节点所在的docment对象
  4283. * @param { Node } node 需要填充的节点对象
  4284. * @example
  4285. * ```html
  4286. * <div id="test"></div>
  4287. *
  4288. * <script>
  4289. * var testNode = document.getElementById("test");
  4290. *
  4291. * //output: 0
  4292. * console.log( testNode.childNodes.length );
  4293. *
  4294. * UE.dom.domUtils.fillNode( document, testNode );
  4295. *
  4296. * //output: 1
  4297. * console.log( testNode.childNodes.length );
  4298. *
  4299. * </script>
  4300. * ```
  4301. */
  4302. fillNode: function (doc, node) {
  4303. var tmpNode = browser.ie
  4304. ? doc.createTextNode(domUtils.fillChar)
  4305. : doc.createElement("br");
  4306. node.innerHTML = "";
  4307. node.appendChild(tmpNode);
  4308. },
  4309. /**
  4310. * 把节点src的所有子节点追加到另一个节点tag上去
  4311. * @method moveChild
  4312. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  4313. * @param { Node } tag 目标节点, 从源节点移除的子节点将被追加到该节点下
  4314. * @example
  4315. * ```html
  4316. * <div id="test1">
  4317. * <span></span>
  4318. * </div>
  4319. * <div id="test2">
  4320. * <div></div>
  4321. * </div>
  4322. *
  4323. * <script>
  4324. *
  4325. * var test1 = document.getElementById("test1"),
  4326. * test2 = document.getElementById("test2");
  4327. *
  4328. * UE.dom.domUtils.moveChild( test1, test2 );
  4329. *
  4330. * //output: ""(空字符串)
  4331. * console.log( test1.innerHTML );
  4332. *
  4333. * //output: "<div></div><span></span>"
  4334. * console.log( test2.innerHTML );
  4335. *
  4336. * </script>
  4337. * ```
  4338. */
  4339. /**
  4340. * 把节点src的所有子节点移动到另一个节点tag上去, 可以通过dir参数控制附加的行为是“追加”还是“插入顶部”
  4341. * @method moveChild
  4342. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  4343. * @param { Node } tag 目标节点, 从源节点移除的子节点将被附加到该节点下
  4344. * @param { Boolean } dir 附加方式, 如果为true, 则附加进去的节点将被放到目标节点的顶部, 反之,则放到末尾
  4345. * @example
  4346. * ```html
  4347. * <div id="test1">
  4348. * <span></span>
  4349. * </div>
  4350. * <div id="test2">
  4351. * <div></div>
  4352. * </div>
  4353. *
  4354. * <script>
  4355. *
  4356. * var test1 = document.getElementById("test1"),
  4357. * test2 = document.getElementById("test2");
  4358. *
  4359. * UE.dom.domUtils.moveChild( test1, test2, true );
  4360. *
  4361. * //output: ""(空字符串)
  4362. * console.log( test1.innerHTML );
  4363. *
  4364. * //output: "<span></span><div></div>"
  4365. * console.log( test2.innerHTML );
  4366. *
  4367. * </script>
  4368. * ```
  4369. */
  4370. moveChild: function (src, tag, dir) {
  4371. while (src.firstChild) {
  4372. if (dir && tag.firstChild) {
  4373. tag.insertBefore(src.lastChild, tag.firstChild);
  4374. } else {
  4375. tag.appendChild(src.firstChild);
  4376. }
  4377. }
  4378. },
  4379. /**
  4380. * 判断节点的标签上是否不存在任何属性
  4381. * @method hasNoAttributes
  4382. * @private
  4383. * @param { Node } node 需要检测的节点对象
  4384. * @return { Boolean } 节点是否不包含任何属性
  4385. * @example
  4386. * ```html
  4387. * <div id="test"><span>xxxx</span></div>
  4388. *
  4389. * <script>
  4390. *
  4391. * //output: false
  4392. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test") ) );
  4393. *
  4394. * //output: true
  4395. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test").firstChild ) );
  4396. *
  4397. * </script>
  4398. * ```
  4399. */
  4400. hasNoAttributes: function (node) {
  4401. return browser.ie
  4402. ? /^<\w+\s*?>/.test(node.outerHTML)
  4403. : node.attributes.length == 0;
  4404. },
  4405. /**
  4406. * 检测节点是否是UEditor所使用的辅助节点
  4407. * @method isCustomeNode
  4408. * @private
  4409. * @param { Node } node 需要检测的节点
  4410. * @remind 辅助节点是指编辑器要完成工作临时添加的节点, 在输出的时候将会从编辑器内移除, 不会影响最终的结果。
  4411. * @return { Boolean } 给定的节点是否是一个辅助节点
  4412. */
  4413. isCustomeNode: function (node) {
  4414. return node.nodeType == 1 && node.getAttribute("_ue_custom_node_");
  4415. },
  4416. /**
  4417. * 检测节点的标签是否是给定的标签
  4418. * @method isTagNode
  4419. * @param { Node } node 需要检测的节点对象
  4420. * @param { String } tagName 标签
  4421. * @return { Boolean } 节点的标签是否是给定的标签
  4422. * @example
  4423. * ```html
  4424. * <div id="test"></div>
  4425. *
  4426. * <script>
  4427. *
  4428. * //output: true
  4429. * console.log( UE.dom.domUtils.isTagNode( document.getElementById("test"), "div" ) );
  4430. *
  4431. * </script>
  4432. * ```
  4433. */
  4434. isTagNode: function (node, tagNames) {
  4435. return (
  4436. node.nodeType == 1 &&
  4437. new RegExp("\\b" + node.tagName + "\\b", "i").test(tagNames)
  4438. );
  4439. },
  4440. /**
  4441. * 给定一个节点数组,在通过指定的过滤器过滤后, 获取其中满足过滤条件的第一个节点
  4442. * @method filterNodeList
  4443. * @param { Array } nodeList 需要过滤的节点数组
  4444. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  4445. * @return { Node | NULL } 如果找到符合过滤条件的节点, 则返回该节点, 否则返回NULL
  4446. * @example
  4447. * ```javascript
  4448. * var divNodes = document.getElementsByTagName("div");
  4449. * divNodes = [].slice.call( divNodes, 0 );
  4450. *
  4451. * //output: null
  4452. * console.log( UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4453. * return node.tagName.toLowerCase() !== 'div';
  4454. * } ) );
  4455. * ```
  4456. */
  4457. /**
  4458. * 给定一个节点数组nodeList和一组标签名tagNames, 获取其中能够匹配标签名的节点集合中的第一个节点
  4459. * @method filterNodeList
  4460. * @param { Array } nodeList 需要过滤的节点数组
  4461. * @param { String } tagNames 需要匹配的标签名, 多个标签名之间用空格分割
  4462. * @return { Node | NULL } 如果找到标签名匹配的节点, 则返回该节点, 否则返回NULL
  4463. * @example
  4464. * ```javascript
  4465. * var divNodes = document.getElementsByTagName("div");
  4466. * divNodes = [].slice.call( divNodes, 0 );
  4467. *
  4468. * //output: null
  4469. * console.log( UE.dom.domUtils.filterNodeList( divNodes, 'a span' ) );
  4470. * ```
  4471. */
  4472. /**
  4473. * 给定一个节点数组,在通过指定的过滤器过滤后, 如果参数forAll为true, 则会返回所有满足过滤
  4474. * 条件的节点集合, 否则, 返回满足条件的节点集合中的第一个节点
  4475. * @method filterNodeList
  4476. * @param { Array } nodeList 需要过滤的节点数组
  4477. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  4478. * @param { Boolean } forAll 是否返回整个节点数组, 如果该参数为false, 则返回节点集合中的第一个节点
  4479. * @return { Array | Node | NULL } 如果找到符合过滤条件的节点, 则根据参数forAll的值决定返回满足
  4480. * 过滤条件的节点数组或第一个节点, 否则返回NULL
  4481. * @example
  4482. * ```javascript
  4483. * var divNodes = document.getElementsByTagName("div");
  4484. * divNodes = [].slice.call( divNodes, 0 );
  4485. *
  4486. * //output: 3(假定有3个div)
  4487. * console.log( divNodes.length );
  4488. *
  4489. * var nodes = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4490. * return node.tagName.toLowerCase() === 'div';
  4491. * }, true );
  4492. *
  4493. * //output: 3
  4494. * console.log( nodes.length );
  4495. *
  4496. * var node = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4497. * return node.tagName.toLowerCase() === 'div';
  4498. * }, false );
  4499. *
  4500. * //output: div
  4501. * console.log( node.nodeName );
  4502. * ```
  4503. */
  4504. filterNodeList: function (nodelist, filter, forAll) {
  4505. var results = [];
  4506. if (!utils.isFunction(filter)) {
  4507. var str = filter;
  4508. filter = function (n) {
  4509. return (
  4510. utils.indexOf(
  4511. utils.isArray(str) ? str : str.split(" "),
  4512. n.tagName.toLowerCase()
  4513. ) != -1
  4514. );
  4515. };
  4516. }
  4517. utils.each(nodelist, function (n) {
  4518. filter(n) && results.push(n);
  4519. });
  4520. return results.length == 0
  4521. ? null
  4522. : results.length == 1 || !forAll ? results[0] : results;
  4523. },
  4524. /**
  4525. * 查询给定的range选区是否在给定的node节点内,且在该节点的最末尾
  4526. * @method isInNodeEndBoundary
  4527. * @param { UE.dom.Range } rng 需要判断的range对象, 该对象的startContainer不能为NULL
  4528. * @param node 需要检测的节点对象
  4529. * @return { Number } 如果给定的选取range对象是在node内部的最末端, 则返回1, 否则返回0
  4530. */
  4531. isInNodeEndBoundary: function (rng, node) {
  4532. var start = rng.startContainer;
  4533. if (start.nodeType == 3 && rng.startOffset != start.nodeValue.length) {
  4534. return 0;
  4535. }
  4536. if (start.nodeType == 1 && rng.startOffset != start.childNodes.length) {
  4537. return 0;
  4538. }
  4539. while (start !== node) {
  4540. if (start.nextSibling) {
  4541. return 0;
  4542. }
  4543. start = start.parentNode;
  4544. }
  4545. return 1;
  4546. },
  4547. isBoundaryNode: function (node, dir) {
  4548. var tmp;
  4549. while (!domUtils.isBody(node)) {
  4550. tmp = node;
  4551. node = node.parentNode;
  4552. if (tmp !== node[dir]) {
  4553. return false;
  4554. }
  4555. }
  4556. return true;
  4557. },
  4558. fillHtml: browser.ie11below ? "&nbsp;" : "<br/>"
  4559. });
  4560. var fillCharReg = new RegExp(domUtils.fillChar, "g");
  4561. // core/Range.js
  4562. /**
  4563. * Range封装
  4564. * @file
  4565. * @module UE.dom
  4566. * @class Range
  4567. * @since 1.2.6.1
  4568. */
  4569. /**
  4570. * dom操作封装
  4571. * @unfile
  4572. * @module UE.dom
  4573. */
  4574. /**
  4575. * Range实现类,本类是UEditor底层核心类,封装不同浏览器之间的Range操作。
  4576. * @unfile
  4577. * @module UE.dom
  4578. * @class Range
  4579. */
  4580. ;(function () {
  4581. var guid = 0,
  4582. fillChar = domUtils.fillChar,
  4583. fillData;
  4584. /**
  4585. * 更新range的collapse状态
  4586. * @param {Range} range range对象
  4587. */
  4588. function updateCollapse(range) {
  4589. range.collapsed =
  4590. range.startContainer &&
  4591. range.endContainer &&
  4592. range.startContainer === range.endContainer &&
  4593. range.startOffset == range.endOffset;
  4594. }
  4595. function selectOneNode(rng) {
  4596. return (
  4597. !rng.collapsed &&
  4598. rng.startContainer.nodeType == 1 &&
  4599. rng.startContainer === rng.endContainer &&
  4600. rng.endOffset - rng.startOffset == 1
  4601. );
  4602. }
  4603. function setEndPoint(toStart, node, offset, range) {
  4604. //如果node是自闭合标签要处理
  4605. if (
  4606. node.nodeType == 1 &&
  4607. (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])
  4608. ) {
  4609. offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1);
  4610. node = node.parentNode;
  4611. }
  4612. if (toStart) {
  4613. range.startContainer = node;
  4614. range.startOffset = offset;
  4615. if (!range.endContainer) {
  4616. range.collapse(true);
  4617. }
  4618. } else {
  4619. range.endContainer = node;
  4620. range.endOffset = offset;
  4621. if (!range.startContainer) {
  4622. range.collapse(false);
  4623. }
  4624. }
  4625. updateCollapse(range);
  4626. return range;
  4627. }
  4628. function execContentsAction(range, action) {
  4629. //调整边界
  4630. //range.includeBookmark();
  4631. var start = range.startContainer,
  4632. end = range.endContainer,
  4633. startOffset = range.startOffset,
  4634. endOffset = range.endOffset,
  4635. doc = range.document,
  4636. frag = doc.createDocumentFragment(),
  4637. tmpStart,
  4638. tmpEnd;
  4639. if (start.nodeType == 1) {
  4640. start =
  4641. start.childNodes[startOffset] ||
  4642. (tmpStart = start.appendChild(doc.createTextNode("")));
  4643. }
  4644. if (end.nodeType == 1) {
  4645. end =
  4646. end.childNodes[endOffset] ||
  4647. (tmpEnd = end.appendChild(doc.createTextNode("")));
  4648. }
  4649. if (start === end && start.nodeType == 3) {
  4650. frag.appendChild(
  4651. doc.createTextNode(
  4652. start.substringData(startOffset, endOffset - startOffset)
  4653. )
  4654. );
  4655. //is not clone
  4656. if (action) {
  4657. start.deleteData(startOffset, endOffset - startOffset);
  4658. range.collapse(true);
  4659. }
  4660. return frag;
  4661. }
  4662. var current,
  4663. currentLevel,
  4664. clone = frag,
  4665. startParents = domUtils.findParents(start, true),
  4666. endParents = domUtils.findParents(end, true);
  4667. for (var i = 0; startParents[i] == endParents[i];) {
  4668. i++;
  4669. }
  4670. for (var j = i, si; (si = startParents[j]); j++) {
  4671. current = si.nextSibling;
  4672. if (si == start) {
  4673. if (!tmpStart) {
  4674. if (range.startContainer.nodeType == 3) {
  4675. clone.appendChild(
  4676. doc.createTextNode(start.nodeValue.slice(startOffset))
  4677. );
  4678. //is not clone
  4679. if (action) {
  4680. start.deleteData(
  4681. startOffset,
  4682. start.nodeValue.length - startOffset
  4683. );
  4684. }
  4685. } else {
  4686. clone.appendChild(!action ? start.cloneNode(true) : start);
  4687. }
  4688. }
  4689. } else {
  4690. currentLevel = si.cloneNode(false);
  4691. clone.appendChild(currentLevel);
  4692. }
  4693. while (current) {
  4694. if (current === end || current === endParents[j]) {
  4695. break;
  4696. }
  4697. si = current.nextSibling;
  4698. clone.appendChild(!action ? current.cloneNode(true) : current);
  4699. current = si;
  4700. }
  4701. clone = currentLevel;
  4702. }
  4703. clone = frag;
  4704. if (!startParents[i]) {
  4705. clone.appendChild(startParents[i - 1].cloneNode(false));
  4706. clone = clone.firstChild;
  4707. }
  4708. for (var j = i, ei; (ei = endParents[j]); j++) {
  4709. current = ei.previousSibling;
  4710. if (ei == end) {
  4711. if (!tmpEnd && range.endContainer.nodeType == 3) {
  4712. clone.appendChild(
  4713. doc.createTextNode(end.substringData(0, endOffset))
  4714. );
  4715. //is not clone
  4716. if (action) {
  4717. end.deleteData(0, endOffset);
  4718. }
  4719. }
  4720. } else {
  4721. currentLevel = ei.cloneNode(false);
  4722. clone.appendChild(currentLevel);
  4723. }
  4724. //如果两端同级,右边第一次已经被开始做了
  4725. if (j != i || !startParents[i]) {
  4726. while (current) {
  4727. if (current === start) {
  4728. break;
  4729. }
  4730. ei = current.previousSibling;
  4731. clone.insertBefore(
  4732. !action ? current.cloneNode(true) : current,
  4733. clone.firstChild
  4734. );
  4735. current = ei;
  4736. }
  4737. }
  4738. clone = currentLevel;
  4739. }
  4740. if (action) {
  4741. range
  4742. .setStartBefore(
  4743. !endParents[i]
  4744. ? endParents[i - 1]
  4745. : !startParents[i] ? startParents[i - 1] : endParents[i]
  4746. )
  4747. .collapse(true);
  4748. }
  4749. tmpStart && domUtils.remove(tmpStart);
  4750. tmpEnd && domUtils.remove(tmpEnd);
  4751. return frag;
  4752. }
  4753. /**
  4754. * 创建一个跟document绑定的空的Range实例
  4755. * @constructor
  4756. * @param { Document } document 新建的选区所属的文档对象
  4757. */
  4758. /**
  4759. * @property { Node } startContainer 当前Range的开始边界的容器节点, 可以是一个元素节点或者是文本节点
  4760. */
  4761. /**
  4762. * @property { Node } startOffset 当前Range的开始边界容器节点的偏移量, 如果是元素节点,
  4763. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4764. */
  4765. /**
  4766. * @property { Node } endContainer 当前Range的结束边界的容器节点, 可以是一个元素节点或者是文本节点
  4767. */
  4768. /**
  4769. * @property { Node } endOffset 当前Range的结束边界容器节点的偏移量, 如果是元素节点,
  4770. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4771. */
  4772. /**
  4773. * @property { Boolean } collapsed 当前Range是否闭合
  4774. * @default true
  4775. * @remind Range是闭合的时候, startContainer === endContainer && startOffset === endOffset
  4776. */
  4777. /**
  4778. * @property { Document } document 当前Range所属的Document对象
  4779. * @remind 不同range的的document属性可以是不同的
  4780. */
  4781. var Range = (dom.Range = function (document) {
  4782. var me = this;
  4783. me.startContainer = me.startOffset = me.endContainer = me.endOffset = null;
  4784. me.document = document;
  4785. me.collapsed = true;
  4786. });
  4787. /**
  4788. * 删除fillData
  4789. * @param doc
  4790. * @param excludeNode
  4791. */
  4792. function removeFillData(doc, excludeNode) {
  4793. try {
  4794. if (fillData && domUtils.inDoc(fillData, doc)) {
  4795. if (!fillData.nodeValue.replace(fillCharReg, "").length) {
  4796. var tmpNode = fillData.parentNode;
  4797. domUtils.remove(fillData);
  4798. while (
  4799. tmpNode &&
  4800. domUtils.isEmptyInlineElement(tmpNode) &&
  4801. //safari的contains有bug
  4802. (browser.safari
  4803. ? !(
  4804. domUtils.getPosition(tmpNode, excludeNode) &
  4805. domUtils.POSITION_CONTAINS
  4806. )
  4807. : !tmpNode.contains(excludeNode))
  4808. ) {
  4809. fillData = tmpNode.parentNode;
  4810. domUtils.remove(tmpNode);
  4811. tmpNode = fillData;
  4812. }
  4813. } else {
  4814. fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, "");
  4815. }
  4816. }
  4817. } catch (e) {
  4818. }
  4819. }
  4820. /**
  4821. * @param node
  4822. * @param dir
  4823. */
  4824. function mergeSibling(node, dir) {
  4825. var tmpNode;
  4826. node = node[dir];
  4827. while (node && domUtils.isFillChar(node)) {
  4828. tmpNode = node[dir];
  4829. domUtils.remove(node);
  4830. node = tmpNode;
  4831. }
  4832. }
  4833. Range.prototype = {
  4834. /**
  4835. * 克隆选区的内容到一个DocumentFragment里
  4836. * @method cloneContents
  4837. * @return { DocumentFragment | NULL } 如果选区是闭合的将返回null, 否则, 返回包含所clone内容的DocumentFragment元素
  4838. * @example
  4839. * ```html
  4840. * <body>
  4841. * <!-- 中括号表示选区 -->
  4842. * <b>x<i>x[x</i>xx]x</b>
  4843. *
  4844. * <script>
  4845. * //range是已选中的选区
  4846. * var fragment = range.cloneContents(),
  4847. * node = document.createElement("div");
  4848. *
  4849. * node.appendChild( fragment );
  4850. *
  4851. * //output: <i>x</i>xx
  4852. * console.log( node.innerHTML );
  4853. *
  4854. * </script>
  4855. * </body>
  4856. * ```
  4857. */
  4858. cloneContents: function () {
  4859. return this.collapsed ? null : execContentsAction(this, 0);
  4860. },
  4861. /**
  4862. * 删除当前选区范围中的所有内容
  4863. * @method deleteContents
  4864. * @remind 执行完该操作后, 当前Range对象变成了闭合状态
  4865. * @return { UE.dom.Range } 当前操作的Range对象
  4866. * @example
  4867. * ```html
  4868. * <body>
  4869. * <!-- 中括号表示选区 -->
  4870. * <b>x<i>x[x</i>xx]x</b>
  4871. *
  4872. * <script>
  4873. * //range是已选中的选区
  4874. * range.deleteContents();
  4875. *
  4876. * //竖线表示闭合后的选区位置
  4877. * //output: <b>x<i>x</i>|x</b>
  4878. * console.log( document.body.innerHTML );
  4879. *
  4880. * //此时, range的各项属性为
  4881. * //output: B
  4882. * console.log( range.startContainer.tagName );
  4883. * //output: 2
  4884. * console.log( range.startOffset );
  4885. * //output: B
  4886. * console.log( range.endContainer.tagName );
  4887. * //output: 2
  4888. * console.log( range.endOffset );
  4889. * //output: true
  4890. * console.log( range.collapsed );
  4891. *
  4892. * </script>
  4893. * </body>
  4894. * ```
  4895. */
  4896. deleteContents: function () {
  4897. var txt;
  4898. if (!this.collapsed) {
  4899. execContentsAction(this, 1);
  4900. }
  4901. if (browser.webkit) {
  4902. txt = this.startContainer;
  4903. if (txt.nodeType == 3 && !txt.nodeValue.length) {
  4904. this.setStartBefore(txt).collapse(true);
  4905. domUtils.remove(txt);
  4906. }
  4907. }
  4908. return this;
  4909. },
  4910. /**
  4911. * 将当前选区的内容提取到一个DocumentFragment里
  4912. * @method extractContents
  4913. * @remind 执行该操作后, 选区将变成闭合状态
  4914. * @warning 执行该操作后, 原来选区所选中的内容将从dom树上剥离出来
  4915. * @return { DocumentFragment } 返回包含所提取内容的DocumentFragment对象
  4916. * @example
  4917. * ```html
  4918. * <body>
  4919. * <!-- 中括号表示选区 -->
  4920. * <b>x<i>x[x</i>xx]x</b>
  4921. *
  4922. * <script>
  4923. * //range是已选中的选区
  4924. * var fragment = range.extractContents(),
  4925. * node = document.createElement( "div" );
  4926. *
  4927. * node.appendChild( fragment );
  4928. *
  4929. * //竖线表示闭合后的选区位置
  4930. *
  4931. * //output: <b>x<i>x</i>|x</b>
  4932. * console.log( document.body.innerHTML );
  4933. * //output: <i>x</i>xx
  4934. * console.log( node.innerHTML );
  4935. *
  4936. * //此时, range的各项属性为
  4937. * //output: B
  4938. * console.log( range.startContainer.tagName );
  4939. * //output: 2
  4940. * console.log( range.startOffset );
  4941. * //output: B
  4942. * console.log( range.endContainer.tagName );
  4943. * //output: 2
  4944. * console.log( range.endOffset );
  4945. * //output: true
  4946. * console.log( range.collapsed );
  4947. *
  4948. * </script>
  4949. * </body>
  4950. */
  4951. extractContents: function () {
  4952. return this.collapsed ? null : execContentsAction(this, 2);
  4953. },
  4954. /**
  4955. * 设置Range的开始容器节点和偏移量
  4956. * @method setStart
  4957. * @remind 如果给定的节点是元素节点,那么offset指的是其子元素中索引为offset的元素,
  4958. * 如果是文本节点,那么offset指的是其文本内容的第offset个字符
  4959. * @remind 如果提供的容器节点是一个不能包含子元素的节点, 则该选区的开始容器将被设置
  4960. * 为该节点的父节点, 此时, 其距离开始容器的偏移量也变成了该节点在其父节点
  4961. * 中的索引
  4962. * @param { Node } node 将被设为当前选区开始边界容器的节点对象
  4963. * @param { int } offset 选区的开始位置偏移量
  4964. * @return { UE.dom.Range } 当前range对象
  4965. * @example
  4966. * ```html
  4967. * <!-- 选区 -->
  4968. * <b>xxx<i>x<span>xx</span>xx<em>xx</em>xxx</i>[xxx]</b>
  4969. *
  4970. * <script>
  4971. *
  4972. * //执行操作
  4973. * range.setStart( document.getElementsByTagName("i")[0], 1 );
  4974. *
  4975. * //此时, 选区变成了
  4976. * //<b>xxx<i>x[<span>xx</span>xx<em>xx</em>xxx</i>xxx]</b>
  4977. *
  4978. * </script>
  4979. * ```
  4980. * @example
  4981. * ```html
  4982. * <!-- 选区 -->
  4983. * <b>xxx<img>[xx]x</b>
  4984. *
  4985. * <script>
  4986. *
  4987. * //执行操作
  4988. * range.setStart( document.getElementsByTagName("img")[0], 3 );
  4989. *
  4990. * //此时, 选区变成了
  4991. * //<b>xxx[<img>xx]x</b>
  4992. *
  4993. * </script>
  4994. * ```
  4995. */
  4996. setStart: function (node, offset) {
  4997. return setEndPoint(true, node, offset, this);
  4998. },
  4999. /**
  5000. * 设置Range的结束容器和偏移量
  5001. * @method setEnd
  5002. * @param { Node } node 作为当前选区结束边界容器的节点对象
  5003. * @param { int } offset 结束边界的偏移量
  5004. * @see UE.dom.Range:setStart(Node,int)
  5005. * @return { UE.dom.Range } 当前range对象
  5006. */
  5007. setEnd: function (node, offset) {
  5008. return setEndPoint(false, node, offset, this);
  5009. },
  5010. /**
  5011. * 将Range开始位置设置到node节点之后
  5012. * @method setStartAfter
  5013. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引+1
  5014. * @param { Node } node 选区的开始边界将紧接着该节点之后
  5015. * @return { UE.dom.Range } 当前range对象
  5016. * @example
  5017. * ```html
  5018. * <!-- 选区示例 -->
  5019. * <b>xx<i>xxx</i><span>xx[x</span>xxx]</b>
  5020. *
  5021. * <script>
  5022. *
  5023. * //执行操作
  5024. * range.setStartAfter( document.getElementsByTagName("i")[0] );
  5025. *
  5026. * //结果选区
  5027. * //<b>xx<i>xxx</i>[<span>xxx</span>xxx]</b>
  5028. *
  5029. * </script>
  5030. * ```
  5031. */
  5032. setStartAfter: function (node) {
  5033. return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1);
  5034. },
  5035. /**
  5036. * 将Range开始位置设置到node节点之前
  5037. * @method setStartBefore
  5038. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引
  5039. * @param { Node } node 新的选区开始位置在该节点之前
  5040. * @see UE.dom.Range:setStartAfter(Node)
  5041. * @return { UE.dom.Range } 当前range对象
  5042. */
  5043. setStartBefore: function (node) {
  5044. return this.setStart(node.parentNode, domUtils.getNodeIndex(node));
  5045. },
  5046. /**
  5047. * 将Range结束位置设置到node节点之后
  5048. * @method setEndAfter
  5049. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引+1
  5050. * @param { Node } node 目标节点
  5051. * @see UE.dom.Range:setStartAfter(Node)
  5052. * @return { UE.dom.Range } 当前range对象
  5053. * @example
  5054. * ```html
  5055. * <!-- 选区示例 -->
  5056. * <b>[xx<i>xxx</i><span>xx]x</span>xxx</b>
  5057. *
  5058. * <script>
  5059. *
  5060. * //执行操作
  5061. * range.setStartAfter( document.getElementsByTagName("span")[0] );
  5062. *
  5063. * //结果选区
  5064. * //<b>[xx<i>xxx</i><span>xxx</span>]xxx</b>
  5065. *
  5066. * </script>
  5067. * ```
  5068. */
  5069. setEndAfter: function (node) {
  5070. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1);
  5071. },
  5072. /**
  5073. * 将Range结束位置设置到node节点之前
  5074. * @method setEndBefore
  5075. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引
  5076. * @param { Node } node 目标节点
  5077. * @see UE.dom.Range:setEndAfter(Node)
  5078. * @return { UE.dom.Range } 当前range对象
  5079. */
  5080. setEndBefore: function (node) {
  5081. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node));
  5082. },
  5083. /**
  5084. * 设置Range的开始位置到node节点内的第一个子节点之前
  5085. * @method setStartAtFirst
  5086. * @remind 选区的开始容器将变成给定的节点, 且偏移量为0
  5087. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  5088. * @param { Node } node 目标节点
  5089. * @see UE.dom.Range:setStartBefore(Node)
  5090. * @return { UE.dom.Range } 当前range对象
  5091. * @example
  5092. * ```html
  5093. * <!-- 选区示例 -->
  5094. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5095. *
  5096. * <script>
  5097. *
  5098. * //执行操作
  5099. * range.setStartAtFirst( document.getElementsByTagName("i")[0] );
  5100. *
  5101. * //结果选区
  5102. * //<b>xx<i>[xxx</i><span>xx]x</span>xxx</b>
  5103. *
  5104. * </script>
  5105. * ```
  5106. */
  5107. setStartAtFirst: function (node) {
  5108. return this.setStart(node, 0);
  5109. },
  5110. /**
  5111. * 设置Range的开始位置到node节点内的最后一个节点之后
  5112. * @method setStartAtLast
  5113. * @remind 选区的开始容器将变成给定的节点, 且偏移量为该节点的子节点数
  5114. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  5115. * @param { Node } node 目标节点
  5116. * @see UE.dom.Range:setStartAtFirst(Node)
  5117. * @return { UE.dom.Range } 当前range对象
  5118. */
  5119. setStartAtLast: function (node) {
  5120. return this.setStart(
  5121. node,
  5122. node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length
  5123. );
  5124. },
  5125. /**
  5126. * 设置Range的结束位置到node节点内的第一个节点之前
  5127. * @method setEndAtFirst
  5128. * @param { Node } node 目标节点
  5129. * @remind 选区的结束容器将变成给定的节点, 且偏移量为0
  5130. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  5131. * @see UE.dom.Range:setStartAtFirst(Node)
  5132. * @return { UE.dom.Range } 当前range对象
  5133. */
  5134. setEndAtFirst: function (node) {
  5135. return this.setEnd(node, 0);
  5136. },
  5137. /**
  5138. * 设置Range的结束位置到node节点内的最后一个节点之后
  5139. * @method setEndAtLast
  5140. * @param { Node } node 目标节点
  5141. * @remind 选区的结束容器将变成给定的节点, 且偏移量为该节点的子节点数量
  5142. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  5143. * @see UE.dom.Range:setStartAtFirst(Node)
  5144. * @return { UE.dom.Range } 当前range对象
  5145. */
  5146. setEndAtLast: function (node) {
  5147. return this.setEnd(
  5148. node,
  5149. node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length
  5150. );
  5151. },
  5152. /**
  5153. * 选中给定节点
  5154. * @method selectNode
  5155. * @remind 此时, 选区的开始容器和结束容器都是该节点的父节点, 其startOffset是该节点在父节点中的位置索引,
  5156. * 而endOffset为startOffset+1
  5157. * @param { Node } node 需要选中的节点
  5158. * @return { UE.dom.Range } 当前range对象,此时的range仅包含当前给定的节点对象
  5159. * @example
  5160. * ```html
  5161. * <!-- 选区示例 -->
  5162. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5163. *
  5164. * <script>
  5165. *
  5166. * //执行操作
  5167. * range.selectNode( document.getElementsByTagName("i")[0] );
  5168. *
  5169. * //结果选区
  5170. * //<b>xx[<i>xxx</i>]<span>xxx</span>xxx</b>
  5171. *
  5172. * </script>
  5173. * ```
  5174. */
  5175. selectNode: function (node) {
  5176. return this.setStartBefore(node).setEndAfter(node);
  5177. },
  5178. /**
  5179. * 选中给定节点内部的所有节点
  5180. * @method selectNodeContents
  5181. * @remind 此时, 选区的开始容器和结束容器都是该节点, 其startOffset为0,
  5182. * 而endOffset是该节点的子节点数。
  5183. * @param { Node } node 目标节点, 当前range将包含该节点内的所有节点
  5184. * @return { UE.dom.Range } 当前range对象, 此时range仅包含给定节点的所有子节点
  5185. * @example
  5186. * ```html
  5187. * <!-- 选区示例 -->
  5188. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5189. *
  5190. * <script>
  5191. *
  5192. * //执行操作
  5193. * range.selectNode( document.getElementsByTagName("b")[0] );
  5194. *
  5195. * //结果选区
  5196. * //<b>[xx<i>xxx</i><span>xxx</span>xxx]</b>
  5197. *
  5198. * </script>
  5199. * ```
  5200. */
  5201. selectNodeContents: function (node) {
  5202. return this.setStart(node, 0).setEndAtLast(node);
  5203. },
  5204. /**
  5205. * clone当前Range对象
  5206. * @method cloneRange
  5207. * @remind 返回的range是一个全新的range对象, 其内部所有属性与当前被clone的range相同。
  5208. * @return { UE.dom.Range } 当前range对象的一个副本
  5209. */
  5210. cloneRange: function () {
  5211. var me = this;
  5212. return new Range(me.document)
  5213. .setStart(me.startContainer, me.startOffset)
  5214. .setEnd(me.endContainer, me.endOffset);
  5215. },
  5216. /**
  5217. * 向当前选区的结束处闭合选区
  5218. * @method collapse
  5219. * @return { UE.dom.Range } 当前range对象
  5220. * @example
  5221. * ```html
  5222. * <!-- 选区示例 -->
  5223. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5224. *
  5225. * <script>
  5226. *
  5227. * //执行操作
  5228. * range.collapse();
  5229. *
  5230. * //结果选区
  5231. * //“|”表示选区已闭合
  5232. * //<b>xx<i>xxx</i><span>xx|x</span>xxx</b>
  5233. *
  5234. * </script>
  5235. * ```
  5236. */
  5237. /**
  5238. * 闭合当前选区,根据给定的toStart参数项决定是向当前选区开始处闭合还是向结束处闭合,
  5239. * 如果toStart的值为true,则向开始位置闭合, 反之,向结束位置闭合。
  5240. * @method collapse
  5241. * @param { Boolean } toStart 是否向选区开始处闭合
  5242. * @return { UE.dom.Range } 当前range对象,此时range对象处于闭合状态
  5243. * @see UE.dom.Range:collapse()
  5244. * @example
  5245. * ```html
  5246. * <!-- 选区示例 -->
  5247. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5248. *
  5249. * <script>
  5250. *
  5251. * //执行操作
  5252. * range.collapse( true );
  5253. *
  5254. * //结果选区
  5255. * //“|”表示选区已闭合
  5256. * //<b>xx<i>xxx</i><span>|xxx</span>xxx</b>
  5257. *
  5258. * </script>
  5259. * ```
  5260. */
  5261. collapse: function (toStart) {
  5262. var me = this;
  5263. if (toStart) {
  5264. me.endContainer = me.startContainer;
  5265. me.endOffset = me.startOffset;
  5266. } else {
  5267. me.startContainer = me.endContainer;
  5268. me.startOffset = me.endOffset;
  5269. }
  5270. me.collapsed = true;
  5271. return me;
  5272. },
  5273. /**
  5274. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置
  5275. * @method shrinkBoundary
  5276. * @return { UE.dom.Range } 当前range对象
  5277. * @example
  5278. * ```html
  5279. * <span>xx<b>xx[</b>xxxxx]</span> => <span>xx<b>xx</b>[xxxxx]</span>
  5280. * ```
  5281. *
  5282. * @example
  5283. * ```html
  5284. * <!-- 选区示例 -->
  5285. * <b>x[xx</b><i>]xxx</i>
  5286. *
  5287. * <script>
  5288. *
  5289. * //执行收缩
  5290. * range.shrinkBoundary();
  5291. *
  5292. * //结果选区
  5293. * //<b>x[xx]</b><i>xxx</i>
  5294. * </script>
  5295. * ```
  5296. *
  5297. * @example
  5298. * ```html
  5299. * [<b><i>xxxx</i>xxxxxxx</b>] => <b><i>[xxxx</i>xxxxxxx]</b>
  5300. * ```
  5301. */
  5302. /**
  5303. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置,
  5304. * 如果ignoreEnd的值为true,则忽略对结束位置的调整
  5305. * @method shrinkBoundary
  5306. * @param { Boolean } ignoreEnd 是否忽略对结束位置的调整
  5307. * @return { UE.dom.Range } 当前range对象
  5308. * @see UE.dom.domUtils.Range:shrinkBoundary()
  5309. */
  5310. shrinkBoundary: function (ignoreEnd) {
  5311. var me = this,
  5312. child,
  5313. collapsed = me.collapsed;
  5314. function check(node) {
  5315. return (
  5316. node.nodeType == 1 &&
  5317. !domUtils.isBookmarkNode(node) &&
  5318. !dtd.$empty[node.tagName] &&
  5319. !dtd.$nonChild[node.tagName]
  5320. );
  5321. }
  5322. while (
  5323. me.startContainer.nodeType == 1 && //是element
  5324. (child = me.startContainer.childNodes[me.startOffset]) && //子节点也是element
  5325. check(child)
  5326. ) {
  5327. me.setStart(child, 0);
  5328. }
  5329. if (collapsed) {
  5330. return me.collapse(true);
  5331. }
  5332. if (!ignoreEnd) {
  5333. while (
  5334. me.endContainer.nodeType == 1 && //是element
  5335. me.endOffset > 0 && //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
  5336. (child = me.endContainer.childNodes[me.endOffset - 1]) && //子节点也是element
  5337. check(child)
  5338. ) {
  5339. me.setEnd(child, child.childNodes.length);
  5340. }
  5341. }
  5342. return me;
  5343. },
  5344. /**
  5345. * 获取离当前选区内包含的所有节点最近的公共祖先节点,
  5346. * @method getCommonAncestor
  5347. * @remind 返回的公共祖先节点一定不是range自身的容器节点, 但有可能是一个文本节点
  5348. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5349. * @example
  5350. * ```html
  5351. * //选区示例
  5352. * <span>xxx<b>x[x<em>xx]x</em>xxx</b>xx</span>
  5353. * <script>
  5354. *
  5355. * var node = range.getCommonAncestor();
  5356. *
  5357. * //公共祖先节点是: b节点
  5358. * //输出: B
  5359. * console.log(node.tagName);
  5360. *
  5361. * </script>
  5362. * ```
  5363. */
  5364. /**
  5365. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  5366. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  5367. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点
  5368. * @method getCommonAncestor
  5369. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  5370. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5371. * @see UE.dom.Range:getCommonAncestor()
  5372. * @example
  5373. * ```html
  5374. * <body>
  5375. *
  5376. * <!-- 选区示例 -->
  5377. * <b>xxx<i>xxxx<span>xx[x</span>xx]x</i>xxxxxxx</b>
  5378. *
  5379. * <script>
  5380. *
  5381. * var node = range.getCommonAncestor( false );
  5382. *
  5383. * //这里的公共祖先节点是B而不是I, 是因为参数限制了获取到的节点不能是容器节点
  5384. * //output: B
  5385. * console.log( node.tagName );
  5386. *
  5387. * </script>
  5388. *
  5389. * </body>
  5390. * ```
  5391. */
  5392. /**
  5393. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  5394. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  5395. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点; 同时可以根据
  5396. * ignoreTextNode 参数的取值决定是否忽略类型为文本节点的祖先节点。
  5397. * @method getCommonAncestor
  5398. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  5399. * @param { Boolean } ignoreTextNode 获取祖先节点的过程中是否忽略类型为文本节点的祖先节点
  5400. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5401. * @see UE.dom.Range:getCommonAncestor()
  5402. * @see UE.dom.Range:getCommonAncestor(Boolean)
  5403. * @example
  5404. * ```html
  5405. * <body>
  5406. *
  5407. * <!-- 选区示例 -->
  5408. * <b>xxx<i>xxxx<span>x[x]x</span>xxx</i>xxxxxxx</b>
  5409. *
  5410. * <script>
  5411. *
  5412. * var node = range.getCommonAncestor( true, false );
  5413. *
  5414. * //output: SPAN
  5415. * console.log( node.tagName );
  5416. *
  5417. * </script>
  5418. *
  5419. * </body>
  5420. * ```
  5421. */
  5422. getCommonAncestor: function (includeSelf, ignoreTextNode) {
  5423. var me = this,
  5424. start = me.startContainer,
  5425. end = me.endContainer;
  5426. if (start === end) {
  5427. if (includeSelf && selectOneNode(this)) {
  5428. start = start.childNodes[me.startOffset];
  5429. if (start.nodeType == 1) return start;
  5430. }
  5431. //只有在上来就相等的情况下才会出现是文本的情况
  5432. return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start;
  5433. }
  5434. return domUtils.getCommonAncestor(start, end);
  5435. },
  5436. /**
  5437. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上
  5438. * @method trimBoundary
  5439. * @remind 该操作有可能会引起文本节点被切开
  5440. * @return { UE.dom.Range } 当前range对象
  5441. * @example
  5442. * ```html
  5443. *
  5444. * //选区示例
  5445. * <b>xxx<i>[xxxxx]</i>xxx</b>
  5446. *
  5447. * <script>
  5448. * //未调整前, 选区的开始容器和结束都是文本节点
  5449. * //执行调整
  5450. * range.trimBoundary();
  5451. *
  5452. * //调整之后, 容器节点变成了i节点
  5453. * //<b>xxx[<i>xxxxx</i>]xxx</b>
  5454. * </script>
  5455. * ```
  5456. */
  5457. /**
  5458. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上,
  5459. * 可以根据 ignoreEnd 参数的值决定是否调整对结束边界的调整
  5460. * @method trimBoundary
  5461. * @param { Boolean } ignoreEnd 是否忽略对结束边界的调整
  5462. * @return { UE.dom.Range } 当前range对象
  5463. * @example
  5464. * ```html
  5465. *
  5466. * //选区示例
  5467. * <b>xxx<i>[xxxxx]</i>xxx</b>
  5468. *
  5469. * <script>
  5470. * //未调整前, 选区的开始容器和结束都是文本节点
  5471. * //执行调整
  5472. * range.trimBoundary( true );
  5473. *
  5474. * //调整之后, 开始容器节点变成了i节点
  5475. * //但是, 结束容器没有发生变化
  5476. * //<b>xxx[<i>xxxxx]</i>xxx</b>
  5477. * </script>
  5478. * ```
  5479. */
  5480. trimBoundary: function (ignoreEnd) {
  5481. this.txtToElmBoundary();
  5482. var start = this.startContainer,
  5483. offset = this.startOffset,
  5484. collapsed = this.collapsed,
  5485. end = this.endContainer;
  5486. if (start.nodeType == 3) {
  5487. if (offset == 0) {
  5488. this.setStartBefore(start);
  5489. } else {
  5490. if (offset >= start.nodeValue.length) {
  5491. this.setStartAfter(start);
  5492. } else {
  5493. var textNode = domUtils.split(start, offset);
  5494. //跟新结束边界
  5495. if (start === end) {
  5496. this.setEnd(textNode, this.endOffset - offset);
  5497. } else if (start.parentNode === end) {
  5498. this.endOffset += 1;
  5499. }
  5500. this.setStartBefore(textNode);
  5501. }
  5502. }
  5503. if (collapsed) {
  5504. return this.collapse(true);
  5505. }
  5506. }
  5507. if (!ignoreEnd) {
  5508. offset = this.endOffset;
  5509. end = this.endContainer;
  5510. if (end.nodeType == 3) {
  5511. if (offset == 0) {
  5512. this.setEndBefore(end);
  5513. } else {
  5514. offset < end.nodeValue.length && domUtils.split(end, offset);
  5515. this.setEndAfter(end);
  5516. }
  5517. }
  5518. }
  5519. return this;
  5520. },
  5521. /**
  5522. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则什么也不做
  5523. * @method txtToElmBoundary
  5524. * @remind 该操作不会修改dom节点
  5525. * @return { UE.dom.Range } 当前range对象
  5526. */
  5527. /**
  5528. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则根据参数项
  5529. * ignoreCollapsed 的值决定是否执行该调整
  5530. * @method txtToElmBoundary
  5531. * @param { Boolean } ignoreCollapsed 是否忽略选区的闭合状态, 如果该参数取值为true, 则
  5532. * 不论选区是否闭合, 都会执行该操作, 反之, 则不会对闭合的选区执行该操作
  5533. * @return { UE.dom.Range } 当前range对象
  5534. */
  5535. txtToElmBoundary: function (ignoreCollapsed) {
  5536. function adjust(r, c) {
  5537. var container = r[c + "Container"],
  5538. offset = r[c + "Offset"];
  5539. if (container.nodeType == 3) {
  5540. if (!offset) {
  5541. r[
  5542. "set" +
  5543. c.replace(/(\w)/, function (a) {
  5544. return a.toUpperCase();
  5545. }) +
  5546. "Before"
  5547. ](container);
  5548. } else if (offset >= container.nodeValue.length) {
  5549. r[
  5550. "set" +
  5551. c.replace(/(\w)/, function (a) {
  5552. return a.toUpperCase();
  5553. }) +
  5554. "After"
  5555. ](container);
  5556. }
  5557. }
  5558. }
  5559. if (ignoreCollapsed || !this.collapsed) {
  5560. adjust(this, "start");
  5561. adjust(this, "end");
  5562. }
  5563. return this;
  5564. },
  5565. /**
  5566. * 在当前选区的开始位置前插入节点,新插入的节点会被该range包含
  5567. * @method insertNode
  5568. * @param { Node } node 需要插入的节点
  5569. * @remind 插入的节点可以是一个DocumentFragment依次插入多个节点
  5570. * @return { UE.dom.Range } 当前range对象
  5571. */
  5572. insertNode: function (node) {
  5573. var first = node,
  5574. length = 1;
  5575. if (node.nodeType == 11) {
  5576. first = node.firstChild;
  5577. length = node.childNodes.length;
  5578. }
  5579. this.trimBoundary(true);
  5580. var start = this.startContainer,
  5581. offset = this.startOffset;
  5582. var nextNode = start.childNodes[offset];
  5583. if (nextNode) {
  5584. start.insertBefore(node, nextNode);
  5585. } else {
  5586. start.appendChild(node);
  5587. }
  5588. if (first.parentNode === this.endContainer) {
  5589. this.endOffset = this.endOffset + length;
  5590. }
  5591. return this.setStartBefore(first);
  5592. },
  5593. /**
  5594. * 闭合选区到当前选区的开始位置, 并且定位光标到闭合后的位置
  5595. * @method setCursor
  5596. * @return { UE.dom.Range } 当前range对象
  5597. * @see UE.dom.Range:collapse()
  5598. */
  5599. /**
  5600. * 闭合选区,可以根据参数toEnd的值控制选区是向前闭合还是向后闭合, 并且定位光标到闭合后的位置。
  5601. * @method setCursor
  5602. * @param { Boolean } toEnd 是否向后闭合, 如果为true, 则闭合选区时, 将向结束容器方向闭合,
  5603. * 反之,则向开始容器方向闭合
  5604. * @return { UE.dom.Range } 当前range对象
  5605. * @see UE.dom.Range:collapse(Boolean)
  5606. */
  5607. setCursor: function (toEnd, noFillData) {
  5608. return this.collapse(!toEnd).select(noFillData);
  5609. },
  5610. /**
  5611. * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
  5612. * @method createBookmark
  5613. * @param { Boolean } serialize 控制返回的标记位置是对当前位置的引用还是ID,如果该值为true,则
  5614. * 返回标记位置的ID, 反之则返回标记位置节点的引用
  5615. * @return { Object } 返回一个书签记录键值对, 其包含的key有: start => 开始标记的ID或者引用,
  5616. * end => 结束标记的ID或引用, id => 当前标记的类型, 如果为true,则表示
  5617. * 返回的记录的类型为ID, 反之则为引用
  5618. */
  5619. createBookmark: function (serialize, same) {
  5620. var endNode,
  5621. startNode = this.document.createElement("span");
  5622. startNode.style.cssText = "display:none;line-height:0px;";
  5623. startNode.appendChild(this.document.createTextNode("\u200D"));
  5624. startNode.id = "_baidu_bookmark_start_" + (same ? "" : guid++);
  5625. if (!this.collapsed) {
  5626. endNode = startNode.cloneNode(true);
  5627. endNode.id = "_baidu_bookmark_end_" + (same ? "" : guid++);
  5628. }
  5629. this.insertNode(startNode);
  5630. if (endNode) {
  5631. this.collapse().insertNode(endNode).setEndBefore(endNode);
  5632. }
  5633. this.setStartAfter(startNode);
  5634. return {
  5635. start: serialize ? startNode.id : startNode,
  5636. end: endNode ? (serialize ? endNode.id : endNode) : null,
  5637. id: serialize
  5638. };
  5639. },
  5640. /**
  5641. * 调整当前range的边界到书签位置,并删除该书签对象所标记的位置内的节点
  5642. * @method moveToBookmark
  5643. * @param { BookMark } bookmark createBookmark所创建的标签对象
  5644. * @return { UE.dom.Range } 当前range对象
  5645. * @see UE.dom.Range:createBookmark(Boolean)
  5646. */
  5647. moveToBookmark: function (bookmark) {
  5648. var start = bookmark.id
  5649. ? this.document.getElementById(bookmark.start)
  5650. : bookmark.start,
  5651. end = bookmark.end && bookmark.id
  5652. ? this.document.getElementById(bookmark.end)
  5653. : bookmark.end;
  5654. this.setStartBefore(start);
  5655. domUtils.remove(start);
  5656. if (end) {
  5657. this.setEndBefore(end);
  5658. domUtils.remove(end);
  5659. } else {
  5660. this.collapse(true);
  5661. }
  5662. return this;
  5663. },
  5664. /**
  5665. * 调整range的边界,使其"放大"到最近的父节点
  5666. * @method enlarge
  5667. * @remind 会引起选区的变化
  5668. * @return { UE.dom.Range } 当前range对象
  5669. */
  5670. /**
  5671. * 调整range的边界,使其"放大"到最近的父节点,根据参数 toBlock 的取值, 可以
  5672. * 要求扩大之后的父节点是block节点
  5673. * @method enlarge
  5674. * @param { Boolean } toBlock 是否要求扩大之后的父节点必须是block节点
  5675. * @return { UE.dom.Range } 当前range对象
  5676. */
  5677. enlarge: function (toBlock, stopFn) {
  5678. var isBody = domUtils.isBody,
  5679. pre,
  5680. node,
  5681. tmp = this.document.createTextNode("");
  5682. if (toBlock) {
  5683. node = this.startContainer;
  5684. if (node.nodeType == 1) {
  5685. if (node.childNodes[this.startOffset]) {
  5686. pre = node = node.childNodes[this.startOffset];
  5687. } else {
  5688. node.appendChild(tmp);
  5689. pre = node = tmp;
  5690. }
  5691. } else {
  5692. pre = node;
  5693. }
  5694. while (1) {
  5695. if (domUtils.isBlockElm(node)) {
  5696. node = pre;
  5697. while ((pre = node.previousSibling) && !domUtils.isBlockElm(pre)) {
  5698. node = pre;
  5699. }
  5700. this.setStartBefore(node);
  5701. break;
  5702. }
  5703. pre = node;
  5704. node = node.parentNode;
  5705. }
  5706. node = this.endContainer;
  5707. if (node.nodeType == 1) {
  5708. if ((pre = node.childNodes[this.endOffset])) {
  5709. node.insertBefore(tmp, pre);
  5710. } else {
  5711. node.appendChild(tmp);
  5712. }
  5713. pre = node = tmp;
  5714. } else {
  5715. pre = node;
  5716. }
  5717. while (1) {
  5718. if (domUtils.isBlockElm(node)) {
  5719. node = pre;
  5720. while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) {
  5721. node = pre;
  5722. }
  5723. this.setEndAfter(node);
  5724. break;
  5725. }
  5726. pre = node;
  5727. node = node.parentNode;
  5728. }
  5729. if (tmp.parentNode === this.endContainer) {
  5730. this.endOffset--;
  5731. }
  5732. domUtils.remove(tmp);
  5733. }
  5734. // 扩展边界到最大
  5735. if (!this.collapsed) {
  5736. while (this.startOffset == 0) {
  5737. if (stopFn && stopFn(this.startContainer)) {
  5738. break;
  5739. }
  5740. if (isBody(this.startContainer)) {
  5741. break;
  5742. }
  5743. this.setStartBefore(this.startContainer);
  5744. }
  5745. while (
  5746. this.endOffset ==
  5747. (this.endContainer.nodeType == 1
  5748. ? this.endContainer.childNodes.length
  5749. : this.endContainer.nodeValue.length)
  5750. ) {
  5751. if (stopFn && stopFn(this.endContainer)) {
  5752. break;
  5753. }
  5754. if (isBody(this.endContainer)) {
  5755. break;
  5756. }
  5757. this.setEndAfter(this.endContainer);
  5758. }
  5759. }
  5760. return this;
  5761. },
  5762. enlargeToBlockElm: function (ignoreEnd) {
  5763. while (!domUtils.isBlockElm(this.startContainer)) {
  5764. this.setStartBefore(this.startContainer);
  5765. }
  5766. if (!ignoreEnd) {
  5767. while (!domUtils.isBlockElm(this.endContainer)) {
  5768. this.setEndAfter(this.endContainer);
  5769. }
  5770. }
  5771. return this;
  5772. },
  5773. /**
  5774. * 调整Range的边界,使其"缩小"到最合适的位置
  5775. * @method adjustmentBoundary
  5776. * @return { UE.dom.Range } 当前range对象
  5777. * @see UE.dom.Range:shrinkBoundary()
  5778. */
  5779. adjustmentBoundary: function () {
  5780. if (!this.collapsed) {
  5781. while (
  5782. !domUtils.isBody(this.startContainer) &&
  5783. this.startOffset ==
  5784. this.startContainer[
  5785. this.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  5786. ].length &&
  5787. this.startContainer[
  5788. this.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  5789. ].length
  5790. ) {
  5791. this.setStartAfter(this.startContainer);
  5792. }
  5793. while (
  5794. !domUtils.isBody(this.endContainer) &&
  5795. !this.endOffset &&
  5796. this.endContainer[
  5797. this.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  5798. ].length
  5799. ) {
  5800. this.setEndBefore(this.endContainer);
  5801. }
  5802. }
  5803. return this;
  5804. },
  5805. /**
  5806. * 给range选区中的内容添加给定的inline标签
  5807. * @method applyInlineStyle
  5808. * @param { String } tagName 需要添加的标签名
  5809. * @example
  5810. * ```html
  5811. * <p>xxxx[xxxx]x</p> ==> range.applyInlineStyle("strong") ==> <p>xxxx[<strong>xxxx</strong>]x</p>
  5812. * ```
  5813. */
  5814. /**
  5815. * 给range选区中的内容添加给定的inline标签, 并且为标签附加上一些初始化属性。
  5816. * @method applyInlineStyle
  5817. * @param { String } tagName 需要添加的标签名
  5818. * @param { Object } attrs 跟随新添加的标签的属性
  5819. * @return { UE.dom.Range } 当前选区
  5820. * @example
  5821. * ```html
  5822. * <p>xxxx[xxxx]x</p>
  5823. *
  5824. * ==>
  5825. *
  5826. * <!-- 执行操作 -->
  5827. * range.applyInlineStyle("strong",{"style":"font-size:12px"})
  5828. *
  5829. * ==>
  5830. *
  5831. * <p>xxxx[<strong style="font-size:12px">xxxx</strong>]x</p>
  5832. * ```
  5833. */
  5834. applyInlineStyle: function (tagName, attrs, list) {
  5835. if (this.collapsed) return this;
  5836. this.trimBoundary()
  5837. .enlarge(false, function (node) {
  5838. return node.nodeType == 1 && domUtils.isBlockElm(node);
  5839. })
  5840. .adjustmentBoundary();
  5841. var bookmark = this.createBookmark(),
  5842. end = bookmark.end,
  5843. filterFn = function (node) {
  5844. return node.nodeType == 1
  5845. ? node.tagName.toLowerCase() != "br"
  5846. : !domUtils.isWhitespace(node);
  5847. },
  5848. current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
  5849. node,
  5850. pre,
  5851. range = this.cloneRange();
  5852. while (
  5853. current &&
  5854. domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
  5855. ) {
  5856. if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
  5857. range.setStartBefore(current);
  5858. node = current;
  5859. while (
  5860. node &&
  5861. (node.nodeType == 3 || dtd[tagName][node.tagName]) &&
  5862. node !== end
  5863. ) {
  5864. pre = node;
  5865. node = domUtils.getNextDomNode(
  5866. node,
  5867. node.nodeType == 1,
  5868. null,
  5869. function (parent) {
  5870. return dtd[tagName][parent.tagName];
  5871. }
  5872. );
  5873. }
  5874. var frag = range.setEndAfter(pre).extractContents(),
  5875. elm;
  5876. if (list && list.length > 0) {
  5877. var level, top;
  5878. top = level = list[0].cloneNode(false);
  5879. for (var i = 1, ci; (ci = list[i++]);) {
  5880. level.appendChild(ci.cloneNode(false));
  5881. level = level.firstChild;
  5882. }
  5883. elm = level;
  5884. } else {
  5885. elm = range.document.createElement(tagName);
  5886. }
  5887. if (attrs) {
  5888. domUtils.setAttributes(elm, attrs);
  5889. }
  5890. elm.appendChild(frag);
  5891. //针对嵌套span的全局样式指定,做容错处理
  5892. if (elm.tagName == "SPAN" && attrs && attrs.style) {
  5893. utils.each(elm.getElementsByTagName("span"), function (s) {
  5894. s.style.cssText = s.style.cssText + ";" + attrs.style;
  5895. });
  5896. }
  5897. range.insertNode(list ? top : elm);
  5898. //处理下滑线在a上的情况
  5899. var aNode;
  5900. if (
  5901. tagName == "span" &&
  5902. attrs.style &&
  5903. /text\-decoration/.test(attrs.style) &&
  5904. (aNode = domUtils.findParentByTagName(elm, "a", true))
  5905. ) {
  5906. domUtils.setAttributes(aNode, attrs);
  5907. domUtils.remove(elm, true);
  5908. elm = aNode;
  5909. } else {
  5910. domUtils.mergeSibling(elm);
  5911. domUtils.clearEmptySibling(elm);
  5912. }
  5913. //去除子节点相同的
  5914. domUtils.mergeChild(elm, attrs);
  5915. current = domUtils.getNextDomNode(elm, false, filterFn);
  5916. domUtils.mergeToParent(elm);
  5917. if (node === end) {
  5918. break;
  5919. }
  5920. } else {
  5921. current = domUtils.getNextDomNode(current, true, filterFn);
  5922. }
  5923. }
  5924. return this.moveToBookmark(bookmark);
  5925. },
  5926. /**
  5927. * 移除当前选区内指定的inline标签,但保留其中的内容
  5928. * @method removeInlineStyle
  5929. * @param { String } tagName 需要移除的标签名
  5930. * @return { UE.dom.Range } 当前的range对象
  5931. * @example
  5932. * ```html
  5933. * xx[x<span>xxx<em>yyy</em>zz]z</span> => range.removeInlineStyle(["em"]) => xx[x<span>xxxyyyzz]z</span>
  5934. * ```
  5935. */
  5936. /**
  5937. * 移除当前选区内指定的一组inline标签,但保留其中的内容
  5938. * @method removeInlineStyle
  5939. * @param { Array } tagNameArr 需要移除的标签名的数组
  5940. * @return { UE.dom.Range } 当前的range对象
  5941. * @see UE.dom.Range:removeInlineStyle(String)
  5942. */
  5943. removeInlineStyle: function (tagNames) {
  5944. if (this.collapsed) return this;
  5945. tagNames = utils.isArray(tagNames) ? tagNames : [tagNames];
  5946. this.shrinkBoundary().adjustmentBoundary();
  5947. var start = this.startContainer,
  5948. end = this.endContainer;
  5949. while (1) {
  5950. if (start.nodeType == 1) {
  5951. if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) {
  5952. break;
  5953. }
  5954. if (start.tagName.toLowerCase() == "body") {
  5955. start = null;
  5956. break;
  5957. }
  5958. }
  5959. start = start.parentNode;
  5960. }
  5961. while (1) {
  5962. if (end.nodeType == 1) {
  5963. if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) {
  5964. break;
  5965. }
  5966. if (end.tagName.toLowerCase() == "body") {
  5967. end = null;
  5968. break;
  5969. }
  5970. }
  5971. end = end.parentNode;
  5972. }
  5973. var bookmark = this.createBookmark(),
  5974. frag,
  5975. tmpRange;
  5976. if (start) {
  5977. tmpRange = this.cloneRange()
  5978. .setEndBefore(bookmark.start)
  5979. .setStartBefore(start);
  5980. frag = tmpRange.extractContents();
  5981. tmpRange.insertNode(frag);
  5982. domUtils.clearEmptySibling(start, true);
  5983. start.parentNode.insertBefore(bookmark.start, start);
  5984. }
  5985. if (end) {
  5986. tmpRange = this.cloneRange()
  5987. .setStartAfter(bookmark.end)
  5988. .setEndAfter(end);
  5989. frag = tmpRange.extractContents();
  5990. tmpRange.insertNode(frag);
  5991. domUtils.clearEmptySibling(end, false, true);
  5992. end.parentNode.insertBefore(bookmark.end, end.nextSibling);
  5993. }
  5994. var current = domUtils.getNextDomNode(bookmark.start, false, function (
  5995. node
  5996. ) {
  5997. return node.nodeType == 1;
  5998. }),
  5999. next;
  6000. while (current && current !== bookmark.end) {
  6001. next = domUtils.getNextDomNode(current, true, function (node) {
  6002. return node.nodeType == 1;
  6003. });
  6004. if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) {
  6005. domUtils.remove(current, true);
  6006. }
  6007. current = next;
  6008. }
  6009. return this.moveToBookmark(bookmark);
  6010. },
  6011. /**
  6012. * 获取当前选中的自闭合的节点
  6013. * @method getClosedNode
  6014. * @return { Node | NULL } 如果当前选中的是自闭合节点, 则返回该节点, 否则返回NULL
  6015. */
  6016. getClosedNode: function () {
  6017. var node;
  6018. if (!this.collapsed) {
  6019. var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
  6020. if (selectOneNode(range)) {
  6021. var child = range.startContainer.childNodes[range.startOffset];
  6022. if (
  6023. child &&
  6024. child.nodeType == 1 &&
  6025. (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])
  6026. ) {
  6027. node = child;
  6028. }
  6029. }
  6030. }
  6031. return node;
  6032. },
  6033. /**
  6034. * 在页面上高亮range所表示的选区
  6035. * @method select
  6036. * @return { UE.dom.Range } 返回当前Range对象
  6037. */
  6038. //这里不区分ie9以上,trace:3824
  6039. select: browser.ie
  6040. ? function (noFillData, textRange) {
  6041. var nativeRange;
  6042. if (!this.collapsed) this.shrinkBoundary();
  6043. var node = this.getClosedNode();
  6044. if (node && !textRange) {
  6045. try {
  6046. nativeRange = this.document.body.createControlRange();
  6047. nativeRange.addElement(node);
  6048. nativeRange.select();
  6049. } catch (e) {
  6050. }
  6051. return this;
  6052. }
  6053. var bookmark = this.createBookmark(),
  6054. start = bookmark.start,
  6055. end;
  6056. nativeRange = this.document.body.createTextRange();
  6057. nativeRange.moveToElementText(start);
  6058. nativeRange.moveStart("character", 1);
  6059. if (!this.collapsed) {
  6060. var nativeRangeEnd = this.document.body.createTextRange();
  6061. end = bookmark.end;
  6062. nativeRangeEnd.moveToElementText(end);
  6063. nativeRange.setEndPoint("EndToEnd", nativeRangeEnd);
  6064. } else {
  6065. if (!noFillData && this.startContainer.nodeType != 3) {
  6066. //使用<span>|x<span>固定住光标
  6067. var tmpText = this.document.createTextNode(fillChar),
  6068. tmp = this.document.createElement("span");
  6069. tmp.appendChild(this.document.createTextNode(fillChar));
  6070. start.parentNode.insertBefore(tmp, start);
  6071. start.parentNode.insertBefore(tmpText, start);
  6072. //当点b,i,u时,不能清除i上边的b
  6073. removeFillData(this.document, tmpText);
  6074. fillData = tmpText;
  6075. mergeSibling(tmp, "previousSibling");
  6076. mergeSibling(start, "nextSibling");
  6077. nativeRange.moveStart("character", -1);
  6078. nativeRange.collapse(true);
  6079. }
  6080. }
  6081. this.moveToBookmark(bookmark);
  6082. tmp && domUtils.remove(tmp);
  6083. //IE在隐藏状态下不支持range操作,catch一下
  6084. try {
  6085. nativeRange.select();
  6086. } catch (e) {
  6087. }
  6088. return this;
  6089. }
  6090. : function (notInsertFillData) {
  6091. function checkOffset(rng) {
  6092. function check(node, offset, dir) {
  6093. if (node.nodeType == 3 && node.nodeValue.length < offset) {
  6094. rng[dir + "Offset"] = node.nodeValue.length;
  6095. }
  6096. }
  6097. check(rng.startContainer, rng.startOffset, "start");
  6098. check(rng.endContainer, rng.endOffset, "end");
  6099. }
  6100. var win = domUtils.getWindow(this.document),
  6101. sel = win.getSelection(),
  6102. txtNode;
  6103. //FF下关闭自动长高时滚动条在关闭dialog时会跳
  6104. //ff下如果不body.focus将不能定位闭合光标到编辑器内
  6105. browser.gecko ? this.document.body.focus() : win.focus();
  6106. if (sel) {
  6107. sel.removeAllRanges();
  6108. // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
  6109. // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
  6110. if (this.collapsed && !notInsertFillData) {
  6111. // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
  6112. // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
  6113. // var tmp = this.document.createTextNode('');
  6114. // this.insertNode(tmp).setStart(tmp, 0).collapse(true);
  6115. // }
  6116. //
  6117. //处理光标落在文本节点的情况
  6118. //处理以下的情况
  6119. //<b>|xxxx</b>
  6120. //<b>xxxx</b>|xxxx
  6121. //xxxx<b>|</b>
  6122. var start = this.startContainer,
  6123. child = start;
  6124. if (start.nodeType == 1) {
  6125. child = start.childNodes[this.startOffset];
  6126. }
  6127. if (
  6128. !(start.nodeType == 3 && this.startOffset) &&
  6129. (child
  6130. ? !child.previousSibling ||
  6131. child.previousSibling.nodeType != 3
  6132. : !start.lastChild || start.lastChild.nodeType != 3)
  6133. ) {
  6134. txtNode = this.document.createTextNode(fillChar);
  6135. //跟着前边走
  6136. this.insertNode(txtNode);
  6137. removeFillData(this.document, txtNode);
  6138. mergeSibling(txtNode, "previousSibling");
  6139. mergeSibling(txtNode, "nextSibling");
  6140. fillData = txtNode;
  6141. this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true);
  6142. }
  6143. }
  6144. var nativeRange = this.document.createRange();
  6145. if (
  6146. this.collapsed &&
  6147. browser.opera &&
  6148. this.startContainer.nodeType == 1
  6149. ) {
  6150. var child = this.startContainer.childNodes[this.startOffset];
  6151. if (!child) {
  6152. //往前靠拢
  6153. child = this.startContainer.lastChild;
  6154. if (child && domUtils.isBr(child)) {
  6155. this.setStartBefore(child).collapse(true);
  6156. }
  6157. } else {
  6158. //向后靠拢
  6159. while (child && domUtils.isBlockElm(child)) {
  6160. if (child.nodeType == 1 && child.childNodes[0]) {
  6161. child = child.childNodes[0];
  6162. } else {
  6163. break;
  6164. }
  6165. }
  6166. child && this.setStartBefore(child).collapse(true);
  6167. }
  6168. }
  6169. //是createAddress最后一位算的不准,现在这里进行微调
  6170. checkOffset(this);
  6171. nativeRange.setStart(this.startContainer, this.startOffset);
  6172. nativeRange.setEnd(this.endContainer, this.endOffset);
  6173. sel.addRange(nativeRange);
  6174. }
  6175. return this;
  6176. },
  6177. /**
  6178. * 滚动到当前range开始的位置
  6179. * @method scrollToView
  6180. * @param { Window } win 当前range对象所属的window对象
  6181. * @return { UE.dom.Range } 当前Range对象
  6182. */
  6183. /**
  6184. * 滚动到距离当前range开始位置 offset 的位置处
  6185. * @method scrollToView
  6186. * @param { Window } win 当前range对象所属的window对象
  6187. * @param { Number } offset 距离range开始位置处的偏移量, 如果为正数, 则向下偏移, 反之, 则向上偏移
  6188. * @return { UE.dom.Range } 当前Range对象
  6189. */
  6190. scrollToView: function (win, offset) {
  6191. win = win ? window : domUtils.getWindow(this.document);
  6192. var me = this,
  6193. span = me.document.createElement("span");
  6194. //trace:717
  6195. span.innerHTML = "&nbsp;";
  6196. me.cloneRange().insertNode(span);
  6197. domUtils.scrollToView(span, win, offset);
  6198. domUtils.remove(span);
  6199. return me;
  6200. },
  6201. /**
  6202. * 判断当前选区内容是否占位符
  6203. * @private
  6204. * @method inFillChar
  6205. * @return { Boolean } 如果是占位符返回true,否则返回false
  6206. */
  6207. inFillChar: function () {
  6208. var start = this.startContainer;
  6209. if (
  6210. this.collapsed &&
  6211. start.nodeType == 3 &&
  6212. start.nodeValue.replace(new RegExp("^" + domUtils.fillChar), "")
  6213. .length +
  6214. 1 ==
  6215. start.nodeValue.length
  6216. ) {
  6217. return true;
  6218. }
  6219. return false;
  6220. },
  6221. /**
  6222. * 保存
  6223. * @method createAddress
  6224. * @private
  6225. * @return { Boolean } 返回开始和结束的位置
  6226. * @example
  6227. * ```html
  6228. * <body>
  6229. * <p>
  6230. * aaaa
  6231. * <em>
  6232. * <!-- 选区开始 -->
  6233. * bbbb
  6234. * <!-- 选区结束 -->
  6235. * </em>
  6236. * </p>
  6237. *
  6238. * <script>
  6239. * //output: {startAddress:[0,1,0,0],endAddress:[0,1,0,4]}
  6240. * console.log( range.createAddress() );
  6241. * </script>
  6242. * </body>
  6243. * ```
  6244. */
  6245. createAddress: function (ignoreEnd, ignoreTxt) {
  6246. var addr = {},
  6247. me = this;
  6248. function getAddress(isStart) {
  6249. var node = isStart ? me.startContainer : me.endContainer;
  6250. var parents = domUtils.findParents(node, true, function (node) {
  6251. return !domUtils.isBody(node);
  6252. }),
  6253. addrs = [];
  6254. for (var i = 0, ci; (ci = parents[i++]);) {
  6255. addrs.push(domUtils.getNodeIndex(ci, ignoreTxt));
  6256. }
  6257. var firstIndex = 0;
  6258. if (ignoreTxt) {
  6259. if (node.nodeType == 3) {
  6260. var tmpNode = node.previousSibling;
  6261. while (tmpNode && tmpNode.nodeType == 3) {
  6262. firstIndex += tmpNode.nodeValue.replace(fillCharReg, "").length;
  6263. tmpNode = tmpNode.previousSibling;
  6264. }
  6265. firstIndex += isStart ? me.startOffset : me.endOffset; // - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
  6266. } else {
  6267. node = node.childNodes[isStart ? me.startOffset : me.endOffset];
  6268. if (node) {
  6269. firstIndex = domUtils.getNodeIndex(node, ignoreTxt);
  6270. } else {
  6271. node = isStart ? me.startContainer : me.endContainer;
  6272. var first = node.firstChild;
  6273. while (first) {
  6274. if (domUtils.isFillChar(first)) {
  6275. first = first.nextSibling;
  6276. continue;
  6277. }
  6278. firstIndex++;
  6279. if (first.nodeType == 3) {
  6280. while (first && first.nodeType == 3) {
  6281. first = first.nextSibling;
  6282. }
  6283. } else {
  6284. first = first.nextSibling;
  6285. }
  6286. }
  6287. }
  6288. }
  6289. } else {
  6290. firstIndex = isStart
  6291. ? domUtils.isFillChar(node) ? 0 : me.startOffset
  6292. : me.endOffset;
  6293. }
  6294. if (firstIndex < 0) {
  6295. firstIndex = 0;
  6296. }
  6297. addrs.push(firstIndex);
  6298. return addrs;
  6299. }
  6300. addr.startAddress = getAddress(true);
  6301. if (!ignoreEnd) {
  6302. addr.endAddress = me.collapsed
  6303. ? [].concat(addr.startAddress)
  6304. : getAddress();
  6305. }
  6306. return addr;
  6307. },
  6308. /**
  6309. * 保存
  6310. * @method createAddress
  6311. * @private
  6312. * @return { Boolean } 返回开始和结束的位置
  6313. * @example
  6314. * ```html
  6315. * <body>
  6316. * <p>
  6317. * aaaa
  6318. * <em>
  6319. * <!-- 选区开始 -->
  6320. * bbbb
  6321. * <!-- 选区结束 -->
  6322. * </em>
  6323. * </p>
  6324. *
  6325. * <script>
  6326. * var range = editor.selection.getRange();
  6327. * range.moveToAddress({startAddress:[0,1,0,0],endAddress:[0,1,0,4]});
  6328. * range.select();
  6329. * //output: 'bbbb'
  6330. * console.log(editor.selection.getText());
  6331. * </script>
  6332. * </body>
  6333. * ```
  6334. */
  6335. moveToAddress: function (addr, ignoreEnd) {
  6336. var me = this;
  6337. function getNode(address, isStart) {
  6338. var tmpNode = me.document.body,
  6339. parentNode,
  6340. offset;
  6341. for (var i = 0, ci, l = address.length; i < l; i++) {
  6342. ci = address[i];
  6343. parentNode = tmpNode;
  6344. tmpNode = tmpNode.childNodes[ci];
  6345. if (!tmpNode) {
  6346. offset = ci;
  6347. break;
  6348. }
  6349. }
  6350. if (isStart) {
  6351. if (tmpNode) {
  6352. me.setStartBefore(tmpNode);
  6353. } else {
  6354. me.setStart(parentNode, offset);
  6355. }
  6356. } else {
  6357. if (tmpNode) {
  6358. me.setEndBefore(tmpNode);
  6359. } else {
  6360. me.setEnd(parentNode, offset);
  6361. }
  6362. }
  6363. }
  6364. getNode(addr.startAddress, true);
  6365. !ignoreEnd && addr.endAddress && getNode(addr.endAddress);
  6366. return me;
  6367. },
  6368. /**
  6369. * 判断给定的Range对象是否和当前Range对象表示的是同一个选区
  6370. * @method equals
  6371. * @param { UE.dom.Range } 需要判断的Range对象
  6372. * @return { Boolean } 如果给定的Range对象与当前Range对象表示的是同一个选区, 则返回true, 否则返回false
  6373. */
  6374. equals: function (rng) {
  6375. for (var p in this) {
  6376. if (this.hasOwnProperty(p)) {
  6377. if (this[p] !== rng[p]) return false;
  6378. }
  6379. }
  6380. return true;
  6381. },
  6382. /**
  6383. * 遍历range内的节点。每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  6384. * 作为其参数。
  6385. * @method traversal
  6386. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  6387. * @return { UE.dom.Range } 当前range对象
  6388. * @example
  6389. * ```html
  6390. *
  6391. * <body>
  6392. *
  6393. * <!-- 选区开始 -->
  6394. * <span></span>
  6395. * <a></a>
  6396. * <!-- 选区结束 -->
  6397. * </body>
  6398. *
  6399. * <script>
  6400. *
  6401. * //output: <span></span><a></a>
  6402. * console.log( range.cloneContents() );
  6403. *
  6404. * range.traversal( function ( node ) {
  6405. *
  6406. * if ( node.nodeType === 1 ) {
  6407. * node.className = "test";
  6408. * }
  6409. *
  6410. * } );
  6411. *
  6412. * //output: <span class="test"></span><a class="test"></a>
  6413. * console.log( range.cloneContents() );
  6414. *
  6415. * </script>
  6416. * ```
  6417. */
  6418. /**
  6419. * 遍历range内的节点。
  6420. * 每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  6421. * 作为其参数。
  6422. * 可以通过参数项 filterFn 来指定一个过滤器, 只有符合该过滤器过滤规则的节点才会触
  6423. * 发doFn函数的执行
  6424. * @method traversal
  6425. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  6426. * @param { Function } filterFn 过滤器, 该函数接受当前遍历的节点作为参数, 如果该节点满足过滤
  6427. * 规则, 请返回true, 该节点会触发doFn, 否则, 请返回false, 则该节点不
  6428. * 会触发doFn。
  6429. * @return { UE.dom.Range } 当前range对象
  6430. * @see UE.dom.Range:traversal(Function)
  6431. * @example
  6432. * ```html
  6433. *
  6434. * <body>
  6435. *
  6436. * <!-- 选区开始 -->
  6437. * <span></span>
  6438. * <a></a>
  6439. * <!-- 选区结束 -->
  6440. * </body>
  6441. *
  6442. * <script>
  6443. *
  6444. * //output: <span></span><a></a>
  6445. * console.log( range.cloneContents() );
  6446. *
  6447. * range.traversal( function ( node ) {
  6448. *
  6449. * node.className = "test";
  6450. *
  6451. * }, function ( node ) {
  6452. * return node.nodeType === 1;
  6453. * } );
  6454. *
  6455. * //output: <span class="test"></span><a class="test"></a>
  6456. * console.log( range.cloneContents() );
  6457. *
  6458. * </script>
  6459. * ```
  6460. */
  6461. traversal: function (doFn, filterFn) {
  6462. if (this.collapsed) return this;
  6463. var bookmark = this.createBookmark(),
  6464. end = bookmark.end,
  6465. current = domUtils.getNextDomNode(bookmark.start, false, filterFn);
  6466. while (
  6467. current &&
  6468. current !== end &&
  6469. domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
  6470. ) {
  6471. var tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  6472. doFn(current);
  6473. current = tmpNode;
  6474. }
  6475. return this.moveToBookmark(bookmark);
  6476. }
  6477. };
  6478. })();
  6479. // core/Selection.js
  6480. /**
  6481. * 选集
  6482. * @file
  6483. * @module UE.dom
  6484. * @class Selection
  6485. * @since 1.2.6.1
  6486. */
  6487. /**
  6488. * 选区集合
  6489. * @unfile
  6490. * @module UE.dom
  6491. * @class Selection
  6492. */
  6493. ;(function () {
  6494. function getBoundaryInformation(range, start) {
  6495. var getIndex = domUtils.getNodeIndex;
  6496. range = range.duplicate();
  6497. range.collapse(start);
  6498. var parent = range.parentElement();
  6499. //如果节点里没有子节点,直接退出
  6500. if (!parent.hasChildNodes()) {
  6501. return {container: parent, offset: 0};
  6502. }
  6503. var siblings = parent.children,
  6504. child,
  6505. testRange = range.duplicate(),
  6506. startIndex = 0,
  6507. endIndex = siblings.length - 1,
  6508. index = -1,
  6509. distance;
  6510. while (startIndex <= endIndex) {
  6511. index = Math.floor((startIndex + endIndex) / 2);
  6512. child = siblings[index];
  6513. testRange.moveToElementText(child);
  6514. var position = testRange.compareEndPoints("StartToStart", range);
  6515. if (position > 0) {
  6516. endIndex = index - 1;
  6517. } else if (position < 0) {
  6518. startIndex = index + 1;
  6519. } else {
  6520. //trace:1043
  6521. return {container: parent, offset: getIndex(child)};
  6522. }
  6523. }
  6524. if (index == -1) {
  6525. testRange.moveToElementText(parent);
  6526. testRange.setEndPoint("StartToStart", range);
  6527. distance = testRange.text.replace(/(\r\n|\r)/g, "\n").length;
  6528. siblings = parent.childNodes;
  6529. if (!distance) {
  6530. child = siblings[siblings.length - 1];
  6531. return {container: child, offset: child.nodeValue.length};
  6532. }
  6533. var i = siblings.length;
  6534. while (distance > 0) {
  6535. distance -= siblings[--i].nodeValue.length;
  6536. }
  6537. return {container: siblings[i], offset: -distance};
  6538. }
  6539. testRange.collapse(position > 0);
  6540. testRange.setEndPoint(position > 0 ? "StartToStart" : "EndToStart", range);
  6541. distance = testRange.text.replace(/(\r\n|\r)/g, "\n").length;
  6542. if (!distance) {
  6543. return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName]
  6544. ? {
  6545. container: parent,
  6546. offset: getIndex(child) + (position > 0 ? 0 : 1)
  6547. }
  6548. : {
  6549. container: child,
  6550. offset: position > 0 ? 0 : child.childNodes.length
  6551. };
  6552. }
  6553. while (distance > 0) {
  6554. try {
  6555. var pre = child;
  6556. child = child[position > 0 ? "previousSibling" : "nextSibling"];
  6557. distance -= child.nodeValue.length;
  6558. } catch (e) {
  6559. return {container: parent, offset: getIndex(pre)};
  6560. }
  6561. }
  6562. return {
  6563. container: child,
  6564. offset: position > 0 ? -distance : child.nodeValue.length + distance
  6565. };
  6566. }
  6567. /**
  6568. * 将ieRange转换为Range对象
  6569. * @param {Range} ieRange ieRange对象
  6570. * @param {Range} range Range对象
  6571. * @return {Range} range 返回转换后的Range对象
  6572. */
  6573. function transformIERangeToRange(ieRange, range) {
  6574. if (ieRange.item) {
  6575. range.selectNode(ieRange.item(0));
  6576. } else {
  6577. var bi = getBoundaryInformation(ieRange, true);
  6578. range.setStart(bi.container, bi.offset);
  6579. if (ieRange.compareEndPoints("StartToEnd", ieRange) != 0) {
  6580. bi = getBoundaryInformation(ieRange, false);
  6581. range.setEnd(bi.container, bi.offset);
  6582. }
  6583. }
  6584. return range;
  6585. }
  6586. /**
  6587. * 获得ieRange
  6588. * @param {Selection} sel Selection对象
  6589. * @return {ieRange} 得到ieRange
  6590. */
  6591. function _getIERange(sel) {
  6592. var ieRange;
  6593. //ie下有可能报错
  6594. try {
  6595. ieRange = sel.getNative().createRange();
  6596. } catch (e) {
  6597. return null;
  6598. }
  6599. var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
  6600. if ((el.ownerDocument || el) === sel.document) {
  6601. return ieRange;
  6602. }
  6603. return null;
  6604. }
  6605. var Selection = (dom.Selection = function (doc) {
  6606. var me = this,
  6607. iframe;
  6608. me.document = doc;
  6609. if (browser.ie9below) {
  6610. iframe = domUtils.getWindow(doc).frameElement;
  6611. domUtils.on(iframe, "beforedeactivate", function () {
  6612. me._bakIERange = me.getIERange();
  6613. });
  6614. domUtils.on(iframe, "activate", function () {
  6615. try {
  6616. if (!_getIERange(me) && me._bakIERange) {
  6617. me._bakIERange.select();
  6618. }
  6619. } catch (ex) {
  6620. }
  6621. me._bakIERange = null;
  6622. });
  6623. }
  6624. iframe = doc = null;
  6625. });
  6626. Selection.prototype = {
  6627. rangeInBody: function (rng, txtRange) {
  6628. var node = browser.ie9below || txtRange
  6629. ? rng.item ? rng.item() : rng.parentElement()
  6630. : rng.startContainer;
  6631. return node === this.document.body || domUtils.inDoc(node, this.document);
  6632. },
  6633. /**
  6634. * 获取原生seleciton对象
  6635. * @method getNative
  6636. * @return { Object } 获得selection对象
  6637. * @example
  6638. * ```javascript
  6639. * editor.selection.getNative();
  6640. * ```
  6641. */
  6642. getNative: function () {
  6643. var doc = this.document;
  6644. try {
  6645. return !doc
  6646. ? null
  6647. : browser.ie9below
  6648. ? doc.selection
  6649. : domUtils.getWindow(doc).getSelection();
  6650. } catch (e) {
  6651. return null;
  6652. }
  6653. },
  6654. /**
  6655. * 获得ieRange
  6656. * @method getIERange
  6657. * @return { Object } 返回ie原生的Range
  6658. * @example
  6659. * ```javascript
  6660. * editor.selection.getIERange();
  6661. * ```
  6662. */
  6663. getIERange: function () {
  6664. var ieRange = _getIERange(this);
  6665. if (!ieRange) {
  6666. if (this._bakIERange) {
  6667. return this._bakIERange;
  6668. }
  6669. }
  6670. return ieRange;
  6671. },
  6672. /**
  6673. * 缓存当前选区的range和选区的开始节点
  6674. * @method cache
  6675. */
  6676. cache: function () {
  6677. this.clear();
  6678. this._cachedRange = this.getRange();
  6679. this._cachedStartElement = this.getStart();
  6680. this._cachedStartElementPath = this.getStartElementPath();
  6681. },
  6682. /**
  6683. * 获取选区开始位置的父节点到body
  6684. * @method getStartElementPath
  6685. * @return { Array } 返回父节点集合
  6686. * @example
  6687. * ```javascript
  6688. * editor.selection.getStartElementPath();
  6689. * ```
  6690. */
  6691. getStartElementPath: function () {
  6692. if (this._cachedStartElementPath) {
  6693. return this._cachedStartElementPath;
  6694. }
  6695. var start = this.getStart();
  6696. if (start) {
  6697. return domUtils.findParents(start, true, null, true);
  6698. }
  6699. return [];
  6700. },
  6701. /**
  6702. * 清空缓存
  6703. * @method clear
  6704. */
  6705. clear: function () {
  6706. this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null;
  6707. },
  6708. /**
  6709. * 编辑器是否得到了选区
  6710. * @method isFocus
  6711. */
  6712. isFocus: function () {
  6713. try {
  6714. if (browser.ie9below) {
  6715. var nativeRange = _getIERange(this);
  6716. return !!(nativeRange && this.rangeInBody(nativeRange));
  6717. } else {
  6718. return !!this.getNative().rangeCount;
  6719. }
  6720. } catch (e) {
  6721. return false;
  6722. }
  6723. },
  6724. /**
  6725. * 获取选区对应的Range
  6726. * @method getRange
  6727. * @return { Object } 得到Range对象
  6728. * @example
  6729. * ```javascript
  6730. * editor.selection.getRange();
  6731. * ```
  6732. */
  6733. getRange: function () {
  6734. var me = this;
  6735. function optimze(range) {
  6736. var child = me.document.body.firstChild,
  6737. collapsed = range.collapsed;
  6738. while (child && child.firstChild) {
  6739. range.setStart(child, 0);
  6740. child = child.firstChild;
  6741. }
  6742. if (!range.startContainer) {
  6743. range.setStart(me.document.body, 0);
  6744. }
  6745. if (collapsed) {
  6746. range.collapse(true);
  6747. }
  6748. }
  6749. if (me._cachedRange != null) {
  6750. return this._cachedRange;
  6751. }
  6752. var range = new baidu.editor.dom.Range(me.document);
  6753. if (browser.ie9below) {
  6754. var nativeRange = me.getIERange();
  6755. if (nativeRange) {
  6756. //备份的_bakIERange可能已经实效了,dom树发生了变化比如从源码模式切回来,所以try一下,实效就放到body开始位置
  6757. try {
  6758. transformIERangeToRange(nativeRange, range);
  6759. } catch (e) {
  6760. optimze(range);
  6761. }
  6762. } else {
  6763. optimze(range);
  6764. }
  6765. } else {
  6766. var sel = me.getNative();
  6767. if (sel && sel.rangeCount) {
  6768. var firstRange = sel.getRangeAt(0);
  6769. var lastRange = sel.getRangeAt(sel.rangeCount - 1);
  6770. range
  6771. .setStart(firstRange.startContainer, firstRange.startOffset)
  6772. .setEnd(lastRange.endContainer, lastRange.endOffset);
  6773. if (
  6774. range.collapsed &&
  6775. domUtils.isBody(range.startContainer) &&
  6776. !range.startOffset
  6777. ) {
  6778. optimze(range);
  6779. }
  6780. } else {
  6781. //trace:1734 有可能已经不在dom树上了,标识的节点
  6782. if (
  6783. this._bakRange &&
  6784. domUtils.inDoc(this._bakRange.startContainer, this.document)
  6785. ) {
  6786. return this._bakRange;
  6787. }
  6788. optimze(range);
  6789. }
  6790. }
  6791. return (this._bakRange = range);
  6792. },
  6793. /**
  6794. * 获取开始元素,用于状态反射
  6795. * @method getStart
  6796. * @return { Element } 获得开始元素
  6797. * @example
  6798. * ```javascript
  6799. * editor.selection.getStart();
  6800. * ```
  6801. */
  6802. getStart: function () {
  6803. if (this._cachedStartElement) {
  6804. return this._cachedStartElement;
  6805. }
  6806. var range = browser.ie9below ? this.getIERange() : this.getRange(),
  6807. tmpRange,
  6808. start,
  6809. tmp,
  6810. parent;
  6811. if (browser.ie9below) {
  6812. if (!range) {
  6813. //todo 给第一个值可能会有问题
  6814. return this.document.body.firstChild;
  6815. }
  6816. //control元素
  6817. if (range.item) {
  6818. return range.item(0);
  6819. }
  6820. tmpRange = range.duplicate();
  6821. //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
  6822. tmpRange.text.length > 0 && tmpRange.moveStart("character", 1);
  6823. tmpRange.collapse(1);
  6824. start = tmpRange.parentElement();
  6825. parent = tmp = range.parentElement();
  6826. while ((tmp = tmp.parentNode)) {
  6827. if (tmp == start) {
  6828. start = parent;
  6829. break;
  6830. }
  6831. }
  6832. } else {
  6833. range.shrinkBoundary();
  6834. start = range.startContainer;
  6835. if (start.nodeType == 1 && start.hasChildNodes()) {
  6836. start =
  6837. start.childNodes[
  6838. Math.min(start.childNodes.length - 1, range.startOffset)
  6839. ];
  6840. }
  6841. if (start.nodeType == 3) {
  6842. return start.parentNode;
  6843. }
  6844. }
  6845. return start;
  6846. },
  6847. /**
  6848. * 得到选区中的文本
  6849. * @method getText
  6850. * @return { String } 选区中包含的文本
  6851. * @example
  6852. * ```javascript
  6853. * editor.selection.getText();
  6854. * ```
  6855. */
  6856. getText: function () {
  6857. var nativeSel, nativeRange;
  6858. if (this.isFocus() && (nativeSel = this.getNative())) {
  6859. nativeRange = browser.ie9below
  6860. ? nativeSel.createRange()
  6861. : nativeSel.getRangeAt(0);
  6862. return browser.ie9below ? nativeRange.text : nativeRange.toString();
  6863. }
  6864. return "";
  6865. },
  6866. /**
  6867. * 清除选区
  6868. * @method clearRange
  6869. * @example
  6870. * ```javascript
  6871. * editor.selection.clearRange();
  6872. * ```
  6873. */
  6874. clearRange: function () {
  6875. this.getNative()[browser.ie9below ? "empty" : "removeAllRanges"]();
  6876. }
  6877. };
  6878. })();
  6879. // core/Editor.js
  6880. /**
  6881. * 编辑器主类,包含编辑器提供的大部分公用接口
  6882. * @file
  6883. * @module UE
  6884. * @class Editor
  6885. * @since 1.2.6.1
  6886. */
  6887. /**
  6888. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  6889. * @unfile
  6890. * @module UE
  6891. */
  6892. /**
  6893. * UEditor的核心类,为用户提供与编辑器交互的接口。
  6894. * @unfile
  6895. * @module UE
  6896. * @class Editor
  6897. */
  6898. ;(function () {
  6899. var uid = 0,
  6900. _selectionChangeTimer;
  6901. /**
  6902. * 获取编辑器的html内容,赋值到编辑器所在表单的textarea文本域里面
  6903. * @private
  6904. * @method setValue
  6905. * @param { UE.Editor } editor 编辑器事例
  6906. */
  6907. function setValue(form, editor) {
  6908. var textarea;
  6909. if (editor.options.textarea) {
  6910. if (utils.isString(editor.options.textarea)) {
  6911. for (
  6912. var i = 0, ti, tis = domUtils.getElementsByTagName(form, "textarea");
  6913. (ti = tis[i++]);
  6914. ) {
  6915. if (ti.id == "ueditor_textarea_" + editor.options.textarea) {
  6916. textarea = ti;
  6917. break;
  6918. }
  6919. }
  6920. } else {
  6921. textarea = editor.textarea;
  6922. }
  6923. }
  6924. if (!textarea) {
  6925. form.appendChild(
  6926. (textarea = domUtils.createElement(document, "textarea", {
  6927. name: editor.options.textarea,
  6928. id: "ueditor_textarea_" + editor.options.textarea,
  6929. style: "display:none"
  6930. }))
  6931. );
  6932. //不要产生多个textarea
  6933. editor.textarea = textarea;
  6934. }
  6935. !textarea.getAttribute("name") &&
  6936. textarea.setAttribute("name", editor.options.textarea);
  6937. textarea.value = editor.hasContents()
  6938. ? editor.options.allHtmlEnabled
  6939. ? editor.getAllHtml()
  6940. : editor.getContent(null, null, true)
  6941. : "";
  6942. }
  6943. function loadPlugins(me) {
  6944. //初始化插件
  6945. for (var pi in UE.plugins) {
  6946. UE.plugins[pi].call(me);
  6947. }
  6948. }
  6949. function checkCurLang(I18N) {
  6950. for (var lang in I18N) {
  6951. return lang;
  6952. }
  6953. }
  6954. function langReadied(me) {
  6955. me.langIsReady = true;
  6956. me.fireEvent("langReady");
  6957. }
  6958. /**
  6959. * 编辑器准备就绪后会触发该事件
  6960. * @module UE
  6961. * @class Editor
  6962. * @event ready
  6963. * @remind render方法执行完成之后,会触发该事件
  6964. * @remind
  6965. * @example
  6966. * ```javascript
  6967. * editor.addListener( 'ready', function( editor ) {
  6968. * editor.execCommand( 'focus' ); //编辑器家在完成后,让编辑器拿到焦点
  6969. * } );
  6970. * ```
  6971. */
  6972. /**
  6973. * 执行destroy方法,会触发该事件
  6974. * @module UE
  6975. * @class Editor
  6976. * @event destroy
  6977. * @see UE.Editor:destroy()
  6978. */
  6979. /**
  6980. * 执行reset方法,会触发该事件
  6981. * @module UE
  6982. * @class Editor
  6983. * @event reset
  6984. * @see UE.Editor:reset()
  6985. */
  6986. /**
  6987. * 执行focus方法,会触发该事件
  6988. * @module UE
  6989. * @class Editor
  6990. * @event focus
  6991. * @see UE.Editor:focus(Boolean)
  6992. */
  6993. /**
  6994. * 语言加载完成会触发该事件
  6995. * @module UE
  6996. * @class Editor
  6997. * @event langReady
  6998. */
  6999. /**
  7000. * 运行命令之后会触发该命令
  7001. * @module UE
  7002. * @class Editor
  7003. * @event beforeExecCommand
  7004. */
  7005. /**
  7006. * 运行命令之后会触发该命令
  7007. * @module UE
  7008. * @class Editor
  7009. * @event afterExecCommand
  7010. */
  7011. /**
  7012. * 运行命令之前会触发该命令
  7013. * @module UE
  7014. * @class Editor
  7015. * @event firstBeforeExecCommand
  7016. */
  7017. /**
  7018. * 在getContent方法执行之前会触发该事件
  7019. * @module UE
  7020. * @class Editor
  7021. * @event beforeGetContent
  7022. * @see UE.Editor:getContent()
  7023. */
  7024. /**
  7025. * 在getContent方法执行之后会触发该事件
  7026. * @module UE
  7027. * @class Editor
  7028. * @event afterGetContent
  7029. * @see UE.Editor:getContent()
  7030. */
  7031. /**
  7032. * 在getAllHtml方法执行时会触发该事件
  7033. * @module UE
  7034. * @class Editor
  7035. * @event getAllHtml
  7036. * @see UE.Editor:getAllHtml()
  7037. */
  7038. /**
  7039. * 在setContent方法执行之前会触发该事件
  7040. * @module UE
  7041. * @class Editor
  7042. * @event beforeSetContent
  7043. * @see UE.Editor:setContent(String)
  7044. */
  7045. /**
  7046. * 在setContent方法执行之后会触发该事件
  7047. * @module UE
  7048. * @class Editor
  7049. * @event afterSetContent
  7050. * @see UE.Editor:setContent(String)
  7051. */
  7052. /**
  7053. * 每当编辑器内部选区发生改变时,将触发该事件
  7054. * @event selectionchange
  7055. * @warning 该事件的触发非常频繁,不建议在该事件的处理过程中做重量级的处理
  7056. * @example
  7057. * ```javascript
  7058. * editor.addListener( 'selectionchange', function( editor ) {
  7059. * console.log('选区发生改变');
  7060. * }
  7061. */
  7062. /**
  7063. * 在所有selectionchange的监听函数执行之前,会触发该事件
  7064. * @module UE
  7065. * @class Editor
  7066. * @event beforeSelectionChange
  7067. * @see UE.Editor:selectionchange
  7068. */
  7069. /**
  7070. * 在所有selectionchange的监听函数执行完之后,会触发该事件
  7071. * @module UE
  7072. * @class Editor
  7073. * @event afterSelectionChange
  7074. * @see UE.Editor:selectionchange
  7075. */
  7076. /**
  7077. * 编辑器内容发生改变时会触发该事件
  7078. * @module UE
  7079. * @class Editor
  7080. * @event contentChange
  7081. */
  7082. /**
  7083. * 以默认参数构建一个编辑器实例
  7084. * @constructor
  7085. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  7086. * @example
  7087. * ```javascript
  7088. * var editor = new UE.Editor();
  7089. * editor.execCommand('blod');
  7090. * ```
  7091. * @see UE.Config
  7092. */
  7093. /**
  7094. * 以给定的参数集合创建一个编辑器实例,对于未指定的参数,将应用默认参数。
  7095. * @constructor
  7096. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  7097. * @param { Object } setting 创建编辑器的参数
  7098. * @example
  7099. * ```javascript
  7100. * var editor = new UE.Editor();
  7101. * editor.execCommand('blod');
  7102. * ```
  7103. * @see UE.Config
  7104. */
  7105. var Editor = (UE.Editor = function (options) {
  7106. var me = this;
  7107. me.uid = uid++;
  7108. EventBase.call(me);
  7109. me.commands = {};
  7110. me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true);
  7111. me.shortcutkeys = {};
  7112. me.inputRules = [];
  7113. me.outputRules = [];
  7114. //设置默认的常用属性
  7115. me.setOpt(Editor.defaultOptions(me));
  7116. /* 尝试异步加载后台配置 */
  7117. me.loadServerConfig();
  7118. if (!utils.isEmptyObject(UE.I18N)) {
  7119. //修改默认的语言类型
  7120. me.options.lang = checkCurLang(UE.I18N);
  7121. UE.plugin.load(me);
  7122. langReadied(me);
  7123. } else {
  7124. utils.loadFile(
  7125. document,
  7126. {
  7127. src:
  7128. me.options.langPath +
  7129. me.options.lang +
  7130. "/" +
  7131. me.options.lang +
  7132. ".js",
  7133. tag: "script",
  7134. type: "text/javascript",
  7135. defer: "defer"
  7136. },
  7137. function () {
  7138. UE.plugin.load(me);
  7139. langReadied(me);
  7140. }
  7141. );
  7142. }
  7143. UE.instants["ueditorInstant" + me.uid] = me;
  7144. });
  7145. Editor.prototype = {
  7146. registerCommand: function (name, obj) {
  7147. this.commands[name] = obj;
  7148. },
  7149. /**
  7150. * 编辑器对外提供的监听ready事件的接口, 通过调用该方法,达到的效果与监听ready事件是一致的
  7151. * @method ready
  7152. * @param { Function } fn 编辑器ready之后所执行的回调, 如果在注册事件之前编辑器已经ready,将会
  7153. * 立即触发该回调。
  7154. * @remind 需要等待编辑器加载完成后才能执行的代码,可以使用该方法传入
  7155. * @example
  7156. * ```javascript
  7157. * editor.ready( function( editor ) {
  7158. * editor.setContent('初始化完毕');
  7159. * } );
  7160. * ```
  7161. * @see UE.Editor.event:ready
  7162. */
  7163. ready: function (fn) {
  7164. var me = this;
  7165. if (fn) {
  7166. me.isReady ? fn.apply(me) : me.addListener("ready", fn);
  7167. }
  7168. },
  7169. /**
  7170. * 该方法用于设置placeholder
  7171. * @method setPlaceholder
  7172. * @param { String } placeholder 编辑器的placeholder文案
  7173. * @example
  7174. * ```javascript
  7175. * editor.setPlaceholder('请输入内容');
  7176. * ```
  7177. */
  7178. setPlaceholder: function () {
  7179. function contentChange() {
  7180. var localHtml = this.getPlainTxt();
  7181. if (!localHtml.trim()) {
  7182. UE.dom.domUtils.addClass(this.body, 'empty');
  7183. } else {
  7184. UE.dom.domUtils.removeClasses(this.body, 'empty');
  7185. }
  7186. }
  7187. return function (placeholder) {
  7188. var _editor = this;
  7189. _editor.ready(function () {
  7190. contentChange.call(_editor);
  7191. _editor.body.setAttribute('placeholder', placeholder);
  7192. });
  7193. _editor.removeListener('keyup contentchange', contentChange);
  7194. _editor.addListener('keyup contentchange', contentChange);
  7195. }
  7196. }(),
  7197. /**
  7198. * 该方法是提供给插件里面使用,设置配置项默认值
  7199. * @method setOpt
  7200. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  7201. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  7202. * @param { String } key 编辑器的可接受的选项名称
  7203. * @param { * } val 该选项可接受的值
  7204. * @example
  7205. * ```javascript
  7206. * editor.setOpt( 'initContent', '欢迎使用编辑器' );
  7207. * ```
  7208. */
  7209. /**
  7210. * 该方法是提供给插件里面使用,以{key:value}集合的方式设置插件内用到的配置项默认值
  7211. * @method setOpt
  7212. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  7213. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  7214. * @param { Object } options 将要设置的选项的键值对对象
  7215. * @example
  7216. * ```javascript
  7217. * editor.setOpt( {
  7218. * 'initContent': '欢迎使用编辑器'
  7219. * } );
  7220. * ```
  7221. */
  7222. setOpt: function (key, val) {
  7223. var obj = {};
  7224. if (utils.isString(key)) {
  7225. obj[key] = val;
  7226. } else {
  7227. obj = key;
  7228. }
  7229. utils.extend(this.options, obj, true);
  7230. },
  7231. getOpt: function (key) {
  7232. return this.options[key];
  7233. },
  7234. /**
  7235. * 销毁编辑器实例,使用textarea代替
  7236. * @method destroy
  7237. * @example
  7238. * ```javascript
  7239. * editor.destroy();
  7240. * ```
  7241. */
  7242. destroy: function () {
  7243. var me = this;
  7244. me.fireEvent("destroy");
  7245. var container = me.container.parentNode;
  7246. var textarea = me.textarea;
  7247. if (!textarea) {
  7248. textarea = document.createElement("textarea");
  7249. container.parentNode.insertBefore(textarea, container);
  7250. } else {
  7251. textarea.style.display = "";
  7252. }
  7253. textarea.style.width = me.iframe.offsetWidth + "px";
  7254. textarea.style.height = me.iframe.offsetHeight + "px";
  7255. textarea.value = me.getContent();
  7256. textarea.id = me.key;
  7257. container.innerHTML = "";
  7258. domUtils.remove(container);
  7259. var key = me.key;
  7260. //trace:2004
  7261. for (var p in me) {
  7262. if (me.hasOwnProperty(p)) {
  7263. delete this[p];
  7264. }
  7265. }
  7266. UE.delEditor(key);
  7267. },
  7268. /**
  7269. * 渲染编辑器的DOM到指定容器
  7270. * @method render
  7271. * @param { String } containerId 指定一个容器ID
  7272. * @remind 执行该方法,会触发ready事件
  7273. * @warning 必须且只能调用一次
  7274. */
  7275. /**
  7276. * 渲染编辑器的DOM到指定容器
  7277. * @method render
  7278. * @param { Element } containerDom 直接指定容器对象
  7279. * @remind 执行该方法,会触发ready事件
  7280. * @warning 必须且只能调用一次
  7281. */
  7282. render: function (container) {
  7283. var me = this,
  7284. options = me.options,
  7285. getStyleValue = function (attr) {
  7286. return parseInt(domUtils.getComputedStyle(container, attr));
  7287. };
  7288. if (utils.isString(container)) {
  7289. container = document.getElementById(container);
  7290. }
  7291. if (container) {
  7292. if (options.initialFrameWidth) {
  7293. options.minFrameWidth = options.initialFrameWidth;
  7294. } else {
  7295. options.minFrameWidth = options.initialFrameWidth =
  7296. container.offsetWidth;
  7297. }
  7298. if (options.initialFrameHeight) {
  7299. options.minFrameHeight = options.initialFrameHeight;
  7300. } else {
  7301. options.initialFrameHeight = options.minFrameHeight =
  7302. container.offsetHeight;
  7303. }
  7304. container.style.width = /%$/.test(options.initialFrameWidth)
  7305. ? "100%"
  7306. : options.initialFrameWidth -
  7307. getStyleValue("padding-left") -
  7308. getStyleValue("padding-right") +
  7309. "px";
  7310. container.style.height = /%$/.test(options.initialFrameHeight)
  7311. ? "100%"
  7312. : options.initialFrameHeight -
  7313. getStyleValue("padding-top") -
  7314. getStyleValue("padding-bottom") +
  7315. "px";
  7316. container.style.zIndex = options.zIndex;
  7317. var html =
  7318. (ie && browser.version < 9 ? "" : "<!DOCTYPE html>") +
  7319. "<html xmlns='http://www.w3.org/1999/xhtml' class='view' >" +
  7320. "<head>" +
  7321. "<style type='text/css'>" +
  7322. //设置四周的留边
  7323. ".view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n" +
  7324. //设置默认字体和字号
  7325. //font-family不能呢随便改,在safari下fillchar会有解析问题
  7326. "body{margin:8px;font-family:sans-serif;font-size:16px;}" +
  7327. //设置placeholder
  7328. "body.empty:before{content:attr(placeholder);position:absolute;color:#999;}" +
  7329. //设置段落间距
  7330. "p{margin:5px 0;}</style>" +
  7331. (options.iframeCssUrl
  7332. ? "<link rel='stylesheet' type='text/css' href='" +
  7333. utils.unhtml(options.iframeCssUrl) +
  7334. "'/>"
  7335. : "") +
  7336. (options.initialStyle
  7337. ? "<style>" + options.initialStyle + "</style>"
  7338. : "") +
  7339. "</head>" +
  7340. "<body class='view' ></body>" +
  7341. "<script type='text/javascript' " +
  7342. (ie ? "defer='defer'" : "") +
  7343. " id='_initialScript'>" +
  7344. "setTimeout(function(){editor = window.parent.UE.instants['ueditorInstant" +
  7345. me.uid +
  7346. "'];editor._setup(document);},0);" +
  7347. "var _tmpScript = document.getElementById('_initialScript');_tmpScript.parentNode.removeChild(_tmpScript);" +
  7348. "</script>" +
  7349. (options.iframeJsUrl
  7350. ? "<script type='text/javascript' src='" +
  7351. utils.unhtml(options.iframeJsUrl) +
  7352. "'></script>"
  7353. : "") +
  7354. "</html>";
  7355. container.appendChild(
  7356. domUtils.createElement(document, "iframe", {
  7357. id: "ueditor_" + me.uid,
  7358. width: "100%",
  7359. height: "100%",
  7360. frameborder: "0",
  7361. //先注释掉了,加的原因忘记了,但开启会直接导致全屏模式下内容多时不会出现滚动条
  7362. // scrolling :'no',
  7363. src:
  7364. "javascript:void(function(){document.open();" +
  7365. (options.customDomain && document.domain != location.hostname
  7366. ? 'document.domain="' + document.domain + '";'
  7367. : "") +
  7368. 'document.write("' +
  7369. html +
  7370. '");document.close();}())'
  7371. })
  7372. );
  7373. container.style.overflow = "hidden";
  7374. //解决如果是给定的百分比,会导致高度算不对的问题
  7375. setTimeout(function () {
  7376. if (/%$/.test(options.initialFrameWidth)) {
  7377. options.minFrameWidth = options.initialFrameWidth =
  7378. container.offsetWidth;
  7379. //如果这里给定宽度,会导致ie在拖动窗口大小时,编辑区域不随着变化
  7380. // container.style.width = options.initialFrameWidth + 'px';
  7381. }
  7382. if (/%$/.test(options.initialFrameHeight)) {
  7383. options.minFrameHeight = options.initialFrameHeight =
  7384. container.offsetHeight;
  7385. container.style.height = options.initialFrameHeight + "px";
  7386. }
  7387. });
  7388. }
  7389. },
  7390. /**
  7391. * 编辑器初始化
  7392. * @method _setup
  7393. * @private
  7394. * @param { Element } doc 编辑器Iframe中的文档对象
  7395. */
  7396. _setup: function (doc) {
  7397. var me = this,
  7398. options = me.options;
  7399. if (ie) {
  7400. doc.body.disabled = true;
  7401. doc.body.contentEditable = true;
  7402. doc.body.disabled = false;
  7403. } else {
  7404. doc.body.contentEditable = true;
  7405. }
  7406. doc.body.spellcheck = false;
  7407. me.document = doc;
  7408. me.window = doc.defaultView || doc.parentWindow;
  7409. me.iframe = me.window.frameElement;
  7410. me.body = doc.body;
  7411. me.selection = new dom.Selection(doc);
  7412. //gecko初始化就能得到range,无法判断isFocus了
  7413. var geckoSel;
  7414. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7415. geckoSel.removeAllRanges();
  7416. }
  7417. this._initEvents();
  7418. //为form提交提供一个隐藏的textarea
  7419. for (
  7420. var form = this.iframe.parentNode;
  7421. !domUtils.isBody(form);
  7422. form = form.parentNode
  7423. ) {
  7424. if (form.tagName == "FORM") {
  7425. me.form = form;
  7426. if (me.options.autoSyncData) {
  7427. domUtils.on(me.window, "blur", function () {
  7428. setValue(form, me);
  7429. });
  7430. } else {
  7431. domUtils.on(form, "submit", function () {
  7432. setValue(this, me);
  7433. });
  7434. }
  7435. break;
  7436. }
  7437. }
  7438. if (options.initialContent) {
  7439. if (options.autoClearinitialContent) {
  7440. var oldExecCommand = me.execCommand;
  7441. me.execCommand = function () {
  7442. me.fireEvent("firstBeforeExecCommand");
  7443. return oldExecCommand.apply(me, arguments);
  7444. };
  7445. this._setDefaultContent(options.initialContent);
  7446. } else this.setContent(options.initialContent, false, true);
  7447. }
  7448. //编辑器不能为空内容
  7449. if (domUtils.isEmptyNode(me.body)) {
  7450. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  7451. }
  7452. //如果要求focus, 就把光标定位到内容开始
  7453. if (options.focus) {
  7454. setTimeout(function () {
  7455. me.focus(me.options.focusInEnd);
  7456. //如果自动清除开着,就不需要做selectionchange;
  7457. !me.options.autoClearinitialContent && me._selectionChange();
  7458. }, 0);
  7459. }
  7460. if (!me.container) {
  7461. me.container = this.iframe.parentNode;
  7462. }
  7463. if (options.fullscreen && me.ui) {
  7464. me.ui.setFullScreen(true);
  7465. }
  7466. try {
  7467. me.document.execCommand("2D-position", false, false);
  7468. } catch (e) {
  7469. }
  7470. try {
  7471. me.document.execCommand("enableInlineTableEditing", false, false);
  7472. } catch (e) {
  7473. }
  7474. try {
  7475. me.document.execCommand("enableObjectResizing", false, false);
  7476. } catch (e) {
  7477. }
  7478. //挂接快捷键
  7479. me._bindshortcutKeys();
  7480. me.isReady = 1;
  7481. me.fireEvent("ready");
  7482. options.onready && options.onready.call(me);
  7483. if (!browser.ie9below) {
  7484. domUtils.on(me.window, ["blur", "focus"], function (e) {
  7485. //chrome下会出现alt+tab切换时,导致选区位置不对
  7486. if (e.type == "blur") {
  7487. me._bakRange = me.selection.getRange();
  7488. try {
  7489. me._bakNativeRange = me.selection.getNative().getRangeAt(0);
  7490. me.selection.getNative().removeAllRanges();
  7491. } catch (e) {
  7492. me._bakNativeRange = null;
  7493. }
  7494. } else {
  7495. try {
  7496. me._bakRange && me._bakRange.select();
  7497. } catch (e) {
  7498. }
  7499. }
  7500. });
  7501. }
  7502. //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
  7503. if (browser.gecko && browser.version <= 10902) {
  7504. //修复ff3.6初始化进来,不能点击获得焦点
  7505. me.body.contentEditable = false;
  7506. setTimeout(function () {
  7507. me.body.contentEditable = true;
  7508. }, 100);
  7509. setInterval(function () {
  7510. me.body.style.height = me.iframe.offsetHeight - 20 + "px";
  7511. }, 100);
  7512. }
  7513. !options.isShow && me.setHide();
  7514. options.readonly && me.setDisabled();
  7515. },
  7516. /**
  7517. * 同步数据到编辑器所在的form
  7518. * 从编辑器的容器节点向上查找form元素,若找到,就同步编辑内容到找到的form里,为提交数据做准备,主要用于是手动提交的情况
  7519. * 后台取得数据的键值,使用你容器上的name属性,如果没有就使用参数里的textarea项
  7520. * @method sync
  7521. * @example
  7522. * ```javascript
  7523. * editor.sync();
  7524. * form.sumbit(); //form变量已经指向了form元素
  7525. * ```
  7526. */
  7527. /**
  7528. * 根据传入的formId,在页面上查找要同步数据的表单,若找到,就同步编辑内容到找到的form里,为提交数据做准备
  7529. * 后台取得数据的键值,该键值默认使用给定的编辑器容器的name属性,如果没有name属性则使用参数项里给定的“textarea”项
  7530. * @method sync
  7531. * @param { String } formID 指定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
  7532. */
  7533. sync: function (formId) {
  7534. var me = this,
  7535. form = formId
  7536. ? document.getElementById(formId)
  7537. : domUtils.findParent(
  7538. me.iframe.parentNode,
  7539. function (node) {
  7540. return node.tagName == "FORM";
  7541. },
  7542. true
  7543. );
  7544. form && setValue(form, me);
  7545. },
  7546. /**
  7547. * 设置编辑器高度
  7548. * @method setHeight
  7549. * @remind 当配置项autoHeightEnabled为真时,该方法无效
  7550. * @param { Number } number 设置的高度值,纯数值,不带单位
  7551. * @example
  7552. * ```javascript
  7553. * editor.setHeight(number);
  7554. * ```
  7555. */
  7556. setHeight: function (height, notSetHeight) {
  7557. if (height !== parseInt(this.iframe.parentNode.style.height)) {
  7558. this.iframe.parentNode.style.height = height + "px";
  7559. }
  7560. !notSetHeight &&
  7561. (this.options.minFrameHeight = this.options.initialFrameHeight = height);
  7562. this.body.style.height = height + "px";
  7563. !notSetHeight && this.trigger("setHeight");
  7564. },
  7565. /**
  7566. * 为编辑器的编辑命令提供快捷键
  7567. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  7568. * @method addshortcutkey
  7569. * @param { Object } keyset 命令名和快捷键键值对对象,多个按钮的快捷键用“+”分隔
  7570. * @example
  7571. * ```javascript
  7572. * editor.addshortcutkey({
  7573. * "Bold" : "ctrl+66",//^B
  7574. * "Italic" : "ctrl+73", //^I
  7575. * });
  7576. * ```
  7577. */
  7578. /**
  7579. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  7580. * @method addshortcutkey
  7581. * @param { String } cmd 触发快捷键时,响应的命令
  7582. * @param { String } keys 快捷键的字符串,多个按钮用“+”分隔
  7583. * @example
  7584. * ```javascript
  7585. * editor.addshortcutkey("Underline", "ctrl+85"); //^U
  7586. * ```
  7587. */
  7588. addshortcutkey: function (cmd, keys) {
  7589. var obj = {};
  7590. if (keys) {
  7591. obj[cmd] = keys;
  7592. } else {
  7593. obj = cmd;
  7594. }
  7595. utils.extend(this.shortcutkeys, obj);
  7596. },
  7597. /**
  7598. * 对编辑器设置keydown事件监听,绑定快捷键和命令,当快捷键组合触发成功,会响应对应的命令
  7599. * @method _bindshortcutKeys
  7600. * @private
  7601. */
  7602. _bindshortcutKeys: function () {
  7603. var me = this,
  7604. shortcutkeys = this.shortcutkeys;
  7605. me.addListener("keydown", function (type, e) {
  7606. var keyCode = e.keyCode || e.which;
  7607. for (var i in shortcutkeys) {
  7608. var tmp = shortcutkeys[i].split(",");
  7609. for (var t = 0, ti; (ti = tmp[t++]);) {
  7610. ti = ti.split(":");
  7611. var key = ti[0],
  7612. param = ti[1];
  7613. if (
  7614. /^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) ||
  7615. /^(\d+)$/.test(key)
  7616. ) {
  7617. if (
  7618. ((RegExp.$1 == "ctrl" ? e.ctrlKey || e.metaKey : 0) &&
  7619. (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1) &&
  7620. keyCode == RegExp.$3) ||
  7621. keyCode == RegExp.$1
  7622. ) {
  7623. if (me.queryCommandState(i, param) != -1)
  7624. me.execCommand(i, param);
  7625. domUtils.preventDefault(e);
  7626. }
  7627. }
  7628. }
  7629. }
  7630. });
  7631. },
  7632. /**
  7633. * 获取编辑器的内容
  7634. * @method getContent
  7635. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  7636. * @return { String } 编辑器的内容字符串, 如果编辑器的内容为空,或者是空的标签内容(如:”&lt;p&gt;&lt;br/&gt;&lt;/p&gt;“), 则返回空字符串
  7637. * @example
  7638. * ```javascript
  7639. * //编辑器html内容:<p>1<strong>2<em>34</em>5</strong>6</p>
  7640. * var content = editor.getContent(); //返回值:<p>1<strong>2<em>34</em>5</strong>6</p>
  7641. * ```
  7642. */
  7643. /**
  7644. * 获取编辑器的内容。 可以通过参数定义编辑器内置的判空规则
  7645. * @method getContent
  7646. * @param { Function } fn 自定的判空规则, 要求该方法返回一个boolean类型的值,
  7647. * 代表当前编辑器的内容是否空,
  7648. * 如果返回true, 则该方法将直接返回空字符串;如果返回false,则编辑器将返回
  7649. * 经过内置过滤规则处理后的内容。
  7650. * @remind 该方法在处理包含有初始化内容的时候能起到很好的作用。
  7651. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  7652. * @return { String } 编辑器的内容字符串
  7653. * @example
  7654. * ```javascript
  7655. * // editor 是一个编辑器的实例
  7656. * var content = editor.getContent( function ( editor ) {
  7657. * return editor.body.innerHTML === '欢迎使用UEditor'; //返回空字符串
  7658. * } );
  7659. * ```
  7660. */
  7661. getContent: function (cmd, fn, notSetCursor, ignoreBlank, formatter) {
  7662. var me = this;
  7663. if (cmd && utils.isFunction(cmd)) {
  7664. fn = cmd;
  7665. cmd = "";
  7666. }
  7667. if (fn ? !fn() : !this.hasContents()) {
  7668. return "";
  7669. }
  7670. me.fireEvent("beforegetcontent");
  7671. var root = UE.htmlparser(me.body.innerHTML, ignoreBlank);
  7672. me.filterOutputRule(root);
  7673. me.fireEvent("aftergetcontent", cmd, root);
  7674. return root.toHtml(formatter);
  7675. },
  7676. /**
  7677. * 取得完整的html代码,可以直接显示成完整的html文档
  7678. * @method getAllHtml
  7679. * @return { String } 编辑器的内容html文档字符串
  7680. * @eaxmple
  7681. * ```javascript
  7682. * editor.getAllHtml(); //返回格式大致是: <html><head>...</head><body>...</body></html>
  7683. * ```
  7684. */
  7685. getAllHtml: function () {
  7686. var me = this,
  7687. headHtml = [],
  7688. html = "";
  7689. me.fireEvent("getAllHtml", headHtml);
  7690. if (browser.ie && browser.version > 8) {
  7691. var headHtmlForIE9 = "";
  7692. utils.each(me.document.styleSheets, function (si) {
  7693. headHtmlForIE9 += si.href
  7694. ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />'
  7695. : "<style>" + si.cssText + "</style>";
  7696. });
  7697. utils.each(me.document.getElementsByTagName("script"), function (si) {
  7698. headHtmlForIE9 += si.outerHTML;
  7699. });
  7700. }
  7701. return (
  7702. "<html><head>" +
  7703. (me.options.charset
  7704. ? '<meta http-equiv="Content-Type" content="text/html; charset=' +
  7705. me.options.charset +
  7706. '"/>'
  7707. : "") +
  7708. (headHtmlForIE9 ||
  7709. me.document.getElementsByTagName("head")[0].innerHTML) +
  7710. headHtml.join("\n") +
  7711. "</head>" +
  7712. "<body " +
  7713. (ie && browser.version < 9 ? 'class="view"' : "") +
  7714. ">" +
  7715. me.getContent(null, null, true) +
  7716. "</body></html>"
  7717. );
  7718. },
  7719. /**
  7720. * 得到编辑器的纯文本内容,但会保留段落格式
  7721. * @method getPlainTxt
  7722. * @return { String } 编辑器带段落格式的纯文本内容字符串
  7723. * @example
  7724. * ```javascript
  7725. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  7726. * console.log(editor.getPlainTxt()); //输出:"1\n2\n
  7727. * ```
  7728. */
  7729. getPlainTxt: function () {
  7730. var reg = new RegExp(domUtils.fillChar, "g"),
  7731. html = this.body.innerHTML.replace(/[\n\r]/g, ""); //ie要先去了\n在处理
  7732. html = html
  7733. .replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, "\n")
  7734. .replace(/<br\/?>/gi, "\n")
  7735. .replace(/<[^>/]+>/g, "")
  7736. .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
  7737. return dtd.$block[c] ? "\n" : b ? b : "";
  7738. });
  7739. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  7740. return html
  7741. .replace(reg, "")
  7742. .replace(/\u00a0/g, " ")
  7743. .replace(/&nbsp;/g, " ");
  7744. },
  7745. /**
  7746. * 获取编辑器中的纯文本内容,没有段落格式
  7747. * @method getContentTxt
  7748. * @return { String } 编辑器不带段落格式的纯文本内容字符串
  7749. * @example
  7750. * ```javascript
  7751. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  7752. * console.log(editor.getPlainTxt()); //输出:"12
  7753. * ```
  7754. */
  7755. getContentTxt: function () {
  7756. var reg = new RegExp(domUtils.fillChar, "g");
  7757. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  7758. return this.body[browser.ie ? "innerText" : "textContent"]
  7759. .replace(reg, "")
  7760. .replace(/\u00a0/g, " ");
  7761. },
  7762. /**
  7763. * 设置编辑器的内容,可修改编辑器当前的html内容
  7764. * @method setContent
  7765. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  7766. * @warning 该方法会触发selectionchange事件
  7767. * @param { String } html 要插入的html内容
  7768. * @example
  7769. * ```javascript
  7770. * editor.getContent('<p>test</p>');
  7771. * ```
  7772. */
  7773. /**
  7774. * 设置编辑器的内容,可修改编辑器当前的html内容
  7775. * @method setContent
  7776. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  7777. * @warning 该方法会触发selectionchange事件
  7778. * @param { String } html 要插入的html内容
  7779. * @param { Boolean } isAppendTo 若传入true,不清空原来的内容,在最后插入内容,否则,清空内容再插入
  7780. * @example
  7781. * ```javascript
  7782. * //假设设置前的编辑器内容是 <p>old text</p>
  7783. * editor.setContent('<p>new text</p>', true); //插入的结果是<p>old text</p><p>new text</p>
  7784. * ```
  7785. */
  7786. setContent: function (html, isAppendTo, notFireSelectionchange) {
  7787. var me = this;
  7788. me.fireEvent("beforesetcontent", html);
  7789. var root = UE.htmlparser(html);
  7790. me.filterInputRule(root);
  7791. html = root.toHtml();
  7792. me.body.innerHTML = (isAppendTo ? me.body.innerHTML : "") + html;
  7793. function isCdataDiv(node) {
  7794. return node.tagName == "DIV" && node.getAttribute("cdata_tag");
  7795. }
  7796. //给文本或者inline节点套p标签
  7797. if (me.options.enterTag == "p") {
  7798. var child = this.body.firstChild,
  7799. tmpNode;
  7800. if (
  7801. !child ||
  7802. (child.nodeType == 1 &&
  7803. (dtd.$cdata[child.tagName] ||
  7804. isCdataDiv(child) ||
  7805. domUtils.isCustomeNode(child)) &&
  7806. child === this.body.lastChild)
  7807. ) {
  7808. this.body.innerHTML =
  7809. "<p>" +
  7810. (browser.ie ? "&nbsp;" : "<br/>") +
  7811. "</p>" +
  7812. this.body.innerHTML;
  7813. } else {
  7814. var p = me.document.createElement("p");
  7815. while (child) {
  7816. while (
  7817. child &&
  7818. (child.nodeType == 3 ||
  7819. (child.nodeType == 1 &&
  7820. dtd.p[child.tagName] &&
  7821. !dtd.$cdata[child.tagName]))
  7822. ) {
  7823. tmpNode = child.nextSibling;
  7824. p.appendChild(child);
  7825. child = tmpNode;
  7826. }
  7827. if (p.firstChild) {
  7828. if (!child) {
  7829. me.body.appendChild(p);
  7830. break;
  7831. } else {
  7832. child.parentNode.insertBefore(p, child);
  7833. p = me.document.createElement("p");
  7834. }
  7835. }
  7836. child = child.nextSibling;
  7837. }
  7838. }
  7839. }
  7840. me.fireEvent("aftersetcontent");
  7841. me.fireEvent("contentchange");
  7842. !notFireSelectionchange && me._selectionChange();
  7843. //清除保存的选区
  7844. me._bakRange = me._bakIERange = me._bakNativeRange = null;
  7845. //trace:1742 setContent后gecko能得到焦点问题
  7846. var geckoSel;
  7847. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7848. geckoSel.removeAllRanges();
  7849. }
  7850. if (me.options.autoSyncData) {
  7851. me.form && setValue(me.form, me);
  7852. }
  7853. },
  7854. /**
  7855. * 让编辑器获得焦点,默认focus到编辑器头部
  7856. * @method focus
  7857. * @example
  7858. * ```javascript
  7859. * editor.focus()
  7860. * ```
  7861. */
  7862. /**
  7863. * 让编辑器获得焦点,toEnd确定focus位置
  7864. * @method focus
  7865. * @param { Boolean } toEnd 默认focus到编辑器头部,toEnd为true时focus到内容尾部
  7866. * @example
  7867. * ```javascript
  7868. * editor.focus(true)
  7869. * ```
  7870. */
  7871. focus: function (toEnd) {
  7872. try {
  7873. var me = this,
  7874. rng = me.selection.getRange();
  7875. if (toEnd) {
  7876. var node = me.body.lastChild;
  7877. if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
  7878. if (domUtils.isEmptyBlock(node)) {
  7879. rng.setStartAtFirst(node);
  7880. } else {
  7881. rng.setStartAtLast(node);
  7882. }
  7883. rng.collapse(true);
  7884. }
  7885. rng.setCursor(true);
  7886. } else {
  7887. if (
  7888. !rng.collapsed &&
  7889. domUtils.isBody(rng.startContainer) &&
  7890. rng.startOffset == 0
  7891. ) {
  7892. var node = me.body.firstChild;
  7893. if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
  7894. rng.setStartAtFirst(node).collapse(true);
  7895. }
  7896. }
  7897. rng.select(true);
  7898. }
  7899. this.fireEvent("focus selectionchange");
  7900. } catch (e) {
  7901. }
  7902. },
  7903. isFocus: function () {
  7904. return this.selection.isFocus();
  7905. },
  7906. blur: function () {
  7907. var sel = this.selection.getNative();
  7908. if (sel.empty && browser.ie) {
  7909. var nativeRng = document.body.createTextRange();
  7910. nativeRng.moveToElementText(document.body);
  7911. nativeRng.collapse(true);
  7912. nativeRng.select();
  7913. sel.empty();
  7914. } else {
  7915. sel.removeAllRanges();
  7916. }
  7917. //this.fireEvent('blur selectionchange');
  7918. },
  7919. /**
  7920. * 初始化UE事件及部分事件代理
  7921. * @method _initEvents
  7922. * @private
  7923. */
  7924. _initEvents: function () {
  7925. var me = this,
  7926. doc = me.document,
  7927. win = me.window;
  7928. me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
  7929. domUtils.on(
  7930. doc,
  7931. [
  7932. "click",
  7933. "contextmenu",
  7934. "mousedown",
  7935. "keydown",
  7936. "keyup",
  7937. "keypress",
  7938. "mouseup",
  7939. "mouseover",
  7940. "mouseout",
  7941. "selectstart"
  7942. ],
  7943. me._proxyDomEvent
  7944. );
  7945. domUtils.on(win, ["focus", "blur"], me._proxyDomEvent);
  7946. domUtils.on(me.body, "drop", function (e) {
  7947. //阻止ff下默认的弹出新页面打开图片
  7948. if (browser.gecko && e.stopPropagation) {
  7949. e.stopPropagation();
  7950. }
  7951. me.fireEvent("contentchange");
  7952. });
  7953. domUtils.on(doc, ["mouseup", "keydown"], function (evt) {
  7954. //特殊键不触发selectionchange
  7955. if (
  7956. evt.type == "keydown" &&
  7957. (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)
  7958. ) {
  7959. return;
  7960. }
  7961. if (evt.button == 2) return;
  7962. me._selectionChange(250, evt);
  7963. });
  7964. },
  7965. /**
  7966. * 触发事件代理
  7967. * @method _proxyDomEvent
  7968. * @private
  7969. * @return { * } fireEvent的返回值
  7970. * @see UE.EventBase:fireEvent(String)
  7971. */
  7972. _proxyDomEvent: function (evt) {
  7973. if (
  7974. this.fireEvent("before" + evt.type.replace(/^on/, "").toLowerCase()) ===
  7975. false
  7976. ) {
  7977. return false;
  7978. }
  7979. if (this.fireEvent(evt.type.replace(/^on/, ""), evt) === false) {
  7980. return false;
  7981. }
  7982. return this.fireEvent(
  7983. "after" + evt.type.replace(/^on/, "").toLowerCase()
  7984. );
  7985. },
  7986. /**
  7987. * 变化选区
  7988. * @method _selectionChange
  7989. * @private
  7990. */
  7991. _selectionChange: function (delay, evt) {
  7992. var me = this;
  7993. //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
  7994. // if ( !me.selection.isFocus() ){
  7995. // return;
  7996. // }
  7997. var hackForMouseUp = false;
  7998. var mouseX, mouseY;
  7999. if (browser.ie && browser.version < 9 && evt && evt.type == "mouseup") {
  8000. var range = this.selection.getRange();
  8001. if (!range.collapsed) {
  8002. hackForMouseUp = true;
  8003. mouseX = evt.clientX;
  8004. mouseY = evt.clientY;
  8005. }
  8006. }
  8007. clearTimeout(_selectionChangeTimer);
  8008. _selectionChangeTimer = setTimeout(function () {
  8009. if (!me.selection || !me.selection.getNative()) {
  8010. return;
  8011. }
  8012. //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
  8013. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
  8014. var ieRange;
  8015. if (hackForMouseUp && me.selection.getNative().type == "None") {
  8016. ieRange = me.document.body.createTextRange();
  8017. try {
  8018. ieRange.moveToPoint(mouseX, mouseY);
  8019. } catch (ex) {
  8020. ieRange = null;
  8021. }
  8022. }
  8023. var bakGetIERange;
  8024. if (ieRange) {
  8025. bakGetIERange = me.selection.getIERange;
  8026. me.selection.getIERange = function () {
  8027. return ieRange;
  8028. };
  8029. }
  8030. me.selection.cache();
  8031. if (bakGetIERange) {
  8032. me.selection.getIERange = bakGetIERange;
  8033. }
  8034. if (me.selection._cachedRange && me.selection._cachedStartElement) {
  8035. me.fireEvent("beforeselectionchange");
  8036. // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
  8037. me.fireEvent("selectionchange", !!evt);
  8038. me.fireEvent("afterselectionchange");
  8039. me.selection.clear();
  8040. }
  8041. }, delay || 50);
  8042. },
  8043. /**
  8044. * 执行编辑命令
  8045. * @method _callCmdFn
  8046. * @private
  8047. * @param { String } fnName 函数名称
  8048. * @param { * } args 传给命令函数的参数
  8049. * @return { * } 返回命令函数运行的返回值
  8050. */
  8051. _callCmdFn: function (fnName, args) {
  8052. var cmdName = args[0].toLowerCase(),
  8053. cmd,
  8054. cmdFn;
  8055. cmd = this.commands[cmdName] || UE.commands[cmdName];
  8056. cmdFn = cmd && cmd[fnName];
  8057. //没有querycommandstate或者没有command的都默认返回0
  8058. if ((!cmd || !cmdFn) && fnName == "queryCommandState") {
  8059. return 0;
  8060. } else if (cmdFn) {
  8061. return cmdFn.apply(this, args);
  8062. }
  8063. },
  8064. /**
  8065. * 执行编辑命令cmdName,完成富文本编辑效果
  8066. * @method execCommand
  8067. * @param { String } cmdName 需要执行的命令
  8068. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8069. * @return { * } 返回命令函数运行的返回值
  8070. * @example
  8071. * ```javascript
  8072. * editor.execCommand(cmdName);
  8073. * ```
  8074. */
  8075. execCommand: function (cmdName) {
  8076. cmdName = cmdName.toLowerCase();
  8077. var me = this;
  8078. var result;
  8079. var cmd = me.commands[cmdName] || UE.commands[cmdName];
  8080. if (!cmd || !cmd.execCommand) {
  8081. return null;
  8082. }
  8083. if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
  8084. me.__hasEnterExecCommand = true;
  8085. if (me.queryCommandState.apply(me, arguments) != -1) {
  8086. me.fireEvent("saveScene");
  8087. me.fireEvent.apply(
  8088. me,
  8089. ["beforeexeccommand", cmdName].concat(arguments)
  8090. );
  8091. result = this._callCmdFn("execCommand", arguments);
  8092. //保存场景时,做了内容对比,再看是否进行contentchange触发,这里多触发了一次,去掉
  8093. // (!cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange');
  8094. me.fireEvent.apply(
  8095. me,
  8096. ["afterexeccommand", cmdName].concat(arguments)
  8097. );
  8098. me.fireEvent("saveScene");
  8099. }
  8100. me.__hasEnterExecCommand = false;
  8101. } else {
  8102. result = this._callCmdFn("execCommand", arguments);
  8103. !me.__hasEnterExecCommand &&
  8104. !cmd.ignoreContentChange &&
  8105. !me._ignoreContentChange &&
  8106. me.fireEvent("contentchange");
  8107. }
  8108. !me.__hasEnterExecCommand &&
  8109. !cmd.ignoreContentChange &&
  8110. !me._ignoreContentChange &&
  8111. me._selectionChange();
  8112. return result;
  8113. },
  8114. /**
  8115. * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
  8116. * @method queryCommandState
  8117. * @param { String } cmdName 需要查询的命令名称
  8118. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8119. * @return { Number } number 返回放前命令的状态,返回值三种情况:(-1|0|1)
  8120. * @example
  8121. * ```javascript
  8122. * editor.queryCommandState(cmdName) => (-1|0|1)
  8123. * ```
  8124. * @see COMMAND.LIST
  8125. */
  8126. queryCommandState: function (cmdName) {
  8127. return this._callCmdFn("queryCommandState", arguments);
  8128. },
  8129. /**
  8130. * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
  8131. * @method queryCommandValue
  8132. * @param { String } cmdName 需要查询的命令名称
  8133. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8134. * @remind 只有部分插件有此方法
  8135. * @return { * } 返回每个命令特定的当前状态值
  8136. * @grammar editor.queryCommandValue(cmdName) => {*}
  8137. * @see COMMAND.LIST
  8138. */
  8139. queryCommandValue: function (cmdName) {
  8140. return this._callCmdFn("queryCommandValue", arguments);
  8141. },
  8142. /**
  8143. * 检查编辑区域中是否有内容
  8144. * @method hasContents
  8145. * @remind 默认有文本内容,或者有以下节点都不认为是空
  8146. * table,ul,ol,dl,iframe,area,base,col,hr,img,embed,input,link,meta,param
  8147. * @return { Boolean } 检查有内容返回true,否则返回false
  8148. * @example
  8149. * ```javascript
  8150. * editor.hasContents()
  8151. * ```
  8152. */
  8153. /**
  8154. * 检查编辑区域中是否有内容,若包含参数tags中的节点类型,直接返回true
  8155. * @method hasContents
  8156. * @param { Array } tags 传入数组判断时用到的节点类型
  8157. * @return { Boolean } 若文档中包含tags数组里对应的tag,返回true,否则返回false
  8158. * @example
  8159. * ```javascript
  8160. * editor.hasContents(['span']);
  8161. * ```
  8162. */
  8163. hasContents: function (tags) {
  8164. if (tags) {
  8165. for (var i = 0, ci; (ci = tags[i++]);) {
  8166. if (this.document.getElementsByTagName(ci).length > 0) {
  8167. return true;
  8168. }
  8169. }
  8170. }
  8171. if (!domUtils.isEmptyBlock(this.body)) {
  8172. return true;
  8173. }
  8174. //随时添加,定义的特殊标签如果存在,不能认为是空
  8175. tags = ["div"];
  8176. for (i = 0; (ci = tags[i++]);) {
  8177. var nodes = domUtils.getElementsByTagName(this.document, ci);
  8178. for (var n = 0, cn; (cn = nodes[n++]);) {
  8179. if (domUtils.isCustomeNode(cn)) {
  8180. return true;
  8181. }
  8182. }
  8183. }
  8184. return false;
  8185. },
  8186. /**
  8187. * 重置编辑器,可用来做多个tab使用同一个编辑器实例
  8188. * @method reset
  8189. * @remind 此方法会清空编辑器内容,清空回退列表,会触发reset事件
  8190. * @example
  8191. * ```javascript
  8192. * editor.reset()
  8193. * ```
  8194. */
  8195. reset: function () {
  8196. this.fireEvent("reset");
  8197. },
  8198. /**
  8199. * 设置当前编辑区域可以编辑
  8200. * @method setEnabled
  8201. * @example
  8202. * ```javascript
  8203. * editor.setEnabled()
  8204. * ```
  8205. */
  8206. setEnabled: function () {
  8207. var me = this,
  8208. range;
  8209. if (me.body.contentEditable == "false") {
  8210. me.body.contentEditable = true;
  8211. range = me.selection.getRange();
  8212. //有可能内容丢失了
  8213. try {
  8214. range.moveToBookmark(me.lastBk);
  8215. delete me.lastBk;
  8216. } catch (e) {
  8217. range.setStartAtFirst(me.body).collapse(true);
  8218. }
  8219. range.select(true);
  8220. if (me.bkqueryCommandState) {
  8221. me.queryCommandState = me.bkqueryCommandState;
  8222. delete me.bkqueryCommandState;
  8223. }
  8224. if (me.bkqueryCommandValue) {
  8225. me.queryCommandValue = me.bkqueryCommandValue;
  8226. delete me.bkqueryCommandValue;
  8227. }
  8228. me.fireEvent("selectionchange");
  8229. }
  8230. },
  8231. enable: function () {
  8232. return this.setEnabled();
  8233. },
  8234. /** 设置当前编辑区域不可编辑
  8235. * @method setDisabled
  8236. */
  8237. /** 设置当前编辑区域不可编辑,except中的命令除外
  8238. * @method setDisabled
  8239. * @param { String } except 例外命令的字符串
  8240. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  8241. * @example
  8242. * ```javascript
  8243. * editor.setDisabled('bold'); //禁用工具栏中除加粗之外的所有功能
  8244. * ```
  8245. */
  8246. /** 设置当前编辑区域不可编辑,except中的命令除外
  8247. * @method setDisabled
  8248. * @param { Array } except 例外命令的字符串数组,数组中的命令仍然可以执行
  8249. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  8250. * @example
  8251. * ```javascript
  8252. * editor.setDisabled(['bold','insertimage']); //禁用工具栏中除加粗和插入图片之外的所有功能
  8253. * ```
  8254. */
  8255. setDisabled: function (except) {
  8256. var me = this;
  8257. except = except ? (utils.isArray(except) ? except : [except]) : [];
  8258. if (me.body.contentEditable == "true") {
  8259. if (!me.lastBk) {
  8260. me.lastBk = me.selection.getRange().createBookmark(true);
  8261. }
  8262. me.body.contentEditable = false;
  8263. me.bkqueryCommandState = me.queryCommandState;
  8264. me.bkqueryCommandValue = me.queryCommandValue;
  8265. me.queryCommandState = function (type) {
  8266. if (utils.indexOf(except, type) != -1) {
  8267. return me.bkqueryCommandState.apply(me, arguments);
  8268. }
  8269. return -1;
  8270. };
  8271. me.queryCommandValue = function (type) {
  8272. if (utils.indexOf(except, type) != -1) {
  8273. return me.bkqueryCommandValue.apply(me, arguments);
  8274. }
  8275. return null;
  8276. };
  8277. me.fireEvent("selectionchange");
  8278. }
  8279. },
  8280. disable: function (except) {
  8281. return this.setDisabled(except);
  8282. },
  8283. /**
  8284. * 设置默认内容
  8285. * @method _setDefaultContent
  8286. * @private
  8287. * @param { String } cont 要存入的内容
  8288. */
  8289. _setDefaultContent: (function () {
  8290. function clear() {
  8291. var me = this;
  8292. if (me.document.getElementById("initContent")) {
  8293. me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
  8294. me.removeListener("firstBeforeExecCommand focus", clear);
  8295. setTimeout(function () {
  8296. me.focus();
  8297. me._selectionChange();
  8298. }, 0);
  8299. }
  8300. }
  8301. return function (cont) {
  8302. var me = this;
  8303. me.body.innerHTML = '<p id="initContent">' + cont + "</p>";
  8304. me.addListener("firstBeforeExecCommand focus", clear);
  8305. };
  8306. })(),
  8307. /**
  8308. * 显示编辑器
  8309. * @method setShow
  8310. * @example
  8311. * ```javascript
  8312. * editor.setShow()
  8313. * ```
  8314. */
  8315. setShow: function () {
  8316. var me = this,
  8317. range = me.selection.getRange();
  8318. if (me.container.style.display == "none") {
  8319. //有可能内容丢失了
  8320. try {
  8321. range.moveToBookmark(me.lastBk);
  8322. delete me.lastBk;
  8323. } catch (e) {
  8324. range.setStartAtFirst(me.body).collapse(true);
  8325. }
  8326. //ie下focus实效,所以做了个延迟
  8327. setTimeout(function () {
  8328. range.select(true);
  8329. }, 100);
  8330. me.container.style.display = "";
  8331. }
  8332. },
  8333. show: function () {
  8334. return this.setShow();
  8335. },
  8336. /**
  8337. * 隐藏编辑器
  8338. * @method setHide
  8339. * @example
  8340. * ```javascript
  8341. * editor.setHide()
  8342. * ```
  8343. */
  8344. setHide: function () {
  8345. var me = this;
  8346. if (!me.lastBk) {
  8347. me.lastBk = me.selection.getRange().createBookmark(true);
  8348. }
  8349. me.container.style.display = "none";
  8350. },
  8351. hide: function () {
  8352. return this.setHide();
  8353. },
  8354. /**
  8355. * 根据指定的路径,获取对应的语言资源
  8356. * @method getLang
  8357. * @param { String } path 路径根据的是lang目录下的语言文件的路径结构
  8358. * @return { Object | String } 根据路径返回语言资源的Json格式对象或者语言字符串
  8359. * @example
  8360. * ```javascript
  8361. * editor.getLang('contextMenu.delete'); //如果当前是中文,那返回是的是'删除'
  8362. * ```
  8363. */
  8364. getLang: function (path) {
  8365. var lang = UE.I18N[this.options.lang];
  8366. if (!lang) {
  8367. throw Error("not import language file");
  8368. }
  8369. path = (path || "").split(".");
  8370. for (var i = 0, ci; (ci = path[i++]);) {
  8371. lang = lang[ci];
  8372. if (!lang) break;
  8373. }
  8374. return lang;
  8375. },
  8376. /**
  8377. * 计算编辑器html内容字符串的长度
  8378. * @method getContentLength
  8379. * @return { Number } 返回计算的长度
  8380. * @example
  8381. * ```javascript
  8382. * //编辑器html内容<p><strong>132</strong></p>
  8383. * editor.getContentLength() //返回27
  8384. * ```
  8385. */
  8386. /**
  8387. * 计算编辑器当前纯文本内容的长度
  8388. * @method getContentLength
  8389. * @param { Boolean } ingoneHtml 传入true时,只按照纯文本来计算
  8390. * @return { Number } 返回计算的长度,内容中有hr/img/iframe标签,长度加1
  8391. * @example
  8392. * ```javascript
  8393. * //编辑器html内容<p><strong>132</strong></p>
  8394. * editor.getContentLength() //返回3
  8395. * ```
  8396. */
  8397. getContentLength: function (ingoneHtml, tagNames) {
  8398. var count = this.getContent(false, false, true).length;
  8399. if (ingoneHtml) {
  8400. tagNames = (tagNames || []).concat(["hr", "img", "iframe"]);
  8401. count = this.getContentTxt().replace(/[\t\r\n]+/g, "").length;
  8402. for (var i = 0, ci; (ci = tagNames[i++]);) {
  8403. count += this.document.getElementsByTagName(ci).length;
  8404. }
  8405. }
  8406. return count;
  8407. },
  8408. /**
  8409. * 注册输入过滤规则
  8410. * @method addInputRule
  8411. * @param { Function } rule 要添加的过滤规则
  8412. * @example
  8413. * ```javascript
  8414. * editor.addInputRule(function(root){
  8415. * $.each(root.getNodesByTagName('div'),function(i,node){
  8416. * node.tagName="p";
  8417. * });
  8418. * });
  8419. * ```
  8420. */
  8421. addInputRule: function (rule) {
  8422. this.inputRules.push(rule);
  8423. },
  8424. /**
  8425. * 执行注册的过滤规则
  8426. * @method filterInputRule
  8427. * @param { UE.uNode } root 要过滤的uNode节点
  8428. * @remind 执行editor.setContent方法和执行'inserthtml'命令后,会运行该过滤函数
  8429. * @example
  8430. * ```javascript
  8431. * editor.filterInputRule(editor.body);
  8432. * ```
  8433. * @see UE.Editor:addInputRule
  8434. */
  8435. filterInputRule: function (root) {
  8436. for (var i = 0, ci; (ci = this.inputRules[i++]);) {
  8437. ci.call(this, root);
  8438. }
  8439. },
  8440. /**
  8441. * 注册输出过滤规则
  8442. * @method addOutputRule
  8443. * @param { Function } rule 要添加的过滤规则
  8444. * @example
  8445. * ```javascript
  8446. * editor.addOutputRule(function(root){
  8447. * $.each(root.getNodesByTagName('p'),function(i,node){
  8448. * node.tagName="div";
  8449. * });
  8450. * });
  8451. * ```
  8452. */
  8453. addOutputRule: function (rule) {
  8454. this.outputRules.push(rule);
  8455. },
  8456. /**
  8457. * 根据输出过滤规则,过滤编辑器内容
  8458. * @method filterOutputRule
  8459. * @remind 执行editor.getContent方法的时候,会先运行该过滤函数
  8460. * @param { UE.uNode } root 要过滤的uNode节点
  8461. * @example
  8462. * ```javascript
  8463. * editor.filterOutputRule(editor.body);
  8464. * ```
  8465. * @see UE.Editor:addOutputRule
  8466. */
  8467. filterOutputRule: function (root) {
  8468. for (var i = 0, ci; (ci = this.outputRules[i++]);) {
  8469. ci.call(this, root);
  8470. }
  8471. },
  8472. /**
  8473. * 根据action名称获取请求的路径
  8474. * @method getActionUrl
  8475. * @remind 假如没有设置serverUrl,会根据imageUrl设置默认的controller路径
  8476. * @param { String } action action名称
  8477. * @example
  8478. * ```javascript
  8479. * editor.getActionUrl('config'); //返回 "/ueditor/php/controller.php?action=config"
  8480. * editor.getActionUrl('image'); //返回 "/ueditor/php/controller.php?action=uplaodimage"
  8481. * editor.getActionUrl('scrawl'); //返回 "/ueditor/php/controller.php?action=uplaodscrawl"
  8482. * editor.getActionUrl('imageManager'); //返回 "/ueditor/php/controller.php?action=listimage"
  8483. * ```
  8484. */
  8485. getActionUrl: function (action) {
  8486. var actionName = this.getOpt(action) || action,
  8487. imageUrl = this.getOpt("imageUrl"),
  8488. serverUrl = this.getOpt("serverUrl");
  8489. if (!serverUrl && imageUrl) {
  8490. serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, "$1controller$2");
  8491. }
  8492. if (serverUrl) {
  8493. serverUrl =
  8494. serverUrl +
  8495. (serverUrl.indexOf("?") == -1 ? "?" : "&") +
  8496. "action=" +
  8497. (actionName || "");
  8498. return utils.formatUrl(serverUrl);
  8499. } else {
  8500. return "";
  8501. }
  8502. }
  8503. };
  8504. utils.inherits(Editor, EventBase);
  8505. })();
  8506. // core/Editor.defaultoptions.js
  8507. //维护编辑器一下默认的不在插件中的配置项
  8508. UE.Editor.defaultOptions = function (editor) {
  8509. var _url = editor.options.UEDITOR_HOME_URL;
  8510. return {
  8511. isShow: true,
  8512. initialContent: "",
  8513. initialStyle: "",
  8514. autoClearinitialContent: false,
  8515. iframeCssUrl: _url + "themes/iframe.css",
  8516. textarea: "editorValue",
  8517. focus: false,
  8518. focusInEnd: true,
  8519. autoClearEmptyNode: true,
  8520. fullscreen: false,
  8521. readonly: false,
  8522. zIndex: 999,
  8523. imagePopup: true,
  8524. enterTag: "p",
  8525. customDomain: false,
  8526. lang: "zh-cn",
  8527. langPath: _url + "i18n/",
  8528. theme: "default",
  8529. themePath: _url + "themes/",
  8530. allHtmlEnabled: false,
  8531. scaleEnabled: false,
  8532. tableNativeEditInFF: false,
  8533. autoSyncData: true,
  8534. fileNameFormat: "{time}{rand:6}"
  8535. };
  8536. };
  8537. // core/loadconfig.js
  8538. ;(function () {
  8539. UE.Editor.prototype.loadServerConfig = function () {
  8540. var me = this;
  8541. setTimeout(function () {
  8542. try {
  8543. me.options.imageUrl &&
  8544. me.setOpt(
  8545. "serverUrl",
  8546. me.options.imageUrl.replace(
  8547. /^(.*[\/]).+([\.].+)$/,
  8548. "$1controller$2"
  8549. )
  8550. );
  8551. var configUrl = me.getActionUrl("config"),
  8552. isJsonp = utils.isCrossDomainUrl(configUrl);
  8553. /* 发出ajax请求 */
  8554. me._serverConfigLoaded = false;
  8555. configUrl &&
  8556. UE.ajax.request(configUrl, {
  8557. method: "GET",
  8558. dataType: isJsonp ? "jsonp" : "",
  8559. onsuccess: function (r) {
  8560. try {
  8561. var config = isJsonp ? r : eval("(" + r.responseText + ")");
  8562. utils.extend(me.options, config);
  8563. me.fireEvent("serverConfigLoaded");
  8564. me._serverConfigLoaded = true;
  8565. } catch (e) {
  8566. showErrorMsg(me.getLang("loadconfigFormatError"));
  8567. }
  8568. },
  8569. onerror: function () {
  8570. showErrorMsg(me.getLang("loadconfigHttpError"));
  8571. }
  8572. });
  8573. } catch (e) {
  8574. showErrorMsg(me.getLang("loadconfigError"));
  8575. }
  8576. });
  8577. function showErrorMsg(msg) {
  8578. console && console.error(msg);
  8579. //me.fireEvent('showMessage', {
  8580. // 'title': msg,
  8581. // 'type': 'error'
  8582. //});
  8583. }
  8584. };
  8585. UE.Editor.prototype.isServerConfigLoaded = function () {
  8586. var me = this;
  8587. return me._serverConfigLoaded || false;
  8588. };
  8589. UE.Editor.prototype.afterConfigReady = function (handler) {
  8590. if (!handler || !utils.isFunction(handler)) return;
  8591. var me = this;
  8592. var readyHandler = function () {
  8593. handler.apply(me, arguments);
  8594. me.removeListener("serverConfigLoaded", readyHandler);
  8595. };
  8596. if (me.isServerConfigLoaded()) {
  8597. handler.call(me, "serverConfigLoaded");
  8598. } else {
  8599. me.addListener("serverConfigLoaded", readyHandler);
  8600. }
  8601. };
  8602. })();
  8603. // core/ajax.js
  8604. /**
  8605. * @file
  8606. * @module UE.ajax
  8607. * @since 1.2.6.1
  8608. */
  8609. /**
  8610. * 提供对ajax请求的支持
  8611. * @module UE.ajax
  8612. */
  8613. UE.ajax = (function () {
  8614. //创建一个ajaxRequest对象
  8615. var fnStr = "XMLHttpRequest()";
  8616. try {
  8617. new ActiveXObject("Msxml2.XMLHTTP");
  8618. fnStr = "ActiveXObject('Msxml2.XMLHTTP')";
  8619. } catch (e) {
  8620. try {
  8621. new ActiveXObject("Microsoft.XMLHTTP");
  8622. fnStr = "ActiveXObject('Microsoft.XMLHTTP')";
  8623. } catch (e) {
  8624. }
  8625. }
  8626. var creatAjaxRequest = new Function("return new " + fnStr);
  8627. /**
  8628. * 将json参数转化成适合ajax提交的参数列表
  8629. * @param json
  8630. */
  8631. function json2str(json) {
  8632. var strArr = [];
  8633. for (var i in json) {
  8634. //忽略默认的几个参数
  8635. if (
  8636. i == "method" ||
  8637. i == "timeout" ||
  8638. i == "async" ||
  8639. i == "dataType" ||
  8640. i == "callback"
  8641. )
  8642. continue;
  8643. //忽略控制
  8644. if (json[i] == undefined || json[i] == null) continue;
  8645. //传递过来的对象和函数不在提交之列
  8646. if (
  8647. !(
  8648. (typeof json[i]).toLowerCase() == "function" ||
  8649. (typeof json[i]).toLowerCase() == "object"
  8650. )
  8651. ) {
  8652. strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]));
  8653. } else if (utils.isArray(json[i])) {
  8654. //支持传数组内容
  8655. for (var j = 0; j < json[i].length; j++) {
  8656. strArr.push(
  8657. encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])
  8658. );
  8659. }
  8660. }
  8661. }
  8662. return strArr.join("&");
  8663. }
  8664. function doAjax(url, ajaxOptions) {
  8665. var xhr = creatAjaxRequest(),
  8666. //是否超时
  8667. timeIsOut = false,
  8668. //默认参数
  8669. defaultAjaxOptions = {
  8670. method: "POST",
  8671. timeout: 5000,
  8672. async: true,
  8673. data: {}, //需要传递对象的话只能覆盖
  8674. onsuccess: function () {
  8675. },
  8676. onerror: function () {
  8677. }
  8678. };
  8679. if (typeof url === "object") {
  8680. ajaxOptions = url;
  8681. url = ajaxOptions.url;
  8682. }
  8683. if (!xhr || !url) return;
  8684. var ajaxOpts = ajaxOptions
  8685. ? utils.extend(defaultAjaxOptions, ajaxOptions)
  8686. : defaultAjaxOptions;
  8687. var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  8688. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  8689. if (!utils.isEmptyObject(ajaxOpts.data)) {
  8690. submitStr += (submitStr ? "&" : "") + json2str(ajaxOpts.data);
  8691. }
  8692. //超时检测
  8693. var timerID = setTimeout(function () {
  8694. if (xhr.readyState != 4) {
  8695. timeIsOut = true;
  8696. xhr.abort();
  8697. clearTimeout(timerID);
  8698. }
  8699. }, ajaxOpts.timeout);
  8700. var method = ajaxOpts.method.toUpperCase();
  8701. var str =
  8702. url +
  8703. (url.indexOf("?") == -1 ? "?" : "&") +
  8704. (method == "POST" ? "" : submitStr + "&noCache=" + +new Date());
  8705. xhr.open(method, str, ajaxOpts.async);
  8706. xhr.onreadystatechange = function () {
  8707. if (xhr.readyState == 4) {
  8708. if (!timeIsOut && xhr.status == 200) {
  8709. ajaxOpts.onsuccess(xhr);
  8710. } else {
  8711. ajaxOpts.onerror(xhr);
  8712. }
  8713. }
  8714. };
  8715. if (method == "POST") {
  8716. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  8717. xhr.send(submitStr);
  8718. } else {
  8719. xhr.send(null);
  8720. }
  8721. }
  8722. function doJsonp(url, opts) {
  8723. var successhandler = opts.onsuccess || function () {
  8724. },
  8725. scr = document.createElement("SCRIPT"),
  8726. options = opts || {},
  8727. charset = options["charset"],
  8728. callbackField = options["jsonp"] || "callback",
  8729. callbackFnName,
  8730. timeOut = options["timeOut"] || 0,
  8731. timer,
  8732. reg = new RegExp("(\\?|&)" + callbackField + "=([^&]*)"),
  8733. matches;
  8734. if (utils.isFunction(successhandler)) {
  8735. callbackFnName =
  8736. "bd__editor__" + Math.floor(Math.random() * 2147483648).toString(36);
  8737. window[callbackFnName] = getCallBack(0);
  8738. } else if (utils.isString(successhandler)) {
  8739. callbackFnName = successhandler;
  8740. } else {
  8741. if ((matches = reg.exec(url))) {
  8742. callbackFnName = matches[2];
  8743. }
  8744. }
  8745. url = url.replace(reg, "\x241" + callbackField + "=" + callbackFnName);
  8746. if (url.search(reg) < 0) {
  8747. url +=
  8748. (url.indexOf("?") < 0 ? "?" : "&") +
  8749. callbackField +
  8750. "=" +
  8751. callbackFnName;
  8752. }
  8753. var queryStr = json2str(opts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  8754. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  8755. if (!utils.isEmptyObject(opts.data)) {
  8756. queryStr += (queryStr ? "&" : "") + json2str(opts.data);
  8757. }
  8758. if (queryStr) {
  8759. url = url.replace(/\?/, "?" + queryStr + "&");
  8760. }
  8761. scr.onerror = getCallBack(1);
  8762. if (timeOut) {
  8763. timer = setTimeout(getCallBack(1), timeOut);
  8764. }
  8765. createScriptTag(scr, url, charset);
  8766. function createScriptTag(scr, url, charset) {
  8767. scr.setAttribute("type", "text/javascript");
  8768. scr.setAttribute("defer", "defer");
  8769. charset && scr.setAttribute("charset", charset);
  8770. scr.setAttribute("src", url);
  8771. document.getElementsByTagName("head")[0].appendChild(scr);
  8772. }
  8773. function getCallBack(onTimeOut) {
  8774. return function () {
  8775. try {
  8776. if (onTimeOut) {
  8777. options.onerror && options.onerror();
  8778. } else {
  8779. try {
  8780. clearTimeout(timer);
  8781. successhandler.apply(window, arguments);
  8782. } catch (e) {
  8783. }
  8784. }
  8785. } catch (exception) {
  8786. options.onerror && options.onerror.call(window, exception);
  8787. } finally {
  8788. options.oncomplete && options.oncomplete.apply(window, arguments);
  8789. scr.parentNode && scr.parentNode.removeChild(scr);
  8790. window[callbackFnName] = null;
  8791. try {
  8792. delete window[callbackFnName];
  8793. } catch (e) {
  8794. }
  8795. }
  8796. };
  8797. }
  8798. }
  8799. return {
  8800. /**
  8801. * 根据给定的参数项,向指定的url发起一个ajax请求。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  8802. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调
  8803. * @method request
  8804. * @param { URLString } url ajax请求的url地址
  8805. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  8806. * @example
  8807. * ```javascript
  8808. * //向sayhello.php发起一个异步的Ajax GET请求, 请求超时时间为10s, 请求完成后执行相应的回调。
  8809. * UE.ajax.requeset( 'sayhello.php', {
  8810. *
  8811. * //请求方法。可选值: 'GET', 'POST',默认值是'POST'
  8812. * method: 'GET',
  8813. *
  8814. * //超时时间。 默认为5000, 单位是ms
  8815. * timeout: 10000,
  8816. *
  8817. * //是否是异步请求。 true为异步请求, false为同步请求
  8818. * async: true,
  8819. *
  8820. * //请求携带的数据。如果请求为GET请求, data会经过stringify后附加到请求url之后。
  8821. * data: {
  8822. * name: 'neditor'
  8823. * },
  8824. *
  8825. * //请求成功后的回调, 该回调接受当前的XMLHttpRequest对象作为参数。
  8826. * onsuccess: function ( xhr ) {
  8827. * console.log( xhr.responseText );
  8828. * },
  8829. *
  8830. * //请求失败或者超时后的回调。
  8831. * onerror: function ( xhr ) {
  8832. * alert( 'Ajax请求失败' );
  8833. * }
  8834. *
  8835. * } );
  8836. * ```
  8837. */
  8838. /**
  8839. * 根据给定的参数项发起一个ajax请求, 参数项里必须包含一个url地址。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  8840. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调。
  8841. * @method request
  8842. * @warning 如果在参数项里未提供一个key为“url”的地址值,则该请求将直接退出。
  8843. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  8844. * @example
  8845. * ```javascript
  8846. *
  8847. * //向sayhello.php发起一个异步的Ajax POST请求, 请求超时时间为5s, 请求完成后不执行任何回调。
  8848. * UE.ajax.requeset( 'sayhello.php', {
  8849. *
  8850. * //请求的地址, 该项是必须的。
  8851. * url: 'sayhello.php'
  8852. *
  8853. * } );
  8854. * ```
  8855. */
  8856. request: function (url, opts) {
  8857. if (opts && opts.dataType == "jsonp") {
  8858. doJsonp(url, opts);
  8859. } else {
  8860. doAjax(url, opts);
  8861. }
  8862. },
  8863. getJSONP: function (url, data, fn) {
  8864. var opts = {
  8865. data: data,
  8866. oncomplete: fn
  8867. };
  8868. doJsonp(url, opts);
  8869. }
  8870. };
  8871. })();
  8872. // core/filterword.js
  8873. /**
  8874. * UE过滤word的静态方法
  8875. * @file
  8876. */
  8877. /**
  8878. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  8879. * @module UE
  8880. */
  8881. /**
  8882. * 根据传入html字符串过滤word
  8883. * @module UE
  8884. * @since 1.2.6.1
  8885. * @method filterWord
  8886. * @param { String } html html字符串
  8887. * @return { String } 已过滤后的结果字符串
  8888. * @example
  8889. * ```javascript
  8890. * UE.filterWord(html);
  8891. * ```
  8892. */
  8893. var filterWord = (UE.filterWord = (function () {
  8894. //是否是word过来的内容
  8895. function isWordDocument(str) {
  8896. return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/gi.test(
  8897. str
  8898. );
  8899. }
  8900. //去掉小数
  8901. function transUnit(v) {
  8902. v = v.replace(/[\d.]+\w+/g, function (m) {
  8903. return utils.transUnitToPx(m);
  8904. });
  8905. return v;
  8906. }
  8907. function filterPasteWord(str) {
  8908. return (
  8909. str
  8910. .replace(/[\t\r\n]+/g, " ")
  8911. .replace(/<!--[\s\S]*?-->/gi, "")
  8912. //转换图片
  8913. .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi, function (str) {
  8914. //opera能自己解析出image所这里直接返回空
  8915. if (browser.opera) {
  8916. return "";
  8917. }
  8918. try {
  8919. //有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中
  8920. if (/Bitmap/i.test(str)) {
  8921. return "";
  8922. }
  8923. var width = str.match(/width:([ \d.]*p[tx])/i)[1],
  8924. height = str.match(/height:([ \d.]*p[tx])/i)[1],
  8925. src = str.match(/src=\s*"([^"]*)"/i)[1];
  8926. return (
  8927. '<img width="' +
  8928. transUnit(width) +
  8929. '" height="' +
  8930. transUnit(height) +
  8931. '" src="' +
  8932. src +
  8933. '" />'
  8934. );
  8935. } catch (e) {
  8936. return "";
  8937. }
  8938. })
  8939. //针对wps添加的多余标签处理
  8940. .replace(/<\/?div[^>]*>/g, "")
  8941. //去掉多余的属性
  8942. .replace(/v:\w+=(["']?)[^'"]+\1/g, "")
  8943. .replace(
  8944. /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi,
  8945. ""
  8946. )
  8947. .replace(
  8948. /<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi,
  8949. "<p><strong>$1</strong></p>"
  8950. )
  8951. //去掉多余的属性
  8952. .replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi, function (
  8953. str,
  8954. name,
  8955. marks,
  8956. val
  8957. ) {
  8958. //保留list的标示
  8959. return name == "class" && val == "MsoListParagraph" ? str : "";
  8960. })
  8961. //清除多余的font/span不能匹配&nbsp;有可能是空格
  8962. .replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function (a, b, c) {
  8963. return c.replace(/[\t\r\n ]+/g, " ");
  8964. })
  8965. //处理style的问题
  8966. .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (
  8967. str,
  8968. tag,
  8969. tmp,
  8970. style
  8971. ) {
  8972. var n = [],
  8973. s = style
  8974. .replace(/^\s+|\s+$/, "")
  8975. .replace(/&#39;/g, "'")
  8976. .replace(/&quot;/gi, "'")
  8977. .replace(/[\d.]+(cm|pt)/g, function (str) {
  8978. return utils.transUnitToPx(str);
  8979. })
  8980. .split(/;\s*/g);
  8981. for (var i = 0, v; (v = s[i]); i++) {
  8982. var name,
  8983. value,
  8984. parts = v.split(":");
  8985. if (parts.length == 2) {
  8986. name = parts[0].toLowerCase();
  8987. value = parts[1].toLowerCase();
  8988. if (
  8989. (/^(background)\w*/.test(name) &&
  8990. value.replace(/(initial|\s)/g, "").length == 0) ||
  8991. (/^(margin)\w*/.test(name) && /^0\w+$/.test(value))
  8992. ) {
  8993. continue;
  8994. }
  8995. switch (name) {
  8996. case "mso-padding-alt":
  8997. case "mso-padding-top-alt":
  8998. case "mso-padding-right-alt":
  8999. case "mso-padding-bottom-alt":
  9000. case "mso-padding-left-alt":
  9001. case "mso-margin-alt":
  9002. case "mso-margin-top-alt":
  9003. case "mso-margin-right-alt":
  9004. case "mso-margin-bottom-alt":
  9005. case "mso-margin-left-alt":
  9006. //ie下会出现挤到一起的情况
  9007. //case "mso-table-layout-alt":
  9008. case "mso-height":
  9009. case "mso-width":
  9010. case "mso-vertical-align-alt":
  9011. //trace:1819 ff下会解析出padding在table上
  9012. if (!/<table/.test(tag))
  9013. n[i] =
  9014. name.replace(/^mso-|-alt$/g, "") + ":" + transUnit(value);
  9015. continue;
  9016. case "horiz-align":
  9017. n[i] = "text-align:" + value;
  9018. continue;
  9019. case "vert-align":
  9020. n[i] = "vertical-align:" + value;
  9021. continue;
  9022. case "font-color":
  9023. case "mso-foreground":
  9024. n[i] = "color:" + value;
  9025. continue;
  9026. case "mso-background":
  9027. case "mso-highlight":
  9028. n[i] = "background:" + value;
  9029. continue;
  9030. case "mso-default-height":
  9031. n[i] = "min-height:" + transUnit(value);
  9032. continue;
  9033. case "mso-default-width":
  9034. n[i] = "min-width:" + transUnit(value);
  9035. continue;
  9036. case "mso-padding-between-alt":
  9037. n[i] =
  9038. "border-collapse:separate;border-spacing:" +
  9039. transUnit(value);
  9040. continue;
  9041. case "text-line-through":
  9042. if (value == "single" || value == "double") {
  9043. n[i] = "text-decoration:line-through";
  9044. }
  9045. continue;
  9046. case "mso-zero-height":
  9047. if (value == "yes") {
  9048. n[i] = "display:none";
  9049. }
  9050. continue;
  9051. // case 'background':
  9052. // break;
  9053. case "margin":
  9054. if (!/[1-9]/.test(value)) {
  9055. continue;
  9056. }
  9057. }
  9058. if (
  9059. /^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?:decor|trans)|top-bar|version|vnd|word-break)/.test(
  9060. name
  9061. ) ||
  9062. (/text\-indent|padding|margin/.test(name) &&
  9063. /\-[\d.]+/.test(value))
  9064. ) {
  9065. continue;
  9066. }
  9067. n[i] = name + ":" + parts[1];
  9068. }
  9069. }
  9070. return (
  9071. tag +
  9072. (n.length
  9073. ? ' style="' + n.join(";").replace(/;{2,}/g, ";") + '"'
  9074. : "")
  9075. );
  9076. })
  9077. );
  9078. }
  9079. return function (html) {
  9080. return isWordDocument(html) ? filterPasteWord(html) : html;
  9081. };
  9082. })());
  9083. // core/node.js
  9084. /**
  9085. * 编辑器模拟的节点类
  9086. * @file
  9087. * @module UE
  9088. * @class uNode
  9089. * @since 1.2.6.1
  9090. */
  9091. /**
  9092. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9093. * @unfile
  9094. * @module UE
  9095. */
  9096. ;(function () {
  9097. /**
  9098. * 编辑器模拟的节点类
  9099. * @unfile
  9100. * @module UE
  9101. * @class uNode
  9102. */
  9103. /**
  9104. * 通过一个键值对,创建一个uNode对象
  9105. * @constructor
  9106. * @param { Object } attr 传入要创建的uNode的初始属性
  9107. * @example
  9108. * ```javascript
  9109. * var node = new uNode({
  9110. * type:'element',
  9111. * tagName:'span',
  9112. * attrs:{style:'font-size:14px;'}
  9113. * })
  9114. * ```
  9115. */
  9116. var uNode = (UE.uNode = function (obj) {
  9117. this.type = obj.type;
  9118. this.data = obj.data;
  9119. this.tagName = obj.tagName;
  9120. this.parentNode = obj.parentNode;
  9121. this.attrs = obj.attrs || {};
  9122. this.children = obj.children;
  9123. });
  9124. var notTransAttrs = {
  9125. href: 1,
  9126. src: 1,
  9127. _src: 1,
  9128. _href: 1,
  9129. cdata_data: 1
  9130. };
  9131. var notTransTagName = {
  9132. style: 1,
  9133. script: 1
  9134. };
  9135. var indentChar = " ",
  9136. breakChar = "\n";
  9137. function insertLine(arr, current, begin) {
  9138. arr.push(breakChar);
  9139. return current + (begin ? 1 : -1);
  9140. }
  9141. function insertIndent(arr, current) {
  9142. //插入缩进
  9143. for (var i = 0; i < current; i++) {
  9144. arr.push(indentChar);
  9145. }
  9146. }
  9147. //创建uNode的静态方法
  9148. //支持标签和html
  9149. uNode.createElement = function (html) {
  9150. if (/[<>]/.test(html)) {
  9151. return UE.htmlparser(html).children[0];
  9152. } else {
  9153. return new uNode({
  9154. type: "element",
  9155. children: [],
  9156. tagName: html
  9157. });
  9158. }
  9159. };
  9160. uNode.createText = function (data, noTrans) {
  9161. return new UE.uNode({
  9162. type: "text",
  9163. data: noTrans ? data : utils.unhtml(data || "")
  9164. });
  9165. };
  9166. function nodeToHtml(node, arr, formatter, current) {
  9167. switch (node.type) {
  9168. case "root":
  9169. for (var i = 0, ci; (ci = node.children[i++]);) {
  9170. //插入新行
  9171. if (
  9172. formatter &&
  9173. ci.type == "element" &&
  9174. !dtd.$inlineWithA[ci.tagName] &&
  9175. i > 1
  9176. ) {
  9177. insertLine(arr, current, true);
  9178. insertIndent(arr, current);
  9179. }
  9180. nodeToHtml(ci, arr, formatter, current);
  9181. }
  9182. break;
  9183. case "text":
  9184. isText(node, arr);
  9185. break;
  9186. case "element":
  9187. isElement(node, arr, formatter, current);
  9188. break;
  9189. case "comment":
  9190. isComment(node, arr, formatter);
  9191. }
  9192. return arr;
  9193. }
  9194. function isText(node, arr) {
  9195. if (node.parentNode.tagName == "pre") {
  9196. //源码模式下输入html标签,不能做转换处理,直接输出
  9197. arr.push(node.data);
  9198. } else {
  9199. arr.push(
  9200. notTransTagName[node.parentNode.tagName]
  9201. ? utils.html(node.data)
  9202. : node.data.replace(/[ ]{2}/g, " &nbsp;")
  9203. );
  9204. }
  9205. }
  9206. function isElement(node, arr, formatter, current) {
  9207. var attrhtml = "";
  9208. if (node.attrs) {
  9209. attrhtml = [];
  9210. var attrs = node.attrs;
  9211. for (var a in attrs) {
  9212. //这里就针对
  9213. //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
  9214. //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
  9215. //有可能做的不够
  9216. attrhtml.push(
  9217. a +
  9218. (attrs[a] !== undefined
  9219. ? '="' +
  9220. (notTransAttrs[a]
  9221. ? utils.html(attrs[a]).replace(/["]/g, function (a) {
  9222. return "&quot;";
  9223. })
  9224. : utils.unhtml(attrs[a])) +
  9225. '"'
  9226. : "")
  9227. );
  9228. }
  9229. attrhtml = attrhtml.join(" ");
  9230. }
  9231. arr.push(
  9232. "<" +
  9233. node.tagName +
  9234. (attrhtml ? " " + attrhtml : "") +
  9235. (dtd.$empty[node.tagName] ? "/" : "") +
  9236. ">"
  9237. );
  9238. //插入新行
  9239. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != "pre") {
  9240. if (node.children && node.children.length) {
  9241. current = insertLine(arr, current, true);
  9242. insertIndent(arr, current);
  9243. }
  9244. }
  9245. if (node.children && node.children.length) {
  9246. for (var i = 0, ci; (ci = node.children[i++]);) {
  9247. if (
  9248. formatter &&
  9249. ci.type == "element" &&
  9250. !dtd.$inlineWithA[ci.tagName] &&
  9251. i > 1
  9252. ) {
  9253. insertLine(arr, current);
  9254. insertIndent(arr, current);
  9255. }
  9256. nodeToHtml(ci, arr, formatter, current);
  9257. }
  9258. }
  9259. if (!dtd.$empty[node.tagName]) {
  9260. if (
  9261. formatter &&
  9262. !dtd.$inlineWithA[node.tagName] &&
  9263. node.tagName != "pre"
  9264. ) {
  9265. if (node.children && node.children.length) {
  9266. current = insertLine(arr, current);
  9267. insertIndent(arr, current);
  9268. }
  9269. }
  9270. arr.push("</" + node.tagName + ">");
  9271. }
  9272. }
  9273. function isComment(node, arr) {
  9274. arr.push("<!--" + node.data + "-->");
  9275. }
  9276. function getNodeById(root, id) {
  9277. var node;
  9278. if (root.type == "element" && root.getAttr("id") == id) {
  9279. return root;
  9280. }
  9281. if (root.children && root.children.length) {
  9282. for (var i = 0, ci; (ci = root.children[i++]);) {
  9283. if ((node = getNodeById(ci, id))) {
  9284. return node;
  9285. }
  9286. }
  9287. }
  9288. }
  9289. function getNodesByTagName(node, tagName, arr) {
  9290. if (node.type == "element" && node.tagName == tagName) {
  9291. arr.push(node);
  9292. }
  9293. if (node.children && node.children.length) {
  9294. for (var i = 0, ci; (ci = node.children[i++]);) {
  9295. getNodesByTagName(ci, tagName, arr);
  9296. }
  9297. }
  9298. }
  9299. function nodeTraversal(root, fn) {
  9300. if (root.children && root.children.length) {
  9301. for (var i = 0, ci; (ci = root.children[i]);) {
  9302. nodeTraversal(ci, fn);
  9303. //ci被替换的情况,这里就不再走 fn了
  9304. if (ci.parentNode) {
  9305. if (ci.children && ci.children.length) {
  9306. fn(ci);
  9307. }
  9308. if (ci.parentNode) i++;
  9309. }
  9310. }
  9311. } else {
  9312. fn(root);
  9313. }
  9314. }
  9315. uNode.prototype = {
  9316. /**
  9317. * 当前节点对象,转换成html文本
  9318. * @method toHtml
  9319. * @return { String } 返回转换后的html字符串
  9320. * @example
  9321. * ```javascript
  9322. * node.toHtml();
  9323. * ```
  9324. */
  9325. /**
  9326. * 当前节点对象,转换成html文本
  9327. * @method toHtml
  9328. * @param { Boolean } formatter 是否格式化返回值
  9329. * @return { String } 返回转换后的html字符串
  9330. * @example
  9331. * ```javascript
  9332. * node.toHtml( true );
  9333. * ```
  9334. */
  9335. toHtml: function (formatter) {
  9336. var arr = [];
  9337. nodeToHtml(this, arr, formatter, 0);
  9338. return arr.join("");
  9339. },
  9340. /**
  9341. * 获取节点的html内容
  9342. * @method innerHTML
  9343. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9344. * @return { String } 返回节点的html内容
  9345. * @example
  9346. * ```javascript
  9347. * var htmlstr = node.innerHTML();
  9348. * ```
  9349. */
  9350. /**
  9351. * 设置节点的html内容
  9352. * @method innerHTML
  9353. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9354. * @param { String } htmlstr 传入要设置的html内容
  9355. * @return { UE.uNode } 返回节点本身
  9356. * @example
  9357. * ```javascript
  9358. * node.innerHTML('<span>text</span>');
  9359. * ```
  9360. */
  9361. innerHTML: function (htmlstr) {
  9362. if (this.type != "element" || dtd.$empty[this.tagName]) {
  9363. return this;
  9364. }
  9365. if (utils.isString(htmlstr)) {
  9366. if (this.children) {
  9367. for (var i = 0, ci; (ci = this.children[i++]);) {
  9368. ci.parentNode = null;
  9369. }
  9370. }
  9371. this.children = [];
  9372. var tmpRoot = UE.htmlparser(htmlstr);
  9373. for (var i = 0, ci; (ci = tmpRoot.children[i++]);) {
  9374. this.children.push(ci);
  9375. ci.parentNode = this;
  9376. }
  9377. return this;
  9378. } else {
  9379. var tmpRoot = new UE.uNode({
  9380. type: "root",
  9381. children: this.children
  9382. });
  9383. return tmpRoot.toHtml();
  9384. }
  9385. },
  9386. /**
  9387. * 获取节点的纯文本内容
  9388. * @method innerText
  9389. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9390. * @return { String } 返回节点的存文本内容
  9391. * @example
  9392. * ```javascript
  9393. * var textStr = node.innerText();
  9394. * ```
  9395. */
  9396. /**
  9397. * 设置节点的纯文本内容
  9398. * @method innerText
  9399. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9400. * @param { String } textStr 传入要设置的文本内容
  9401. * @return { UE.uNode } 返回节点本身
  9402. * @example
  9403. * ```javascript
  9404. * node.innerText('<span>text</span>');
  9405. * ```
  9406. */
  9407. innerText: function (textStr, noTrans) {
  9408. if (this.type != "element" || dtd.$empty[this.tagName]) {
  9409. return this;
  9410. }
  9411. if (textStr) {
  9412. if (this.children) {
  9413. for (var i = 0, ci; (ci = this.children[i++]);) {
  9414. ci.parentNode = null;
  9415. }
  9416. }
  9417. this.children = [];
  9418. this.appendChild(uNode.createText(textStr, noTrans));
  9419. return this;
  9420. } else {
  9421. return this.toHtml().replace(/<[^>]+>/g, "");
  9422. }
  9423. },
  9424. /**
  9425. * 获取当前对象的data属性
  9426. * @method getData
  9427. * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
  9428. * @example
  9429. * ```javascript
  9430. * node.getData();
  9431. * ```
  9432. */
  9433. getData: function () {
  9434. if (this.type == "element") return "";
  9435. return this.data;
  9436. },
  9437. /**
  9438. * 获取当前节点下的第一个子节点
  9439. * @method firstChild
  9440. * @return { UE.uNode } 返回第一个子节点
  9441. * @example
  9442. * ```javascript
  9443. * node.firstChild(); //返回第一个子节点
  9444. * ```
  9445. */
  9446. firstChild: function () {
  9447. // if (this.type != 'element' || dtd.$empty[this.tagName]) {
  9448. // return this;
  9449. // }
  9450. return this.children ? this.children[0] : null;
  9451. },
  9452. /**
  9453. * 获取当前节点下的最后一个子节点
  9454. * @method lastChild
  9455. * @return { UE.uNode } 返回最后一个子节点
  9456. * @example
  9457. * ```javascript
  9458. * node.lastChild(); //返回最后一个子节点
  9459. * ```
  9460. */
  9461. lastChild: function () {
  9462. // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
  9463. // return this;
  9464. // }
  9465. return this.children ? this.children[this.children.length - 1] : null;
  9466. },
  9467. /**
  9468. * 获取和当前节点有相同父亲节点的前一个节点
  9469. * @method previousSibling
  9470. * @return { UE.uNode } 返回前一个节点
  9471. * @example
  9472. * ```javascript
  9473. * node.children[2].previousSibling(); //返回子节点node.children[1]
  9474. * ```
  9475. */
  9476. previousSibling: function () {
  9477. var parent = this.parentNode;
  9478. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  9479. if (ci === this) {
  9480. return i == 0 ? null : parent.children[i - 1];
  9481. }
  9482. }
  9483. },
  9484. /**
  9485. * 获取和当前节点有相同父亲节点的后一个节点
  9486. * @method nextSibling
  9487. * @return { UE.uNode } 返回后一个节点,找不到返回null
  9488. * @example
  9489. * ```javascript
  9490. * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
  9491. * ```
  9492. */
  9493. nextSibling: function () {
  9494. var parent = this.parentNode;
  9495. for (var i = 0, ci; (ci = parent.children[i++]);) {
  9496. if (ci === this) {
  9497. return parent.children[i];
  9498. }
  9499. }
  9500. },
  9501. /**
  9502. * 用新的节点替换当前节点
  9503. * @method replaceChild
  9504. * @param { UE.uNode } target 要替换成该节点参数
  9505. * @param { UE.uNode } source 要被替换掉的节点
  9506. * @return { UE.uNode } 返回替换之后的节点对象
  9507. * @example
  9508. * ```javascript
  9509. * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
  9510. * ```
  9511. */
  9512. replaceChild: function (target, source) {
  9513. if (this.children) {
  9514. if (target.parentNode) {
  9515. target.parentNode.removeChild(target);
  9516. }
  9517. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9518. if (ci === source) {
  9519. this.children.splice(i, 1, target);
  9520. source.parentNode = null;
  9521. target.parentNode = this;
  9522. return target;
  9523. }
  9524. }
  9525. }
  9526. },
  9527. /**
  9528. * 在节点的子节点列表最后位置插入一个节点
  9529. * @method appendChild
  9530. * @param { UE.uNode } node 要插入的节点
  9531. * @return { UE.uNode } 返回刚插入的子节点
  9532. * @example
  9533. * ```javascript
  9534. * node.appendChild( newNode ); //在node内插入子节点newNode
  9535. * ```
  9536. */
  9537. appendChild: function (node) {
  9538. if (
  9539. this.type == "root" ||
  9540. (this.type == "element" && !dtd.$empty[this.tagName])
  9541. ) {
  9542. if (!this.children) {
  9543. this.children = [];
  9544. }
  9545. if (node.parentNode) {
  9546. node.parentNode.removeChild(node);
  9547. }
  9548. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9549. if (ci === node) {
  9550. this.children.splice(i, 1);
  9551. break;
  9552. }
  9553. }
  9554. this.children.push(node);
  9555. node.parentNode = this;
  9556. return node;
  9557. }
  9558. },
  9559. /**
  9560. * 在传入节点的前面插入一个节点
  9561. * @method insertBefore
  9562. * @param { UE.uNode } target 要插入的节点
  9563. * @param { UE.uNode } source 在该参数节点前面插入
  9564. * @return { UE.uNode } 返回刚插入的子节点
  9565. * @example
  9566. * ```javascript
  9567. * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
  9568. * ```
  9569. */
  9570. insertBefore: function (target, source) {
  9571. if (this.children) {
  9572. if (target.parentNode) {
  9573. target.parentNode.removeChild(target);
  9574. }
  9575. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9576. if (ci === source) {
  9577. this.children.splice(i, 0, target);
  9578. target.parentNode = this;
  9579. return target;
  9580. }
  9581. }
  9582. }
  9583. },
  9584. /**
  9585. * 在传入节点的后面插入一个节点
  9586. * @method insertAfter
  9587. * @param { UE.uNode } target 要插入的节点
  9588. * @param { UE.uNode } source 在该参数节点后面插入
  9589. * @return { UE.uNode } 返回刚插入的子节点
  9590. * @example
  9591. * ```javascript
  9592. * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
  9593. * ```
  9594. */
  9595. insertAfter: function (target, source) {
  9596. if (this.children) {
  9597. if (target.parentNode) {
  9598. target.parentNode.removeChild(target);
  9599. }
  9600. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9601. if (ci === source) {
  9602. this.children.splice(i + 1, 0, target);
  9603. target.parentNode = this;
  9604. return target;
  9605. }
  9606. }
  9607. }
  9608. },
  9609. /**
  9610. * 从当前节点的子节点列表中,移除节点
  9611. * @method removeChild
  9612. * @param { UE.uNode } node 要移除的节点引用
  9613. * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
  9614. * @return { * } 返回刚移除的子节点
  9615. * @example
  9616. * ```javascript
  9617. * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
  9618. * ```
  9619. */
  9620. removeChild: function (node, keepChildren) {
  9621. if (this.children) {
  9622. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9623. if (ci === node) {
  9624. this.children.splice(i, 1);
  9625. ci.parentNode = null;
  9626. if (keepChildren && ci.children && ci.children.length) {
  9627. for (var j = 0, cj; (cj = ci.children[j]); j++) {
  9628. this.children.splice(i + j, 0, cj);
  9629. cj.parentNode = this;
  9630. }
  9631. }
  9632. return ci;
  9633. }
  9634. }
  9635. }
  9636. },
  9637. /**
  9638. * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
  9639. * @method getAttr
  9640. * @param { String } attrName 要获取的属性名称
  9641. * @return { * } 返回attrs对象下的属性值
  9642. * @example
  9643. * ```javascript
  9644. * node.getAttr('title');
  9645. * ```
  9646. */
  9647. getAttr: function (attrName) {
  9648. return this.attrs && this.attrs[attrName.toLowerCase()];
  9649. },
  9650. /**
  9651. * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
  9652. * @method setAttr
  9653. * @param { String } attrName 要设置的属性名称
  9654. * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
  9655. * @return { * } 返回attrs对象下的属性值
  9656. * @example
  9657. * ```javascript
  9658. * node.setAttr('title','标题');
  9659. * ```
  9660. */
  9661. setAttr: function (attrName, attrVal) {
  9662. if (!attrName) {
  9663. delete this.attrs;
  9664. return;
  9665. }
  9666. if (!this.attrs) {
  9667. this.attrs = {};
  9668. }
  9669. if (utils.isObject(attrName)) {
  9670. for (var a in attrName) {
  9671. if (!attrName[a]) {
  9672. delete this.attrs[a];
  9673. } else {
  9674. this.attrs[a.toLowerCase()] = attrName[a];
  9675. }
  9676. }
  9677. } else {
  9678. if (!attrVal) {
  9679. delete this.attrs[attrName];
  9680. } else {
  9681. this.attrs[attrName.toLowerCase()] = attrVal;
  9682. }
  9683. }
  9684. },
  9685. /**
  9686. * 获取当前节点在父节点下的位置索引
  9687. * @method getIndex
  9688. * @return { Number } 返回索引数值,如果没有父节点,返回-1
  9689. * @example
  9690. * ```javascript
  9691. * node.getIndex();
  9692. * ```
  9693. */
  9694. getIndex: function () {
  9695. var parent = this.parentNode;
  9696. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  9697. if (ci === this) {
  9698. return i;
  9699. }
  9700. }
  9701. return -1;
  9702. },
  9703. /**
  9704. * 在当前节点下,根据id查找节点
  9705. * @method getNodeById
  9706. * @param { String } id 要查找的id
  9707. * @return { UE.uNode } 返回找到的节点
  9708. * @example
  9709. * ```javascript
  9710. * node.getNodeById('textId');
  9711. * ```
  9712. */
  9713. getNodeById: function (id) {
  9714. var node;
  9715. if (this.children && this.children.length) {
  9716. for (var i = 0, ci; (ci = this.children[i++]);) {
  9717. if ((node = getNodeById(ci, id))) {
  9718. return node;
  9719. }
  9720. }
  9721. }
  9722. },
  9723. /**
  9724. * 在当前节点下,根据元素名称查找节点列表
  9725. * @method getNodesByTagName
  9726. * @param { String } tagNames 要查找的元素名称
  9727. * @return { Array } 返回找到的节点列表
  9728. * @example
  9729. * ```javascript
  9730. * node.getNodesByTagName('span');
  9731. * ```
  9732. */
  9733. getNodesByTagName: function (tagNames) {
  9734. tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, " ").split(" ");
  9735. var arr = [],
  9736. me = this;
  9737. utils.each(tagNames, function (tagName) {
  9738. if (me.children && me.children.length) {
  9739. for (var i = 0, ci; (ci = me.children[i++]);) {
  9740. getNodesByTagName(ci, tagName, arr);
  9741. }
  9742. }
  9743. });
  9744. return arr;
  9745. },
  9746. /**
  9747. * 根据样式名称,获取节点的样式值
  9748. * @method getStyle
  9749. * @param { String } name 要获取的样式名称
  9750. * @return { String } 返回样式值
  9751. * @example
  9752. * ```javascript
  9753. * node.getStyle('font-size');
  9754. * ```
  9755. */
  9756. getStyle: function (name) {
  9757. var cssStyle = this.getAttr("style");
  9758. if (!cssStyle) {
  9759. return "";
  9760. }
  9761. var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+)", "i");
  9762. var match = cssStyle.match(reg);
  9763. if (match && match[0]) {
  9764. return match[2];
  9765. }
  9766. return "";
  9767. },
  9768. /**
  9769. * 给节点设置样式
  9770. * @method setStyle
  9771. * @param { String } name 要设置的的样式名称
  9772. * @param { String } val 要设置的的样值
  9773. * @example
  9774. * ```javascript
  9775. * node.setStyle('font-size', '12px');
  9776. * ```
  9777. */
  9778. setStyle: function (name, val) {
  9779. function exec(name, val) {
  9780. var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+;?)", "gi");
  9781. cssStyle = cssStyle.replace(reg, "$1");
  9782. if (val) {
  9783. cssStyle = name + ":" + utils.unhtml(val) + ";" + cssStyle;
  9784. }
  9785. }
  9786. var cssStyle = this.getAttr("style");
  9787. if (!cssStyle) {
  9788. cssStyle = "";
  9789. }
  9790. if (utils.isObject(name)) {
  9791. for (var a in name) {
  9792. exec(a, name[a]);
  9793. }
  9794. } else {
  9795. exec(name, val);
  9796. }
  9797. this.setAttr("style", utils.trim(cssStyle));
  9798. },
  9799. /**
  9800. * 传入一个函数,递归遍历当前节点下的所有节点
  9801. * @method traversal
  9802. * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
  9803. * @example
  9804. * ```javascript
  9805. * traversal(node, function(){
  9806. * console.log(node.type);
  9807. * });
  9808. * ```
  9809. */
  9810. traversal: function (fn) {
  9811. if (this.children && this.children.length) {
  9812. nodeTraversal(this, fn);
  9813. }
  9814. return this;
  9815. }
  9816. };
  9817. })();
  9818. // core/htmlparser.js
  9819. /**
  9820. * html字符串转换成uNode节点
  9821. * @file
  9822. * @module UE
  9823. * @since 1.2.6.1
  9824. */
  9825. /**
  9826. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9827. * @unfile
  9828. * @module UE
  9829. */
  9830. /**
  9831. * html字符串转换成uNode节点的静态方法
  9832. * @method htmlparser
  9833. * @param { String } htmlstr 要转换的html代码
  9834. * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
  9835. * @return { uNode } 给定的html片段转换形成的uNode对象
  9836. * @example
  9837. * ```javascript
  9838. * var root = UE.htmlparser('<p><b>htmlparser</b></p>', true);
  9839. * ```
  9840. */
  9841. var htmlparser = (UE.htmlparser = function (htmlstr, ignoreBlank) {
  9842. //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 <TD vAlign=top background=../AAA.JPG> 这样的标签了
  9843. //先去掉了,加上的原因忘了,这里先记录
  9844. //var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  9845. //以上的正则表达式无法匹配:<div style="text-align:center;font-family:" font-size:14px;"=""><img src="http://hs-album.oss.aliyuncs.com/static/27/78/35/image/20161206/20161206174331_41105.gif" alt="" /><br /></div>
  9846. //修改为如下正则表达式:
  9847. var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g,
  9848. re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
  9849. //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
  9850. var allowEmptyTags = {
  9851. b: 1,
  9852. code: 1,
  9853. i: 1,
  9854. u: 1,
  9855. strike: 1,
  9856. s: 1,
  9857. tt: 1,
  9858. strong: 1,
  9859. q: 1,
  9860. samp: 1,
  9861. em: 1,
  9862. span: 1,
  9863. sub: 1,
  9864. img: 1,
  9865. sup: 1,
  9866. font: 1,
  9867. big: 1,
  9868. small: 1,
  9869. iframe: 1,
  9870. a: 1,
  9871. br: 1,
  9872. pre: 1
  9873. };
  9874. htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, "g"), "");
  9875. if (!ignoreBlank) {
  9876. htmlstr = htmlstr.replace(
  9877. new RegExp(
  9878. "[\\r\\t\\n" +
  9879. (ignoreBlank ? "" : " ") +
  9880. "]*</?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n" +
  9881. (ignoreBlank ? "" : " ") +
  9882. "]*",
  9883. "g"
  9884. ),
  9885. function (a, b) {
  9886. //br暂时单独处理
  9887. if (b && allowEmptyTags[b.toLowerCase()]) {
  9888. return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, "");
  9889. }
  9890. return a
  9891. .replace(new RegExp("^[\\r\\n" + (ignoreBlank ? "" : " ") + "]+"), "")
  9892. .replace(
  9893. new RegExp("[\\r\\n" + (ignoreBlank ? "" : " ") + "]+$"),
  9894. ""
  9895. );
  9896. }
  9897. );
  9898. }
  9899. var notTransAttrs = {
  9900. href: 1,
  9901. src: 1
  9902. };
  9903. var uNode = UE.uNode,
  9904. needParentNode = {
  9905. td: "tr",
  9906. tr: ["tbody", "thead", "tfoot"],
  9907. tbody: "table",
  9908. th: "tr",
  9909. thead: "table",
  9910. tfoot: "table",
  9911. caption: "table",
  9912. li: ["ul", "ol"],
  9913. dt: "dl",
  9914. dd: "dl",
  9915. option: "select"
  9916. },
  9917. needChild = {
  9918. ol: "li",
  9919. ul: "li"
  9920. };
  9921. function text(parent, data) {
  9922. if (needChild[parent.tagName]) {
  9923. var tmpNode = uNode.createElement(needChild[parent.tagName]);
  9924. parent.appendChild(tmpNode);
  9925. tmpNode.appendChild(uNode.createText(data));
  9926. parent = tmpNode;
  9927. } else {
  9928. parent.appendChild(uNode.createText(data));
  9929. }
  9930. }
  9931. function element(parent, tagName, htmlattr) {
  9932. var needParentTag;
  9933. if ((needParentTag = needParentNode[tagName])) {
  9934. var tmpParent = parent,
  9935. hasParent;
  9936. while (tmpParent.type != "root") {
  9937. if (
  9938. utils.isArray(needParentTag)
  9939. ? utils.indexOf(needParentTag, tmpParent.tagName) != -1
  9940. : needParentTag == tmpParent.tagName
  9941. ) {
  9942. parent = tmpParent;
  9943. hasParent = true;
  9944. break;
  9945. }
  9946. tmpParent = tmpParent.parentNode;
  9947. }
  9948. if (!hasParent) {
  9949. parent = element(
  9950. parent,
  9951. utils.isArray(needParentTag) ? needParentTag[0] : needParentTag
  9952. );
  9953. }
  9954. }
  9955. //按dtd处理嵌套
  9956. // if(parent.type != 'root' && !dtd[parent.tagName][tagName])
  9957. // parent = parent.parentNode;
  9958. var elm = new uNode({
  9959. parentNode: parent,
  9960. type: "element",
  9961. tagName: tagName.toLowerCase(),
  9962. //是自闭合的处理一下
  9963. children: dtd.$empty[tagName] ? null : []
  9964. });
  9965. //如果属性存在,处理属性
  9966. if (htmlattr) {
  9967. var attrs = {},
  9968. match;
  9969. while ((match = re_attr.exec(htmlattr))) {
  9970. attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()]
  9971. ? match[2] || match[3] || match[4]
  9972. : utils.unhtml(match[2] || match[3] || match[4]);
  9973. }
  9974. elm.attrs = attrs;
  9975. }
  9976. //trace:3970
  9977. // //如果parent下不能放elm
  9978. // if(dtd.$inline[parent.tagName] && dtd.$block[elm.tagName] && !dtd[parent.tagName][elm.tagName]){
  9979. // parent = parent.parentNode;
  9980. // elm.parentNode = parent;
  9981. // }
  9982. parent.children.push(elm);
  9983. //如果是自闭合节点返回父亲节点
  9984. return dtd.$empty[tagName] ? parent : elm;
  9985. }
  9986. function comment(parent, data) {
  9987. parent.children.push(
  9988. new uNode({
  9989. type: "comment",
  9990. data: data,
  9991. parentNode: parent
  9992. })
  9993. );
  9994. }
  9995. var match,
  9996. currentIndex = 0,
  9997. nextIndex = 0;
  9998. //设置根节点
  9999. var root = new uNode({
  10000. type: "root",
  10001. children: []
  10002. });
  10003. var currentParent = root;
  10004. while ((match = re_tag.exec(htmlstr))) {
  10005. currentIndex = match.index;
  10006. try {
  10007. if (currentIndex > nextIndex) {
  10008. //text node
  10009. text(currentParent, htmlstr.slice(nextIndex, currentIndex));
  10010. }
  10011. if (match[3]) {
  10012. if (dtd.$cdata[currentParent.tagName]) {
  10013. text(currentParent, match[0]);
  10014. } else {
  10015. //start tag
  10016. currentParent = element(
  10017. currentParent,
  10018. match[3].toLowerCase(),
  10019. match[4]
  10020. );
  10021. }
  10022. } else if (match[1]) {
  10023. if (currentParent.type != "root") {
  10024. if (dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) {
  10025. text(currentParent, match[0]);
  10026. } else {
  10027. var tmpParent = currentParent;
  10028. while (
  10029. currentParent.type == "element" &&
  10030. currentParent.tagName != match[1].toLowerCase()
  10031. ) {
  10032. currentParent = currentParent.parentNode;
  10033. if (currentParent.type == "root") {
  10034. currentParent = tmpParent;
  10035. throw "break";
  10036. }
  10037. }
  10038. //end tag
  10039. currentParent = currentParent.parentNode;
  10040. }
  10041. }
  10042. } else if (match[2]) {
  10043. //comment
  10044. comment(currentParent, match[2]);
  10045. }
  10046. } catch (e) {
  10047. }
  10048. nextIndex = re_tag.lastIndex;
  10049. }
  10050. //如果结束是文本,就有可能丢掉,所以这里手动判断一下
  10051. //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
  10052. if (nextIndex < htmlstr.length) {
  10053. text(currentParent, htmlstr.slice(nextIndex));
  10054. }
  10055. return root;
  10056. });
  10057. // core/filternode.js
  10058. /**
  10059. * UE过滤节点的静态方法
  10060. * @file
  10061. */
  10062. /**
  10063. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  10064. * @module UE
  10065. */
  10066. /**
  10067. * 根据传入节点和过滤规则过滤相应节点
  10068. * @module UE
  10069. * @since 1.2.6.1
  10070. * @method filterNode
  10071. * @param { Object } root 指定root节点
  10072. * @param { Object } rules 过滤规则json对象
  10073. * @example
  10074. * ```javascript
  10075. * UE.filterNode(root,editor.options.filterRules);
  10076. * ```
  10077. */
  10078. var filterNode = (UE.filterNode = (function () {
  10079. function filterNode(node, rules) {
  10080. switch (node.type) {
  10081. case "text":
  10082. break;
  10083. case "element":
  10084. var val;
  10085. if ((val = rules[node.tagName])) {
  10086. if (val === "-") {
  10087. node.parentNode.removeChild(node);
  10088. } else if (utils.isFunction(val)) {
  10089. var parentNode = node.parentNode,
  10090. index = node.getIndex();
  10091. val(node);
  10092. if (node.parentNode) {
  10093. if (node.children) {
  10094. for (var i = 0, ci; (ci = node.children[i]);) {
  10095. filterNode(ci, rules);
  10096. if (ci.parentNode) {
  10097. i++;
  10098. }
  10099. }
  10100. }
  10101. } else {
  10102. for (var i = index, ci; (ci = parentNode.children[i]);) {
  10103. filterNode(ci, rules);
  10104. if (ci.parentNode) {
  10105. i++;
  10106. }
  10107. }
  10108. }
  10109. } else {
  10110. var attrs = val["$"];
  10111. if (attrs && node.attrs) {
  10112. var tmpAttrs = {},
  10113. tmpVal;
  10114. for (var a in attrs) {
  10115. tmpVal = node.getAttr(a);
  10116. //todo 只先对style单独处理
  10117. if (a == "style" && utils.isArray(attrs[a])) {
  10118. var tmpCssStyle = [];
  10119. utils.each(attrs[a], function (v) {
  10120. var tmp;
  10121. if ((tmp = node.getStyle(v))) {
  10122. tmpCssStyle.push(v + ":" + tmp);
  10123. }
  10124. });
  10125. tmpVal = tmpCssStyle.join(";");
  10126. }
  10127. if (tmpVal) {
  10128. tmpAttrs[a] = tmpVal;
  10129. }
  10130. }
  10131. node.attrs = tmpAttrs;
  10132. }
  10133. if (node.children) {
  10134. for (var i = 0, ci; (ci = node.children[i]);) {
  10135. filterNode(ci, rules);
  10136. if (ci.parentNode) {
  10137. i++;
  10138. }
  10139. }
  10140. }
  10141. }
  10142. } else {
  10143. //如果不在名单里扣出子节点并删除该节点,cdata除外
  10144. if (dtd.$cdata[node.tagName]) {
  10145. node.parentNode.removeChild(node);
  10146. } else {
  10147. var parentNode = node.parentNode,
  10148. index = node.getIndex();
  10149. node.parentNode.removeChild(node, true);
  10150. for (var i = index, ci; (ci = parentNode.children[i]);) {
  10151. filterNode(ci, rules);
  10152. if (ci.parentNode) {
  10153. i++;
  10154. }
  10155. }
  10156. }
  10157. }
  10158. break;
  10159. case "comment":
  10160. node.parentNode.removeChild(node);
  10161. }
  10162. }
  10163. return function (root, rules) {
  10164. if (utils.isEmptyObject(rules)) {
  10165. return root;
  10166. }
  10167. var val;
  10168. if ((val = rules["-"])) {
  10169. utils.each(val.split(" "), function (k) {
  10170. rules[k] = "-";
  10171. });
  10172. }
  10173. for (var i = 0, ci; (ci = root.children[i]);) {
  10174. filterNode(ci, rules);
  10175. if (ci.parentNode) {
  10176. i++;
  10177. }
  10178. }
  10179. return root;
  10180. };
  10181. })());
  10182. // core/plugin.js
  10183. /**
  10184. * Created with JetBrains PhpStorm.
  10185. * User: campaign
  10186. * Date: 10/8/13
  10187. * Time: 6:15 PM
  10188. * To change this template use File | Settings | File Templates.
  10189. */
  10190. UE.plugin = (function () {
  10191. var _plugins = {};
  10192. return {
  10193. register: function (pluginName, fn, oldOptionName, afterDisabled) {
  10194. if (oldOptionName && utils.isFunction(oldOptionName)) {
  10195. afterDisabled = oldOptionName;
  10196. oldOptionName = null;
  10197. }
  10198. _plugins[pluginName] = {
  10199. optionName: oldOptionName || pluginName,
  10200. execFn: fn,
  10201. //当插件被禁用时执行
  10202. afterDisabled: afterDisabled
  10203. };
  10204. },
  10205. load: function (editor) {
  10206. utils.each(_plugins, function (plugin) {
  10207. var _export = plugin.execFn.call(editor);
  10208. if (editor.options[plugin.optionName] !== false) {
  10209. if (_export) {
  10210. //后边需要再做扩展
  10211. utils.each(_export, function (v, k) {
  10212. switch (k.toLowerCase()) {
  10213. case "shortcutkey":
  10214. editor.addshortcutkey(v);
  10215. break;
  10216. case "bindevents":
  10217. utils.each(v, function (fn, eventName) {
  10218. editor.addListener(eventName, fn);
  10219. });
  10220. break;
  10221. case "bindmultievents":
  10222. utils.each(utils.isArray(v) ? v : [v], function (event) {
  10223. var types = utils.trim(event.type).split(/\s+/);
  10224. utils.each(types, function (eventName) {
  10225. editor.addListener(eventName, event.handler);
  10226. });
  10227. });
  10228. break;
  10229. case "commands":
  10230. utils.each(v, function (execFn, execName) {
  10231. editor.commands[execName] = execFn;
  10232. });
  10233. break;
  10234. case "outputrule":
  10235. editor.addOutputRule(v);
  10236. break;
  10237. case "inputrule":
  10238. editor.addInputRule(v);
  10239. break;
  10240. case "defaultoptions":
  10241. editor.setOpt(v);
  10242. }
  10243. });
  10244. }
  10245. } else if (plugin.afterDisabled) {
  10246. plugin.afterDisabled.call(editor);
  10247. }
  10248. });
  10249. //向下兼容
  10250. utils.each(UE.plugins, function (plugin) {
  10251. plugin.call(editor);
  10252. });
  10253. },
  10254. run: function (pluginName, editor) {
  10255. var plugin = _plugins[pluginName];
  10256. if (plugin) {
  10257. plugin.exeFn.call(editor);
  10258. }
  10259. }
  10260. };
  10261. })();
  10262. // core/keymap.js
  10263. var keymap = (UE.keymap = {
  10264. Backspace: 8,
  10265. Tab: 9,
  10266. Enter: 13,
  10267. Shift: 16,
  10268. Control: 17,
  10269. Alt: 18,
  10270. CapsLock: 20,
  10271. Esc: 27,
  10272. Spacebar: 32,
  10273. PageUp: 33,
  10274. PageDown: 34,
  10275. End: 35,
  10276. Home: 36,
  10277. Left: 37,
  10278. Up: 38,
  10279. Right: 39,
  10280. Down: 40,
  10281. Insert: 45,
  10282. Del: 46,
  10283. NumLock: 144,
  10284. Cmd: 91,
  10285. "=": 187,
  10286. "-": 189,
  10287. b: 66,
  10288. i: 73,
  10289. //回退
  10290. z: 90,
  10291. y: 89,
  10292. //粘贴
  10293. v: 86,
  10294. x: 88,
  10295. s: 83,
  10296. n: 78
  10297. });
  10298. // core/localstorage.js
  10299. //存储媒介封装
  10300. var LocalStorage = (UE.LocalStorage = (function () {
  10301. var storage = window.localStorage || getUserData() || null,
  10302. LOCAL_FILE = "localStorage";
  10303. return {
  10304. saveLocalData: function (key, data) {
  10305. if (storage && data) {
  10306. storage.setItem(key, data);
  10307. return true;
  10308. }
  10309. return false;
  10310. },
  10311. getLocalData: function (key) {
  10312. if (storage) {
  10313. return storage.getItem(key);
  10314. }
  10315. return null;
  10316. },
  10317. removeItem: function (key) {
  10318. storage && storage.removeItem(key);
  10319. }
  10320. };
  10321. function getUserData() {
  10322. var container = document.createElement("div");
  10323. container.style.display = "none";
  10324. if (!container.addBehavior) {
  10325. return null;
  10326. }
  10327. container.addBehavior("#default#userdata");
  10328. return {
  10329. getItem: function (key) {
  10330. var result = null;
  10331. try {
  10332. document.body.appendChild(container);
  10333. container.load(LOCAL_FILE);
  10334. result = container.getAttribute(key);
  10335. document.body.removeChild(container);
  10336. } catch (e) {
  10337. }
  10338. return result;
  10339. },
  10340. setItem: function (key, value) {
  10341. document.body.appendChild(container);
  10342. container.setAttribute(key, value);
  10343. container.save(LOCAL_FILE);
  10344. document.body.removeChild(container);
  10345. },
  10346. //// 暂时没有用到
  10347. //clear: function () {
  10348. //
  10349. // var expiresTime = new Date();
  10350. // expiresTime.setFullYear(expiresTime.getFullYear() - 1);
  10351. // document.body.appendChild(container);
  10352. // container.expires = expiresTime.toUTCString();
  10353. // container.save(LOCAL_FILE);
  10354. // document.body.removeChild(container);
  10355. //
  10356. //},
  10357. removeItem: function (key) {
  10358. document.body.appendChild(container);
  10359. container.removeAttribute(key);
  10360. container.save(LOCAL_FILE);
  10361. document.body.removeChild(container);
  10362. }
  10363. };
  10364. }
  10365. })());
  10366. ;(function () {
  10367. var ROOTKEY = "ueditor_preference";
  10368. UE.Editor.prototype.setPreferences = function (key, value) {
  10369. var obj = {};
  10370. if (utils.isString(key)) {
  10371. obj[key] = value;
  10372. } else {
  10373. obj = key;
  10374. }
  10375. var data = LocalStorage.getLocalData(ROOTKEY);
  10376. if (data && (data = utils.str2json(data))) {
  10377. utils.extend(data, obj);
  10378. } else {
  10379. data = obj;
  10380. }
  10381. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  10382. };
  10383. UE.Editor.prototype.getPreferences = function (key) {
  10384. var data = LocalStorage.getLocalData(ROOTKEY);
  10385. if (data && (data = utils.str2json(data))) {
  10386. return key ? data[key] : data;
  10387. }
  10388. return null;
  10389. };
  10390. UE.Editor.prototype.removePreferences = function (key) {
  10391. var data = LocalStorage.getLocalData(ROOTKEY);
  10392. if (data && (data = utils.str2json(data))) {
  10393. data[key] = undefined;
  10394. delete data[key];
  10395. }
  10396. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  10397. };
  10398. })();
  10399. // plugins/defaultfilter.js
  10400. ///import core
  10401. ///plugin 编辑器默认的过滤转换机制
  10402. UE.plugins["defaultfilter"] = function () {
  10403. var me = this;
  10404. me.setOpt({
  10405. allowDivTransToP: true,
  10406. disabledTableInTable: true,
  10407. rgb2Hex: true
  10408. });
  10409. //默认的过滤处理
  10410. //进入编辑器的内容处理
  10411. me.addInputRule(function (root) {
  10412. var allowDivTransToP = this.options.allowDivTransToP;
  10413. var val;
  10414. function tdParent(node) {
  10415. while (node && node.type == "element") {
  10416. if (node.tagName == "td") {
  10417. return true;
  10418. }
  10419. node = node.parentNode;
  10420. }
  10421. return false;
  10422. }
  10423. //进行默认的处理
  10424. root.traversal(function (node) {
  10425. if (node.type == "element") {
  10426. if (
  10427. !dtd.$cdata[node.tagName] &&
  10428. me.options.autoClearEmptyNode &&
  10429. dtd.$inline[node.tagName] &&
  10430. !dtd.$empty[node.tagName] &&
  10431. (!node.attrs || utils.isEmptyObject(node.attrs))
  10432. ) {
  10433. if (!node.firstChild()) node.parentNode.removeChild(node);
  10434. else if (
  10435. node.tagName == "span" &&
  10436. (!node.attrs || utils.isEmptyObject(node.attrs))
  10437. ) {
  10438. node.parentNode.removeChild(node, true);
  10439. }
  10440. return;
  10441. }
  10442. switch (node.tagName) {
  10443. case "style":
  10444. case "script":
  10445. node.setAttr({
  10446. cdata_tag: node.tagName,
  10447. cdata_data: node.innerHTML() || "",
  10448. _ue_custom_node_: "true"
  10449. });
  10450. node.tagName = "div";
  10451. node.innerHTML("");
  10452. break;
  10453. case "a":
  10454. if ((val = node.getAttr("href"))) {
  10455. node.setAttr("_href", val);
  10456. }
  10457. break;
  10458. case "img":
  10459. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  10460. if ((val = node.getAttr("src"))) {
  10461. if (/^data:/.test(val)) {
  10462. node.parentNode.removeChild(node);
  10463. break;
  10464. }
  10465. }
  10466. node.setAttr("_src", node.getAttr("src"));
  10467. break;
  10468. case "span":
  10469. if (browser.webkit && (val = node.getStyle("white-space"))) {
  10470. if (/nowrap|normal/.test(val)) {
  10471. node.setStyle("white-space", "");
  10472. if (
  10473. me.options.autoClearEmptyNode &&
  10474. utils.isEmptyObject(node.attrs)
  10475. ) {
  10476. node.parentNode.removeChild(node, true);
  10477. }
  10478. }
  10479. }
  10480. val = node.getAttr("id");
  10481. if (val && /^_baidu_bookmark_/i.test(val)) {
  10482. node.parentNode.removeChild(node);
  10483. }
  10484. break;
  10485. case "p":
  10486. if ((val = node.getAttr("align"))) {
  10487. node.setAttr("align");
  10488. node.setStyle("text-align", val);
  10489. }
  10490. //trace:3431
  10491. // var cssStyle = node.getAttr('style');
  10492. // if (cssStyle) {
  10493. // cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
  10494. // node.setAttr('style', cssStyle)
  10495. //
  10496. // }
  10497. //p标签不允许嵌套
  10498. utils.each(node.children, function (n) {
  10499. if (n.type == "element" && n.tagName == "p") {
  10500. var next = n.nextSibling();
  10501. node.parentNode.insertAfter(n, node);
  10502. var last = n;
  10503. while (next) {
  10504. var tmp = next.nextSibling();
  10505. node.parentNode.insertAfter(next, last);
  10506. last = next;
  10507. next = tmp;
  10508. }
  10509. return false;
  10510. }
  10511. });
  10512. if (!node.firstChild()) {
  10513. node.innerHTML(browser.ie ? "&nbsp;" : "<br/>");
  10514. }
  10515. break;
  10516. case "div":
  10517. if (node.getAttr("cdata_tag")) {
  10518. break;
  10519. }
  10520. //针对代码这里不处理插入代码的div
  10521. val = node.getAttr("class");
  10522. if (val && /^line number\d+/.test(val)) {
  10523. break;
  10524. }
  10525. if (!allowDivTransToP) {
  10526. break;
  10527. }
  10528. var tmpNode,
  10529. p = UE.uNode.createElement("p");
  10530. while ((tmpNode = node.firstChild())) {
  10531. if (
  10532. tmpNode.type == "text" ||
  10533. !UE.dom.dtd.$block[tmpNode.tagName]
  10534. ) {
  10535. p.appendChild(tmpNode);
  10536. } else {
  10537. if (p.firstChild()) {
  10538. node.parentNode.insertBefore(p, node);
  10539. p = UE.uNode.createElement("p");
  10540. } else {
  10541. node.parentNode.insertBefore(tmpNode, node);
  10542. }
  10543. }
  10544. }
  10545. if (p.firstChild()) {
  10546. node.parentNode.insertBefore(p, node);
  10547. }
  10548. node.parentNode.removeChild(node);
  10549. break;
  10550. case "dl":
  10551. node.tagName = "ul";
  10552. break;
  10553. case "dt":
  10554. case "dd":
  10555. node.tagName = "li";
  10556. break;
  10557. case "li":
  10558. var className = node.getAttr("class");
  10559. if (!className || !/list\-/.test(className)) {
  10560. node.setAttr();
  10561. }
  10562. var tmpNodes = node.getNodesByTagName("ol ul");
  10563. UE.utils.each(tmpNodes, function (n) {
  10564. node.parentNode.insertAfter(n, node);
  10565. });
  10566. break;
  10567. case "td":
  10568. case "th":
  10569. case "caption":
  10570. if (!node.children || !node.children.length) {
  10571. node.appendChild(
  10572. browser.ie11below
  10573. ? UE.uNode.createText(" ")
  10574. : UE.uNode.createElement("br")
  10575. );
  10576. }
  10577. break;
  10578. case "table":
  10579. if (me.options.disabledTableInTable && tdParent(node)) {
  10580. node.parentNode.insertBefore(
  10581. UE.uNode.createText(node.innerText()),
  10582. node
  10583. );
  10584. node.parentNode.removeChild(node);
  10585. }
  10586. }
  10587. }
  10588. // if(node.type == 'comment'){
  10589. // node.parentNode.removeChild(node);
  10590. // }
  10591. });
  10592. });
  10593. //从编辑器出去的内容处理
  10594. me.addOutputRule(function (root) {
  10595. var val;
  10596. root.traversal(function (node) {
  10597. if (node.type == "element") {
  10598. if (
  10599. me.options.autoClearEmptyNode &&
  10600. dtd.$inline[node.tagName] &&
  10601. !dtd.$empty[node.tagName] &&
  10602. (!node.attrs || utils.isEmptyObject(node.attrs))
  10603. ) {
  10604. if (!node.firstChild()) node.parentNode.removeChild(node);
  10605. else if (
  10606. node.tagName == "span" &&
  10607. (!node.attrs || utils.isEmptyObject(node.attrs))
  10608. ) {
  10609. node.parentNode.removeChild(node, true);
  10610. }
  10611. return;
  10612. }
  10613. switch (node.tagName) {
  10614. case "div":
  10615. if ((val = node.getAttr("cdata_tag"))) {
  10616. node.tagName = val;
  10617. node.appendChild(UE.uNode.createText(node.getAttr("cdata_data")));
  10618. node.setAttr({
  10619. cdata_tag: "",
  10620. cdata_data: "",
  10621. _ue_custom_node_: ""
  10622. });
  10623. }
  10624. break;
  10625. case "a":
  10626. if ((val = node.getAttr("_href"))) {
  10627. node.setAttr({
  10628. href: utils.html(val),
  10629. _href: ""
  10630. });
  10631. }
  10632. break;
  10633. break;
  10634. case "span":
  10635. val = node.getAttr("id");
  10636. if (val && /^_baidu_bookmark_/i.test(val)) {
  10637. node.parentNode.removeChild(node);
  10638. }
  10639. //将color的rgb格式转换为#16进制格式
  10640. if (me.getOpt("rgb2Hex")) {
  10641. var cssStyle = node.getAttr("style");
  10642. if (cssStyle) {
  10643. node.setAttr(
  10644. "style",
  10645. cssStyle.replace(/rgba?\(([\d,\s]+)\)/g, function (a, value) {
  10646. var array = value.split(",");
  10647. if (array.length > 3) return "";
  10648. value = "#";
  10649. for (var i = 0, color; (color = array[i++]);) {
  10650. color = parseInt(
  10651. color.replace(/[^\d]/gi, ""),
  10652. 10
  10653. ).toString(16);
  10654. value += color.length == 1 ? "0" + color : color;
  10655. }
  10656. return value.toUpperCase();
  10657. })
  10658. );
  10659. }
  10660. }
  10661. break;
  10662. case "img":
  10663. if ((val = node.getAttr("_src"))) {
  10664. node.setAttr({
  10665. src: node.getAttr("_src"),
  10666. _src: ""
  10667. });
  10668. }
  10669. }
  10670. }
  10671. });
  10672. });
  10673. };
  10674. // plugins/inserthtml.js
  10675. /**
  10676. * 插入html字符串插件
  10677. * @file
  10678. * @since 1.2.6.1
  10679. */
  10680. /**
  10681. * 插入html代码
  10682. * @command inserthtml
  10683. * @method execCommand
  10684. * @param { String } cmd 命令字符串
  10685. * @param { String } html 插入的html字符串
  10686. * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
  10687. * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
  10688. * @example
  10689. * ```javascript
  10690. * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
  10691. * //执行命令,插入<b>CC</b>
  10692. * //插入后的效果 xxx<b>CC</b>xxx
  10693. * //<p>xx|xxx</p> 当前选区为闭合状态
  10694. * //插入<p>CC</p>
  10695. * //结果 <p>xx</p><p>CC</p><p>xxx</p>
  10696. * //<p>xxxx</p>|</p>xxx</p> 当前选区在两个p标签之间
  10697. * //插入 xxxx
  10698. * //结果 <p>xxxx</p><p>xxxx</p></p>xxx</p>
  10699. * ```
  10700. */
  10701. UE.commands["inserthtml"] = {
  10702. execCommand: function (command, html, notNeedFilter) {
  10703. var me = this,
  10704. range,
  10705. div;
  10706. if (!html) {
  10707. return;
  10708. }
  10709. if (me.fireEvent("beforeinserthtml", html) === true) {
  10710. return;
  10711. }
  10712. range = me.selection.getRange();
  10713. div = range.document.createElement("div");
  10714. div.style.display = "inline";
  10715. if (!notNeedFilter) {
  10716. var root = UE.htmlparser(html);
  10717. //如果给了过滤规则就先进行过滤
  10718. if (me.options.filterRules) {
  10719. UE.filterNode(root, me.options.filterRules);
  10720. }
  10721. //执行默认的处理
  10722. me.filterInputRule(root);
  10723. html = root.toHtml();
  10724. }
  10725. div.innerHTML = utils.trim(html);
  10726. if (!range.collapsed) {
  10727. var tmpNode = range.startContainer;
  10728. if (domUtils.isFillChar(tmpNode)) {
  10729. range.setStartBefore(tmpNode);
  10730. }
  10731. tmpNode = range.endContainer;
  10732. if (domUtils.isFillChar(tmpNode)) {
  10733. range.setEndAfter(tmpNode);
  10734. }
  10735. range.txtToElmBoundary();
  10736. //结束边界可能放到了br的前边,要把br包含进来
  10737. // x[xxx]<br/>
  10738. if (range.endContainer && range.endContainer.nodeType == 1) {
  10739. tmpNode = range.endContainer.childNodes[range.endOffset];
  10740. if (tmpNode && domUtils.isBr(tmpNode)) {
  10741. range.setEndAfter(tmpNode);
  10742. }
  10743. }
  10744. if (range.startOffset == 0) {
  10745. tmpNode = range.startContainer;
  10746. if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
  10747. tmpNode = range.endContainer;
  10748. if (
  10749. range.endOffset ==
  10750. (tmpNode.nodeType == 3
  10751. ? tmpNode.nodeValue.length
  10752. : tmpNode.childNodes.length) &&
  10753. domUtils.isBoundaryNode(tmpNode, "lastChild")
  10754. ) {
  10755. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  10756. range.setStart(me.body.firstChild, 0).collapse(true);
  10757. }
  10758. }
  10759. }
  10760. !range.collapsed && range.deleteContents();
  10761. if (range.startContainer.nodeType == 1) {
  10762. var child = range.startContainer.childNodes[range.startOffset],
  10763. pre;
  10764. if (
  10765. child &&
  10766. domUtils.isBlockElm(child) &&
  10767. (pre = child.previousSibling) &&
  10768. domUtils.isBlockElm(pre)
  10769. ) {
  10770. range.setEnd(pre, pre.childNodes.length).collapse();
  10771. while (child.firstChild) {
  10772. pre.appendChild(child.firstChild);
  10773. }
  10774. domUtils.remove(child);
  10775. }
  10776. }
  10777. }
  10778. var child,
  10779. parent,
  10780. pre,
  10781. tmp,
  10782. hadBreak = 0,
  10783. nextNode;
  10784. //如果当前位置选中了fillchar要干掉,要不会产生空行
  10785. if (range.inFillChar()) {
  10786. child = range.startContainer;
  10787. if (domUtils.isFillChar(child)) {
  10788. range.setStartBefore(child).collapse(true);
  10789. domUtils.remove(child);
  10790. } else if (domUtils.isFillChar(child, true)) {
  10791. child.nodeValue = child.nodeValue.replace(fillCharReg, "");
  10792. range.startOffset--;
  10793. range.collapsed && range.collapse(true);
  10794. }
  10795. }
  10796. //列表单独处理
  10797. var li = domUtils.findParentByTagName(range.startContainer, "li", true);
  10798. if (li) {
  10799. var next, last;
  10800. while ((child = div.firstChild)) {
  10801. //针对hr单独处理一下先
  10802. while (
  10803. child &&
  10804. (child.nodeType == 3 ||
  10805. !domUtils.isBlockElm(child) ||
  10806. child.tagName == "HR")
  10807. ) {
  10808. next = child.nextSibling;
  10809. range.insertNode(child).collapse();
  10810. last = child;
  10811. child = next;
  10812. }
  10813. if (child) {
  10814. if (/^(ol|ul)$/i.test(child.tagName)) {
  10815. while (child.firstChild) {
  10816. last = child.firstChild;
  10817. domUtils.insertAfter(li, child.firstChild);
  10818. li = li.nextSibling;
  10819. }
  10820. domUtils.remove(child);
  10821. } else {
  10822. var tmpLi;
  10823. next = child.nextSibling;
  10824. tmpLi = me.document.createElement("li");
  10825. domUtils.insertAfter(li, tmpLi);
  10826. tmpLi.appendChild(child);
  10827. last = child;
  10828. child = next;
  10829. li = tmpLi;
  10830. }
  10831. }
  10832. }
  10833. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  10834. if (domUtils.isEmptyBlock(li)) {
  10835. domUtils.remove(li);
  10836. }
  10837. if (last) {
  10838. range.setStartAfter(last).collapse(true).select(true);
  10839. }
  10840. } else {
  10841. while ((child = div.firstChild)) {
  10842. if (hadBreak) {
  10843. var p = me.document.createElement("p");
  10844. while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
  10845. nextNode = child.nextSibling;
  10846. p.appendChild(child);
  10847. child = nextNode;
  10848. }
  10849. if (p.firstChild) {
  10850. child = p;
  10851. }
  10852. }
  10853. range.insertNode(child);
  10854. nextNode = child.nextSibling;
  10855. if (
  10856. !hadBreak &&
  10857. child.nodeType == domUtils.NODE_ELEMENT &&
  10858. domUtils.isBlockElm(child)
  10859. ) {
  10860. parent = domUtils.findParent(child, function (node) {
  10861. return domUtils.isBlockElm(node);
  10862. });
  10863. if (
  10864. parent &&
  10865. parent.tagName.toLowerCase() != "body" &&
  10866. !(
  10867. dtd[parent.tagName][child.nodeName] && child.parentNode === parent
  10868. )
  10869. ) {
  10870. if (!dtd[parent.tagName][child.nodeName]) {
  10871. pre = parent;
  10872. } else {
  10873. tmp = child.parentNode;
  10874. while (tmp !== parent) {
  10875. pre = tmp;
  10876. tmp = tmp.parentNode;
  10877. }
  10878. }
  10879. domUtils.breakParent(child, pre || tmp);
  10880. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  10881. var pre = child.previousSibling;
  10882. domUtils.trimWhiteTextNode(pre);
  10883. if (!pre.childNodes.length) {
  10884. domUtils.remove(pre);
  10885. }
  10886. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  10887. if (
  10888. !browser.ie &&
  10889. (next = child.nextSibling) &&
  10890. domUtils.isBlockElm(next) &&
  10891. next.lastChild &&
  10892. !domUtils.isBr(next.lastChild)
  10893. ) {
  10894. next.appendChild(me.document.createElement("br"));
  10895. }
  10896. hadBreak = 1;
  10897. }
  10898. }
  10899. var next = child.nextSibling;
  10900. if (!div.firstChild && next && domUtils.isBlockElm(next)) {
  10901. range.setStart(next, 0).collapse(true);
  10902. break;
  10903. }
  10904. range.setEndAfter(child).collapse();
  10905. }
  10906. child = range.startContainer;
  10907. if (nextNode && domUtils.isBr(nextNode)) {
  10908. domUtils.remove(nextNode);
  10909. }
  10910. //用chrome可能有空白展位符
  10911. if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
  10912. if ((nextNode = child.nextSibling)) {
  10913. domUtils.remove(child);
  10914. if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
  10915. range.setStart(nextNode, 0).collapse(true).shrinkBoundary();
  10916. }
  10917. } else {
  10918. try {
  10919. child.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
  10920. } catch (e) {
  10921. range.setStartBefore(child);
  10922. domUtils.remove(child);
  10923. }
  10924. }
  10925. }
  10926. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  10927. try {
  10928. range.select(true);
  10929. } catch (e) {
  10930. }
  10931. }
  10932. setTimeout(function () {
  10933. range = me.selection.getRange();
  10934. range.scrollToView(
  10935. me.autoHeightEnabled,
  10936. me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0
  10937. );
  10938. me.fireEvent("afterinserthtml", html);
  10939. }, 200);
  10940. }
  10941. };
  10942. // plugins/autotypeset.js
  10943. /**
  10944. * 自动排版
  10945. * @file
  10946. * @since 1.2.6.1
  10947. */
  10948. /**
  10949. * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
  10950. * @command autotypeset
  10951. * @method execCommand
  10952. * @param { String } cmd 命令字符串
  10953. * @example
  10954. * ```javascript
  10955. * editor.execCommand( 'autotypeset' );
  10956. * ```
  10957. */
  10958. UE.plugins["autotypeset"] = function () {
  10959. this.setOpt({
  10960. autotypeset: {
  10961. mergeEmptyline: true, //合并空行
  10962. removeClass: true, //去掉冗余的class
  10963. removeEmptyline: false, //去掉空行
  10964. textAlign: "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  10965. imageBlockLine: "center", //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  10966. pasteFilter: false, //根据规则过滤没事粘贴进来的内容
  10967. clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
  10968. clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
  10969. removeEmptyNode: false, // 去掉空节点
  10970. //可以去掉的标签
  10971. removeTagNames: utils.extend({div: 1}, dtd.$removeEmpty),
  10972. indent: false, // 行首缩进
  10973. indentValue: "2em", //行首缩进的大小
  10974. bdc2sb: false,
  10975. tobdc: false
  10976. }
  10977. });
  10978. var me = this,
  10979. opt = me.options.autotypeset,
  10980. remainClass = {
  10981. selectTdClass: 1,
  10982. pagebreak: 1,
  10983. anchorclass: 1
  10984. },
  10985. remainTag = {
  10986. li: 1
  10987. },
  10988. tags = {
  10989. div: 1,
  10990. p: 1,
  10991. //trace:2183 这些也认为是行
  10992. blockquote: 1,
  10993. center: 1,
  10994. h1: 1,
  10995. h2: 1,
  10996. h3: 1,
  10997. h4: 1,
  10998. h5: 1,
  10999. h6: 1,
  11000. span: 1
  11001. },
  11002. highlightCont;
  11003. //升级了版本,但配置项目里没有autotypeset
  11004. if (!opt) {
  11005. return;
  11006. }
  11007. readLocalOpts();
  11008. function isLine(node, notEmpty) {
  11009. if (!node || node.nodeType == 3) return 0;
  11010. if (domUtils.isBr(node)) return 1;
  11011. if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
  11012. if (
  11013. (highlightCont && highlightCont.contains(node)) ||
  11014. node.getAttribute("pagebreak")
  11015. ) {
  11016. return 0;
  11017. }
  11018. return notEmpty
  11019. ? !domUtils.isEmptyBlock(node)
  11020. : domUtils.isEmptyBlock(
  11021. node,
  11022. new RegExp("[\\s" + domUtils.fillChar + "]", "g")
  11023. );
  11024. }
  11025. }
  11026. function removeNotAttributeSpan(node) {
  11027. if (!node.style.cssText) {
  11028. domUtils.removeAttributes(node, ["style"]);
  11029. if (
  11030. node.tagName.toLowerCase() == "span" &&
  11031. domUtils.hasNoAttributes(node)
  11032. ) {
  11033. domUtils.remove(node, true);
  11034. }
  11035. }
  11036. }
  11037. function autotype(type, html) {
  11038. var me = this,
  11039. cont;
  11040. if (html) {
  11041. if (!opt.pasteFilter) {
  11042. return;
  11043. }
  11044. cont = me.document.createElement("div");
  11045. cont.innerHTML = html.html;
  11046. } else {
  11047. cont = me.document.body;
  11048. }
  11049. var nodes = domUtils.getElementsByTagName(cont, "*");
  11050. // 行首缩进,段落方向,段间距,段内间距
  11051. for (var i = 0, ci; (ci = nodes[i++]);) {
  11052. if (me.fireEvent("excludeNodeinautotype", ci) === true) {
  11053. continue;
  11054. }
  11055. //font-size
  11056. if (opt.clearFontSize && ci.style.fontSize) {
  11057. domUtils.removeStyle(ci, "font-size");
  11058. removeNotAttributeSpan(ci);
  11059. }
  11060. //font-family
  11061. if (opt.clearFontFamily && ci.style.fontFamily) {
  11062. domUtils.removeStyle(ci, "font-family");
  11063. removeNotAttributeSpan(ci);
  11064. }
  11065. if (isLine(ci)) {
  11066. //合并空行
  11067. if (opt.mergeEmptyline) {
  11068. var next = ci.nextSibling,
  11069. tmpNode,
  11070. isBr = domUtils.isBr(ci);
  11071. while (isLine(next)) {
  11072. tmpNode = next;
  11073. next = tmpNode.nextSibling;
  11074. if (isBr && (!next || (next && !domUtils.isBr(next)))) {
  11075. break;
  11076. }
  11077. domUtils.remove(tmpNode);
  11078. }
  11079. }
  11080. //去掉空行,保留占位的空行
  11081. if (
  11082. opt.removeEmptyline &&
  11083. domUtils.inDoc(ci, cont) &&
  11084. !remainTag[ci.parentNode.tagName.toLowerCase()]
  11085. ) {
  11086. if (domUtils.isBr(ci)) {
  11087. next = ci.nextSibling;
  11088. if (next && !domUtils.isBr(next)) {
  11089. continue;
  11090. }
  11091. }
  11092. domUtils.remove(ci);
  11093. continue;
  11094. }
  11095. }
  11096. if (isLine(ci, true) && ci.tagName != "SPAN") {
  11097. if (opt.indent) {
  11098. ci.style.textIndent = opt.indentValue;
  11099. }
  11100. if (opt.textAlign) {
  11101. ci.style.textAlign = opt.textAlign;
  11102. }
  11103. // if(opt.lineHeight)
  11104. // ci.style.lineHeight = opt.lineHeight + 'cm';
  11105. }
  11106. //去掉class,保留的class不去掉
  11107. if (
  11108. opt.removeClass &&
  11109. ci.className &&
  11110. !remainClass[ci.className.toLowerCase()]
  11111. ) {
  11112. if (highlightCont && highlightCont.contains(ci)) {
  11113. continue;
  11114. }
  11115. domUtils.removeAttributes(ci, ["class"]);
  11116. }
  11117. //表情不处理
  11118. if (
  11119. opt.imageBlockLine &&
  11120. ci.tagName.toLowerCase() == "img" &&
  11121. !ci.getAttribute("emotion")
  11122. ) {
  11123. if (html) {
  11124. var img = ci;
  11125. switch (opt.imageBlockLine) {
  11126. case "left":
  11127. case "right":
  11128. case "none":
  11129. var pN = img.parentNode,
  11130. tmpNode,
  11131. pre,
  11132. next;
  11133. while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
  11134. pN = pN.parentNode;
  11135. }
  11136. tmpNode = pN;
  11137. if (
  11138. tmpNode.tagName == "P" &&
  11139. domUtils.getStyle(tmpNode, "text-align") == "center"
  11140. ) {
  11141. if (
  11142. !domUtils.isBody(tmpNode) &&
  11143. domUtils.getChildCount(tmpNode, function (node) {
  11144. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11145. }) == 1
  11146. ) {
  11147. pre = tmpNode.previousSibling;
  11148. next = tmpNode.nextSibling;
  11149. if (
  11150. pre &&
  11151. next &&
  11152. pre.nodeType == 1 &&
  11153. next.nodeType == 1 &&
  11154. pre.tagName == next.tagName &&
  11155. domUtils.isBlockElm(pre)
  11156. ) {
  11157. pre.appendChild(tmpNode.firstChild);
  11158. while (next.firstChild) {
  11159. pre.appendChild(next.firstChild);
  11160. }
  11161. domUtils.remove(tmpNode);
  11162. domUtils.remove(next);
  11163. } else {
  11164. domUtils.setStyle(tmpNode, "text-align", "");
  11165. }
  11166. }
  11167. }
  11168. domUtils.setStyle(img, "float", opt.imageBlockLine);
  11169. break;
  11170. case "center":
  11171. if (me.queryCommandValue("imagefloat") != "center") {
  11172. pN = img.parentNode;
  11173. domUtils.setStyle(img, "float", "none");
  11174. tmpNode = img;
  11175. while (
  11176. pN &&
  11177. domUtils.getChildCount(pN, function (node) {
  11178. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11179. }) == 1 &&
  11180. (dtd.$inline[pN.tagName] || pN.tagName == "A")
  11181. ) {
  11182. tmpNode = pN;
  11183. pN = pN.parentNode;
  11184. }
  11185. var pNode = me.document.createElement("p");
  11186. domUtils.setAttributes(pNode, {
  11187. style: "text-align:center"
  11188. });
  11189. tmpNode.parentNode.insertBefore(pNode, tmpNode);
  11190. pNode.appendChild(tmpNode);
  11191. domUtils.setStyle(tmpNode, "float", "");
  11192. }
  11193. }
  11194. } else {
  11195. var range = me.selection.getRange();
  11196. range.selectNode(ci).select();
  11197. me.execCommand("imagefloat", opt.imageBlockLine);
  11198. }
  11199. }
  11200. //去掉冗余的标签
  11201. if (opt.removeEmptyNode) {
  11202. if (
  11203. opt.removeTagNames[ci.tagName.toLowerCase()] &&
  11204. domUtils.hasNoAttributes(ci) &&
  11205. domUtils.isEmptyBlock(ci)
  11206. ) {
  11207. domUtils.remove(ci);
  11208. }
  11209. }
  11210. }
  11211. if (opt.tobdc) {
  11212. var root = UE.htmlparser(cont.innerHTML);
  11213. root.traversal(function (node) {
  11214. if (node.type == "text") {
  11215. node.data = ToDBC(node.data);
  11216. }
  11217. });
  11218. cont.innerHTML = root.toHtml();
  11219. }
  11220. if (opt.bdc2sb) {
  11221. var root = UE.htmlparser(cont.innerHTML);
  11222. root.traversal(function (node) {
  11223. if (node.type == "text") {
  11224. node.data = DBC2SB(node.data);
  11225. }
  11226. });
  11227. cont.innerHTML = root.toHtml();
  11228. }
  11229. if (html) {
  11230. html.html = cont.innerHTML;
  11231. }
  11232. }
  11233. if (opt.pasteFilter) {
  11234. me.addListener("beforepaste", autotype);
  11235. }
  11236. function DBC2SB(str) {
  11237. var result = "";
  11238. for (var i = 0; i < str.length; i++) {
  11239. var code = str.charCodeAt(i); //获取当前字符的unicode编码
  11240. if (code >= 65281 && code <= 65373) {
  11241. //在这个unicode编码范围中的是所有的英文字母已经各种字符
  11242. result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码
  11243. } else if (code == 12288) {
  11244. //空格
  11245. result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
  11246. } else {
  11247. result += str.charAt(i);
  11248. }
  11249. }
  11250. return result;
  11251. }
  11252. function ToDBC(txtstring) {
  11253. txtstring = utils.html(txtstring);
  11254. var tmp = "";
  11255. var mark = "";
  11256. /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
  11257. for (var i = 0; i < txtstring.length; i++) {
  11258. if (txtstring.charCodeAt(i) == 32) {
  11259. tmp = tmp + String.fromCharCode(12288);
  11260. } else if (txtstring.charCodeAt(i) < 127) {
  11261. tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248);
  11262. } else {
  11263. tmp += txtstring.charAt(i);
  11264. }
  11265. }
  11266. return tmp;
  11267. }
  11268. function readLocalOpts() {
  11269. var cookieOpt = me.getPreferences("autotypeset");
  11270. utils.extend(me.options.autotypeset, cookieOpt);
  11271. }
  11272. me.commands["autotypeset"] = {
  11273. execCommand: function () {
  11274. me.removeListener("beforepaste", autotype);
  11275. if (opt.pasteFilter) {
  11276. me.addListener("beforepaste", autotype);
  11277. }
  11278. autotype.call(me);
  11279. }
  11280. };
  11281. };
  11282. // plugins/autosubmit.js
  11283. /**
  11284. * 快捷键提交
  11285. * @file
  11286. * @since 1.2.6.1
  11287. */
  11288. /**
  11289. * 提交表单
  11290. * @command autosubmit
  11291. * @method execCommand
  11292. * @param { String } cmd 命令字符串
  11293. * @example
  11294. * ```javascript
  11295. * editor.execCommand( 'autosubmit' );
  11296. * ```
  11297. */
  11298. UE.plugin.register("autosubmit", function () {
  11299. return {
  11300. shortcutkey: {
  11301. autosubmit: "ctrl+13" //手动提交
  11302. },
  11303. commands: {
  11304. autosubmit: {
  11305. execCommand: function () {
  11306. var me = this,
  11307. form = domUtils.findParentByTagName(me.iframe, "form", false);
  11308. if (form) {
  11309. if (me.fireEvent("beforesubmit") === false) {
  11310. return;
  11311. }
  11312. me.sync();
  11313. form.submit();
  11314. }
  11315. }
  11316. }
  11317. }
  11318. };
  11319. });
  11320. // plugins/background.js
  11321. /**
  11322. * 背景插件,为UEditor提供设置背景功能
  11323. * @file
  11324. * @since 1.2.6.1
  11325. */
  11326. UE.plugin.register("background", function () {
  11327. var me = this,
  11328. cssRuleId = "editor_background",
  11329. isSetColored,
  11330. reg = new RegExp("body[\\s]*\\{(.+)\\}", "i");
  11331. function stringToObj(str) {
  11332. var obj = {},
  11333. styles = str.split(";");
  11334. utils.each(styles, function (v) {
  11335. var index = v.indexOf(":"),
  11336. key = utils.trim(v.substr(0, index)).toLowerCase();
  11337. key && (obj[key] = utils.trim(v.substr(index + 1) || ""));
  11338. });
  11339. return obj;
  11340. }
  11341. function setBackground(obj) {
  11342. if (obj) {
  11343. var styles = [];
  11344. for (var name in obj) {
  11345. if (obj.hasOwnProperty(name)) {
  11346. styles.push(name + ":" + obj[name] + "; ");
  11347. }
  11348. }
  11349. utils.cssRule(
  11350. cssRuleId,
  11351. styles.length ? "body{" + styles.join("") + "}" : "",
  11352. me.document
  11353. );
  11354. } else {
  11355. utils.cssRule(cssRuleId, "", me.document);
  11356. }
  11357. }
  11358. //重写editor.hasContent方法
  11359. var orgFn = me.hasContents;
  11360. me.hasContents = function () {
  11361. if (me.queryCommandValue("background")) {
  11362. return true;
  11363. }
  11364. return orgFn.apply(me, arguments);
  11365. };
  11366. return {
  11367. bindEvents: {
  11368. getAllHtml: function (type, headHtml) {
  11369. var body = this.body,
  11370. su = domUtils.getComputedStyle(body, "background-image"),
  11371. url = "";
  11372. if (su.indexOf(me.options.imagePath) > 0) {
  11373. url = su
  11374. .substring(su.indexOf(me.options.imagePath), su.length - 1)
  11375. .replace(/"|\(|\)/gi, "");
  11376. } else {
  11377. url = su != "none" ? su.replace(/url\("?|"?\)/gi, "") : "";
  11378. }
  11379. var html = '<style type="text/css">body{';
  11380. var bgObj = {
  11381. "background-color":
  11382. domUtils.getComputedStyle(body, "background-color") || "#ffffff",
  11383. "background-image": url ? "url(" + url + ")" : "",
  11384. "background-repeat":
  11385. domUtils.getComputedStyle(body, "background-repeat") || "",
  11386. "background-position": browser.ie
  11387. ? domUtils.getComputedStyle(body, "background-position-x") +
  11388. " " +
  11389. domUtils.getComputedStyle(body, "background-position-y")
  11390. : domUtils.getComputedStyle(body, "background-position"),
  11391. height: domUtils.getComputedStyle(body, "height")
  11392. };
  11393. for (var name in bgObj) {
  11394. if (bgObj.hasOwnProperty(name)) {
  11395. html += name + ":" + bgObj[name] + "; ";
  11396. }
  11397. }
  11398. html += "}</style> ";
  11399. headHtml.push(html);
  11400. },
  11401. aftersetcontent: function () {
  11402. if (isSetColored == false) setBackground();
  11403. }
  11404. },
  11405. inputRule: function (root) {
  11406. isSetColored = false;
  11407. utils.each(root.getNodesByTagName("p"), function (p) {
  11408. var styles = p.getAttr("data-background");
  11409. if (styles) {
  11410. isSetColored = true;
  11411. setBackground(stringToObj(styles));
  11412. p.parentNode.removeChild(p);
  11413. }
  11414. });
  11415. },
  11416. outputRule: function (root) {
  11417. var me = this,
  11418. styles = (utils.cssRule(cssRuleId, me.document) || "")
  11419. .replace(/[\n\r]+/g, "")
  11420. .match(reg);
  11421. if (styles) {
  11422. root.appendChild(
  11423. UE.uNode.createElement(
  11424. '<p style="display:none;" data-background="' +
  11425. utils.trim(styles[1].replace(/"/g, "").replace(/[\s]+/g, " ")) +
  11426. '"><br/></p>'
  11427. )
  11428. );
  11429. }
  11430. },
  11431. commands: {
  11432. background: {
  11433. execCommand: function (cmd, obj) {
  11434. setBackground(obj);
  11435. },
  11436. queryCommandValue: function () {
  11437. var me = this,
  11438. styles = (utils.cssRule(cssRuleId, me.document) || "")
  11439. .replace(/[\n\r]+/g, "")
  11440. .match(reg);
  11441. return styles ? stringToObj(styles[1]) : null;
  11442. },
  11443. notNeedUndo: true
  11444. }
  11445. }
  11446. };
  11447. });
  11448. // plugins/image.js
  11449. /**
  11450. * 图片插入、排版插件
  11451. * @file
  11452. * @since 1.2.6.1
  11453. */
  11454. /**
  11455. * 图片对齐方式
  11456. * @command imagefloat
  11457. * @method execCommand
  11458. * @remind 值center为独占一行居中
  11459. * @param { String } cmd 命令字符串
  11460. * @param { String } align 对齐方式,可传left、right、none、center
  11461. * @remaind center表示图片独占一行
  11462. * @example
  11463. * ```javascript
  11464. * editor.execCommand( 'imagefloat', 'center' );
  11465. * ```
  11466. */
  11467. /**
  11468. * 如果选区所在位置是图片区域
  11469. * @command imagefloat
  11470. * @method queryCommandValue
  11471. * @param { String } cmd 命令字符串
  11472. * @return { String } 返回图片对齐方式
  11473. * @example
  11474. * ```javascript
  11475. * editor.queryCommandValue( 'imagefloat' );
  11476. * ```
  11477. */
  11478. UE.commands["imagefloat"] = {
  11479. execCommand: function (cmd, align) {
  11480. var me = this,
  11481. range = me.selection.getRange();
  11482. if (!range.collapsed) {
  11483. var img = range.getClosedNode();
  11484. if (img && img.tagName == "IMG") {
  11485. switch (align) {
  11486. case "left":
  11487. case "right":
  11488. case "none":
  11489. var pN = img.parentNode,
  11490. tmpNode,
  11491. pre,
  11492. next;
  11493. while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
  11494. pN = pN.parentNode;
  11495. }
  11496. tmpNode = pN;
  11497. if (
  11498. tmpNode.tagName == "P" &&
  11499. domUtils.getStyle(tmpNode, "text-align") == "center"
  11500. ) {
  11501. if (
  11502. !domUtils.isBody(tmpNode) &&
  11503. domUtils.getChildCount(tmpNode, function (node) {
  11504. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11505. }) == 1
  11506. ) {
  11507. pre = tmpNode.previousSibling;
  11508. next = tmpNode.nextSibling;
  11509. if (
  11510. pre &&
  11511. next &&
  11512. pre.nodeType == 1 &&
  11513. next.nodeType == 1 &&
  11514. pre.tagName == next.tagName &&
  11515. domUtils.isBlockElm(pre)
  11516. ) {
  11517. pre.appendChild(tmpNode.firstChild);
  11518. while (next.firstChild) {
  11519. pre.appendChild(next.firstChild);
  11520. }
  11521. domUtils.remove(tmpNode);
  11522. domUtils.remove(next);
  11523. } else {
  11524. domUtils.setStyle(tmpNode, "text-align", "");
  11525. }
  11526. }
  11527. range.selectNode(img).select();
  11528. }
  11529. domUtils.setStyle(img, "float", align == "none" ? "" : align);
  11530. if (align == "none") {
  11531. domUtils.removeAttributes(img, "align");
  11532. }
  11533. break;
  11534. case "center":
  11535. if (me.queryCommandValue("imagefloat") != "center") {
  11536. var pN = img.parentNode;
  11537. domUtils.setStyle(img, "float", "");
  11538. domUtils.removeAttributes(img, "align");
  11539. tmpNode = img;
  11540. while (
  11541. pN &&
  11542. domUtils.getChildCount(pN, function (node) {
  11543. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11544. }) == 1 &&
  11545. (dtd.$inline[pN.tagName] || pN.tagName == "A")
  11546. ) {
  11547. tmpNode = pN;
  11548. pN = pN.parentNode;
  11549. }
  11550. range.setStartBefore(tmpNode).setCursor(false);
  11551. pN = me.document.createElement("div");
  11552. pN.appendChild(tmpNode);
  11553. domUtils.setStyle(tmpNode, "float", "");
  11554. me.execCommand(
  11555. "insertHtml",
  11556. '<p class="_img_parent_tmp" style="text-align:center">' +
  11557. pN.innerHTML +
  11558. "</p>"
  11559. );
  11560. tmpNode = me.document.getElementsByClassName("_img_parent_tmp")[0];
  11561. tmpNode.removeAttribute("class");
  11562. tmpNode = tmpNode.firstChild;
  11563. range.selectNode(tmpNode).select();
  11564. //去掉后边多余的元素
  11565. next = tmpNode.parentNode.nextSibling;
  11566. if (next && domUtils.isEmptyNode(next)) {
  11567. domUtils.remove(next);
  11568. }
  11569. }
  11570. break;
  11571. }
  11572. }
  11573. }
  11574. },
  11575. queryCommandValue: function () {
  11576. var range = this.selection.getRange(),
  11577. startNode,
  11578. floatStyle;
  11579. if (range.collapsed) {
  11580. return "none";
  11581. }
  11582. startNode = range.getClosedNode();
  11583. if (startNode && startNode.nodeType == 1 && startNode.tagName == "IMG") {
  11584. floatStyle =
  11585. domUtils.getComputedStyle(startNode, "float") ||
  11586. startNode.getAttribute("align");
  11587. if (floatStyle == "none") {
  11588. floatStyle = domUtils.getComputedStyle(
  11589. startNode.parentNode,
  11590. "text-align"
  11591. ) == "center"
  11592. ? "center"
  11593. : floatStyle;
  11594. }
  11595. return {
  11596. left: 1,
  11597. right: 1,
  11598. center: 1
  11599. }[floatStyle]
  11600. ? floatStyle
  11601. : "none";
  11602. }
  11603. return "none";
  11604. },
  11605. queryCommandState: function () {
  11606. var range = this.selection.getRange(),
  11607. startNode;
  11608. if (range.collapsed) return -1;
  11609. startNode = range.getClosedNode();
  11610. if (startNode && startNode.nodeType == 1 && startNode.tagName == "IMG") {
  11611. return 0;
  11612. }
  11613. return -1;
  11614. }
  11615. };
  11616. /**
  11617. * 插入图片
  11618. * @command insertimage
  11619. * @method execCommand
  11620. * @param { String } cmd 命令字符串
  11621. * @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片
  11622. * @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片,
  11623. * 此时数组的每一个元素都是一个Object类型的图片属性集合。
  11624. * @example
  11625. * ```javascript
  11626. * editor.execCommand( 'insertimage', {
  11627. * src:'a/b/c.jpg',
  11628. * width:'100',
  11629. * height:'100'
  11630. * } );
  11631. * ```
  11632. * @example
  11633. * ```javascript
  11634. * editor.execCommand( 'insertimage', [{
  11635. * src:'a/b/c.jpg',
  11636. * width:'100',
  11637. * height:'100'
  11638. * },{
  11639. * src:'a/b/d.jpg',
  11640. * width:'100',
  11641. * height:'100'
  11642. * }] );
  11643. * ```
  11644. */
  11645. UE.commands["insertimage"] = {
  11646. execCommand: function (cmd, opt) {
  11647. opt = utils.isArray(opt) ? opt : [opt];
  11648. if (!opt.length) {
  11649. return;
  11650. }
  11651. var me = this,
  11652. range = me.selection.getRange(),
  11653. img = range.getClosedNode();
  11654. if (me.fireEvent("beforeinsertimage", opt) === true) {
  11655. return;
  11656. }
  11657. if (
  11658. img &&
  11659. /img/i.test(img.tagName) &&
  11660. (img.className != "edui-faked-video" ||
  11661. img.className.indexOf("edui-upload-video") != -1) &&
  11662. !img.getAttribute("word_img")
  11663. ) {
  11664. var first = opt.shift();
  11665. var floatStyle = first["floatStyle"];
  11666. delete first["floatStyle"];
  11667. //// img.style.border = (first.border||0) +"px solid #000";
  11668. //// img.style.margin = (first.margin||0) +"px";
  11669. // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
  11670. domUtils.setAttributes(img, first);
  11671. me.execCommand("imagefloat", floatStyle);
  11672. if (opt.length > 0) {
  11673. range.setStartAfter(img).setCursor(false, true);
  11674. me.execCommand("insertimage", opt);
  11675. }
  11676. } else {
  11677. var html = [],
  11678. str = "",
  11679. ci;
  11680. ci = opt[0];
  11681. if (opt.length == 1) {
  11682. str =
  11683. '<img src="' +
  11684. ci.src +
  11685. '" ' +
  11686. (ci._src ? ' _src="' + ci._src + '" ' : "") +
  11687. (ci.width ? 'width="' + ci.width + '" ' : "") +
  11688. (ci.height ? ' height="' + ci.height + '" ' : "") +
  11689. (ci["floatStyle"] == "left" || ci["floatStyle"] == "right"
  11690. ? ' style="float:' + ci["floatStyle"] + ';"'
  11691. : "") +
  11692. (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : "") +
  11693. (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : "") +
  11694. (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : "") +
  11695. (ci.hspace && ci.hspace != "0"
  11696. ? ' hspace = "' + ci.hspace + '"'
  11697. : "") +
  11698. (ci.vspace && ci.vspace != "0"
  11699. ? ' vspace = "' + ci.vspace + '"'
  11700. : "") +
  11701. "/>";
  11702. if (ci["floatStyle"] == "center") {
  11703. str = '<p style="text-align: center">' + str + "</p>";
  11704. }
  11705. html.push(str);
  11706. } else {
  11707. for (var i = 0; (ci = opt[i++]);) {
  11708. str =
  11709. "<p " +
  11710. (ci["floatStyle"] == "center"
  11711. ? 'style="text-align: center" '
  11712. : "") +
  11713. '><img src="' +
  11714. ci.src +
  11715. '" ' +
  11716. (ci.width ? 'width="' + ci.width + '" ' : "") +
  11717. (ci._src ? ' _src="' + ci._src + '" ' : "") +
  11718. (ci.height ? ' height="' + ci.height + '" ' : "") +
  11719. ' style="' +
  11720. (ci["floatStyle"] && ci["floatStyle"] != "center"
  11721. ? "float:" + ci["floatStyle"] + ";"
  11722. : "") +
  11723. (ci.border || "") +
  11724. '" ' +
  11725. (ci.title ? ' title="' + ci.title + '"' : "") +
  11726. " /></p>";
  11727. html.push(str);
  11728. }
  11729. }
  11730. me.execCommand("insertHtml", html.join(""));
  11731. }
  11732. me.fireEvent("afterinsertimage", opt);
  11733. }
  11734. };
  11735. // plugins/justify.js
  11736. /**
  11737. * 段落格式
  11738. * @file
  11739. * @since 1.2.6.1
  11740. */
  11741. /**
  11742. * 段落对齐方式
  11743. * @command justify
  11744. * @method execCommand
  11745. * @param { String } cmd 命令字符串
  11746. * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐
  11747. * @example
  11748. * ```javascript
  11749. * editor.execCommand( 'justify', 'center' );
  11750. * ```
  11751. */
  11752. /**
  11753. * 如果选区所在位置是段落区域,返回当前段落对齐方式
  11754. * @command justify
  11755. * @method queryCommandValue
  11756. * @param { String } cmd 命令字符串
  11757. * @return { String } 返回段落对齐方式
  11758. * @example
  11759. * ```javascript
  11760. * editor.queryCommandValue( 'justify' );
  11761. * ```
  11762. */
  11763. UE.plugins["justify"] = function () {
  11764. var me = this,
  11765. block = domUtils.isBlockElm,
  11766. defaultValue = {
  11767. left: 1,
  11768. right: 1,
  11769. center: 1,
  11770. justify: 1
  11771. },
  11772. doJustify = function (range, style) {
  11773. var bookmark = range.createBookmark(),
  11774. filterFn = function (node) {
  11775. return node.nodeType == 1
  11776. ? node.tagName.toLowerCase() != "br" &&
  11777. !domUtils.isBookmarkNode(node)
  11778. : !domUtils.isWhitespace(node);
  11779. };
  11780. range.enlarge(true);
  11781. var bookmark2 = range.createBookmark(),
  11782. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  11783. tmpRange = range.cloneRange(),
  11784. tmpNode;
  11785. while (
  11786. current &&
  11787. !(
  11788. domUtils.getPosition(current, bookmark2.end) &
  11789. domUtils.POSITION_FOLLOWING
  11790. )
  11791. ) {
  11792. if (current.nodeType == 3 || !block(current)) {
  11793. tmpRange.setStartBefore(current);
  11794. while (current && current !== bookmark2.end && !block(current)) {
  11795. tmpNode = current;
  11796. current = domUtils.getNextDomNode(current, false, null, function (
  11797. node
  11798. ) {
  11799. return !block(node);
  11800. });
  11801. }
  11802. tmpRange.setEndAfter(tmpNode);
  11803. var common = tmpRange.getCommonAncestor();
  11804. if (!domUtils.isBody(common) && block(common)) {
  11805. domUtils.setStyles(
  11806. common,
  11807. utils.isString(style) ? {"text-align": style} : style
  11808. );
  11809. current = common;
  11810. } else {
  11811. var p = range.document.createElement("p");
  11812. domUtils.setStyles(
  11813. p,
  11814. utils.isString(style) ? {"text-align": style} : style
  11815. );
  11816. var frag = tmpRange.extractContents();
  11817. p.appendChild(frag);
  11818. tmpRange.insertNode(p);
  11819. current = p;
  11820. }
  11821. current = domUtils.getNextDomNode(current, false, filterFn);
  11822. } else {
  11823. current = domUtils.getNextDomNode(current, true, filterFn);
  11824. }
  11825. }
  11826. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  11827. };
  11828. UE.commands["justify"] = {
  11829. execCommand: function (cmdName, align) {
  11830. var range = this.selection.getRange(),
  11831. txt;
  11832. //闭合时单独处理
  11833. if (range.collapsed) {
  11834. txt = this.document.createTextNode("p");
  11835. range.insertNode(txt);
  11836. }
  11837. doJustify(range, align);
  11838. if (txt) {
  11839. range.setStartBefore(txt).collapse(true);
  11840. domUtils.remove(txt);
  11841. }
  11842. range.select();
  11843. return true;
  11844. },
  11845. queryCommandValue: function () {
  11846. var startNode = this.selection.getStart(),
  11847. value = domUtils.getComputedStyle(startNode, "text-align");
  11848. return defaultValue[value] ? value : "left";
  11849. },
  11850. queryCommandState: function () {
  11851. var start = this.selection.getStart(),
  11852. cell =
  11853. start &&
  11854. domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  11855. return cell ? -1 : 0;
  11856. }
  11857. };
  11858. };
  11859. // plugins/font.js
  11860. /**
  11861. * 字体颜色,背景色,字号,字体,下划线,删除线
  11862. * @file
  11863. * @since 1.2.6.1
  11864. */
  11865. /**
  11866. * 字体颜色
  11867. * @command forecolor
  11868. * @method execCommand
  11869. * @param { String } cmd 命令字符串
  11870. * @param { String } value 色值(必须十六进制)
  11871. * @example
  11872. * ```javascript
  11873. * editor.execCommand( 'forecolor', '#000' );
  11874. * ```
  11875. */
  11876. /**
  11877. * 返回选区字体颜色
  11878. * @command forecolor
  11879. * @method queryCommandValue
  11880. * @param { String } cmd 命令字符串
  11881. * @return { String } 返回字体颜色
  11882. * @example
  11883. * ```javascript
  11884. * editor.queryCommandValue( 'forecolor' );
  11885. * ```
  11886. */
  11887. /**
  11888. * 字体背景颜色
  11889. * @command backcolor
  11890. * @method execCommand
  11891. * @param { String } cmd 命令字符串
  11892. * @param { String } value 色值(必须十六进制)
  11893. * @example
  11894. * ```javascript
  11895. * editor.execCommand( 'backcolor', '#000' );
  11896. * ```
  11897. */
  11898. /**
  11899. * 返回选区字体颜色
  11900. * @command backcolor
  11901. * @method queryCommandValue
  11902. * @param { String } cmd 命令字符串
  11903. * @return { String } 返回字体背景颜色
  11904. * @example
  11905. * ```javascript
  11906. * editor.queryCommandValue( 'backcolor' );
  11907. * ```
  11908. */
  11909. /**
  11910. * 字体大小
  11911. * @command fontsize
  11912. * @method execCommand
  11913. * @param { String } cmd 命令字符串
  11914. * @param { String } value 字体大小
  11915. * @example
  11916. * ```javascript
  11917. * editor.execCommand( 'fontsize', '14px' );
  11918. * ```
  11919. */
  11920. /**
  11921. * 返回选区字体大小
  11922. * @command fontsize
  11923. * @method queryCommandValue
  11924. * @param { String } cmd 命令字符串
  11925. * @return { String } 返回字体大小
  11926. * @example
  11927. * ```javascript
  11928. * editor.queryCommandValue( 'fontsize' );
  11929. * ```
  11930. */
  11931. /**
  11932. * 字体样式
  11933. * @command fontfamily
  11934. * @method execCommand
  11935. * @param { String } cmd 命令字符串
  11936. * @param { String } value 字体样式
  11937. * @example
  11938. * ```javascript
  11939. * editor.execCommand( 'fontfamily', '微软雅黑' );
  11940. * ```
  11941. */
  11942. /**
  11943. * 返回选区字体样式
  11944. * @command fontfamily
  11945. * @method queryCommandValue
  11946. * @param { String } cmd 命令字符串
  11947. * @return { String } 返回字体样式
  11948. * @example
  11949. * ```javascript
  11950. * editor.queryCommandValue( 'fontfamily' );
  11951. * ```
  11952. */
  11953. /**
  11954. * 字体下划线,与删除线互斥
  11955. * @command underline
  11956. * @method execCommand
  11957. * @param { String } cmd 命令字符串
  11958. * @example
  11959. * ```javascript
  11960. * editor.execCommand( 'underline' );
  11961. * ```
  11962. */
  11963. /**
  11964. * 字体删除线,与下划线互斥
  11965. * @command strikethrough
  11966. * @method execCommand
  11967. * @param { String } cmd 命令字符串
  11968. * @example
  11969. * ```javascript
  11970. * editor.execCommand( 'strikethrough' );
  11971. * ```
  11972. */
  11973. /**
  11974. * 字体边框
  11975. * @command fontborder
  11976. * @method execCommand
  11977. * @param { String } cmd 命令字符串
  11978. * @example
  11979. * ```javascript
  11980. * editor.execCommand( 'fontborder' );
  11981. * ```
  11982. */
  11983. UE.plugins["font"] = function () {
  11984. var me = this,
  11985. fonts = {
  11986. forecolor: "color",
  11987. backcolor: "background-color",
  11988. fontsize: "font-size",
  11989. fontfamily: "font-family",
  11990. underline: "text-decoration",
  11991. strikethrough: "text-decoration",
  11992. fontborder: "border"
  11993. },
  11994. needCmd = {underline: 1, strikethrough: 1, fontborder: 1},
  11995. needSetChild = {
  11996. forecolor: "color",
  11997. backcolor: "background-color",
  11998. fontsize: "font-size",
  11999. fontfamily: "font-family"
  12000. };
  12001. me.setOpt({
  12002. fontfamily: [
  12003. {name: "songti", val: "宋体,SimSun"},
  12004. {name: "yahei", val: "微软雅黑,Microsoft YaHei"},
  12005. {name: "kaiti", val: "楷体,楷体_GB2312, SimKai"},
  12006. {name: "heiti", val: "黑体, SimHei"},
  12007. {name: "lishu", val: "隶书, SimLi"},
  12008. {name: "andaleMono", val: "andale mono"},
  12009. {name: "arial", val: "arial, helvetica,sans-serif"},
  12010. {name: "arialBlack", val: "arial black,avant garde"},
  12011. {name: "comicSansMs", val: "comic sans ms"},
  12012. {name: "impact", val: "impact,chicago"},
  12013. {name: "timesNewRoman", val: "times new roman"}
  12014. ],
  12015. fontsize: [10, 11, 12, 14, 16, 18, 20, 24, 36]
  12016. });
  12017. function mergeWithParent(node) {
  12018. var parent;
  12019. while ((parent = node.parentNode)) {
  12020. if (
  12021. parent.tagName == "SPAN" &&
  12022. domUtils.getChildCount(parent, function (child) {
  12023. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child);
  12024. }) == 1
  12025. ) {
  12026. parent.style.cssText += node.style.cssText;
  12027. domUtils.remove(node, true);
  12028. node = parent;
  12029. } else {
  12030. break;
  12031. }
  12032. }
  12033. }
  12034. function mergeChild(rng, cmdName, value) {
  12035. if (needSetChild[cmdName]) {
  12036. rng.adjustmentBoundary();
  12037. if (!rng.collapsed && rng.startContainer.nodeType == 1) {
  12038. rng.traversal(function (node) {
  12039. var start;
  12040. if (domUtils.isTagNode(node, 'span')) {
  12041. start = node;
  12042. } else {
  12043. start = domUtils.getElementsByTagName(node, 'span')[0];
  12044. }
  12045. if (start && domUtils.isTagNode(start, "span")) {
  12046. var bk = rng.createBookmark();
  12047. utils.each(domUtils.getElementsByTagName(start, "span"), function (
  12048. span
  12049. ) {
  12050. if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
  12051. if (
  12052. cmdName == "backcolor" &&
  12053. domUtils
  12054. .getComputedStyle(span, "background-color")
  12055. .toLowerCase() === value
  12056. ) {
  12057. return;
  12058. }
  12059. domUtils.removeStyle(span, needSetChild[cmdName]);
  12060. if (span.style.cssText.replace(/^\s+$/, "").length == 0) {
  12061. domUtils.remove(span, true);
  12062. }
  12063. });
  12064. rng.moveToBookmark(bk);
  12065. }
  12066. });
  12067. }
  12068. }
  12069. }
  12070. function mergesibling(rng, cmdName, value) {
  12071. var collapsed = rng.collapsed,
  12072. bk = rng.createBookmark(),
  12073. common;
  12074. if (collapsed) {
  12075. common = bk.start.parentNode;
  12076. while (dtd.$inline[common.tagName]) {
  12077. common = common.parentNode;
  12078. }
  12079. } else {
  12080. common = domUtils.getCommonAncestor(bk.start, bk.end);
  12081. }
  12082. utils.each(domUtils.getElementsByTagName(common, "span"), function (span) {
  12083. if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
  12084. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  12085. if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
  12086. domUtils.remove(span, true);
  12087. } else {
  12088. domUtils.removeStyle(span, "border");
  12089. }
  12090. return;
  12091. }
  12092. if (
  12093. /border/i.test(span.style.cssText) &&
  12094. span.parentNode.tagName == "SPAN" &&
  12095. /border/i.test(span.parentNode.style.cssText)
  12096. ) {
  12097. span.style.cssText = span.style.cssText.replace(
  12098. /border[^:]*:[^;]+;?/gi,
  12099. ""
  12100. );
  12101. }
  12102. if (!(cmdName == "fontborder" && value == "none")) {
  12103. var next = span.nextSibling;
  12104. while (next && next.nodeType == 1 && next.tagName == "SPAN") {
  12105. if (domUtils.isBookmarkNode(next) && cmdName == "fontborder") {
  12106. span.appendChild(next);
  12107. next = span.nextSibling;
  12108. continue;
  12109. }
  12110. if (next.style.cssText == span.style.cssText) {
  12111. domUtils.moveChild(next, span);
  12112. domUtils.remove(next);
  12113. }
  12114. if (span.nextSibling === next) break;
  12115. next = span.nextSibling;
  12116. }
  12117. }
  12118. mergeWithParent(span);
  12119. if (browser.ie && browser.version > 8) {
  12120. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  12121. var parent = domUtils.findParent(span, function (n) {
  12122. return (
  12123. n.tagName == "SPAN" && /background-color/.test(n.style.cssText)
  12124. );
  12125. });
  12126. if (parent && !/background-color/.test(span.style.cssText)) {
  12127. span.style.backgroundColor = parent.style.backgroundColor;
  12128. }
  12129. }
  12130. });
  12131. rng.moveToBookmark(bk);
  12132. mergeChild(rng, cmdName, value);
  12133. }
  12134. me.addInputRule(function (root) {
  12135. utils.each(root.getNodesByTagName("u s del font strike"), function (node) {
  12136. if (node.tagName == "font") {
  12137. var cssStyle = [];
  12138. for (var p in node.attrs) {
  12139. switch (p) {
  12140. case "size":
  12141. cssStyle.push(
  12142. "font-size:" +
  12143. ({
  12144. "1": "10",
  12145. "2": "12",
  12146. "3": "16",
  12147. "4": "18",
  12148. "5": "24",
  12149. "6": "32",
  12150. "7": "48"
  12151. }[node.attrs[p]] || node.attrs[p]) +
  12152. "px"
  12153. );
  12154. break;
  12155. case "color":
  12156. cssStyle.push("color:" + node.attrs[p]);
  12157. break;
  12158. case "face":
  12159. cssStyle.push("font-family:" + node.attrs[p]);
  12160. break;
  12161. case "style":
  12162. cssStyle.push(node.attrs[p]);
  12163. }
  12164. }
  12165. node.attrs = {
  12166. style: cssStyle.join(";")
  12167. };
  12168. } else {
  12169. var val = node.tagName == "u" ? "underline" : "line-through";
  12170. node.attrs = {
  12171. style: (node.getAttr("style") || "") + "text-decoration:" + val + ";"
  12172. };
  12173. }
  12174. node.tagName = "span";
  12175. });
  12176. // utils.each(root.getNodesByTagName('span'), function (node) {
  12177. // var val;
  12178. // if(val = node.getAttr('class')){
  12179. // if(/fontstrikethrough/.test(val)){
  12180. // node.setStyle('text-decoration','line-through');
  12181. // if(node.attrs['class']){
  12182. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  12183. // }else{
  12184. // node.setAttr('class')
  12185. // }
  12186. // }
  12187. // if(/fontborder/.test(val)){
  12188. // node.setStyle('border','1px solid #000');
  12189. // if(node.attrs['class']){
  12190. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  12191. // }else{
  12192. // node.setAttr('class')
  12193. // }
  12194. // }
  12195. // }
  12196. // });
  12197. });
  12198. // me.addOutputRule(function(root){
  12199. // utils.each(root.getNodesByTagName('span'), function (node) {
  12200. // var val;
  12201. // if(val = node.getStyle('text-decoration')){
  12202. // if(/line-through/.test(val)){
  12203. // if(node.attrs['class']){
  12204. // node.attrs['class'] += ' fontstrikethrough';
  12205. // }else{
  12206. // node.setAttr('class','fontstrikethrough')
  12207. // }
  12208. // }
  12209. //
  12210. // node.setStyle('text-decoration')
  12211. // }
  12212. // if(val = node.getStyle('border')){
  12213. // if(/1px/.test(val) && /solid/.test(val)){
  12214. // if(node.attrs['class']){
  12215. // node.attrs['class'] += ' fontborder';
  12216. //
  12217. // }else{
  12218. // node.setAttr('class','fontborder')
  12219. // }
  12220. // }
  12221. // node.setStyle('border')
  12222. //
  12223. // }
  12224. // });
  12225. // });
  12226. for (var p in fonts) {
  12227. (function (cmd, style) {
  12228. UE.commands[cmd] = {
  12229. execCommand: function (cmdName, value) {
  12230. value =
  12231. value ||
  12232. (this.queryCommandState(cmdName)
  12233. ? "none"
  12234. : cmdName == "underline"
  12235. ? "underline"
  12236. : cmdName == "fontborder" ? "1px solid #000" : "line-through");
  12237. var me = this,
  12238. range = this.selection.getRange(),
  12239. text;
  12240. if (value == "default") {
  12241. if (range.collapsed) {
  12242. text = me.document.createTextNode("font");
  12243. range.insertNode(text).select();
  12244. }
  12245. me.execCommand("removeFormat", "span,a", style);
  12246. if (text) {
  12247. range.setStartBefore(text).collapse(true);
  12248. domUtils.remove(text);
  12249. }
  12250. mergesibling(range, cmdName, value);
  12251. range.select();
  12252. } else {
  12253. if (!range.collapsed) {
  12254. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  12255. me.execCommand("removeFormat", "span,a", style);
  12256. }
  12257. range = me.selection.getRange();
  12258. range.applyInlineStyle("span", {style: style + ":" + value});
  12259. mergesibling(range, cmdName, value);
  12260. range.select();
  12261. } else {
  12262. var span = domUtils.findParentByTagName(
  12263. range.startContainer,
  12264. "span",
  12265. true
  12266. );
  12267. text = me.document.createTextNode("font");
  12268. if (
  12269. span &&
  12270. !span.children.length &&
  12271. !span[browser.ie ? "innerText" : "textContent"].replace(
  12272. fillCharReg,
  12273. ""
  12274. ).length
  12275. ) {
  12276. //for ie hack when enter
  12277. range.insertNode(text);
  12278. if (needCmd[cmd]) {
  12279. range.selectNode(text).select();
  12280. me.execCommand("removeFormat", "span,a", style, null);
  12281. span = domUtils.findParentByTagName(text, "span", true);
  12282. range.setStartBefore(text);
  12283. }
  12284. span && (span.style.cssText += ";" + style + ":" + value);
  12285. range.collapse(true).select();
  12286. } else {
  12287. range.insertNode(text);
  12288. range.selectNode(text).select();
  12289. span = range.document.createElement("span");
  12290. if (needCmd[cmd]) {
  12291. //a标签内的不处理跳过
  12292. if (domUtils.findParentByTagName(text, "a", true)) {
  12293. range.setStartBefore(text).setCursor();
  12294. domUtils.remove(text);
  12295. return;
  12296. }
  12297. me.execCommand("removeFormat", "span,a", style);
  12298. }
  12299. span.style.cssText = style + ":" + value;
  12300. text.parentNode.insertBefore(span, text);
  12301. //修复,span套span 但样式不继承的问题
  12302. if (!browser.ie || (browser.ie && browser.version == 9)) {
  12303. var spanParent = span.parentNode;
  12304. while (!domUtils.isBlockElm(spanParent)) {
  12305. if (spanParent.tagName == "SPAN") {
  12306. //opera合并style不会加入";"
  12307. span.style.cssText =
  12308. spanParent.style.cssText + ";" + span.style.cssText;
  12309. }
  12310. spanParent = spanParent.parentNode;
  12311. }
  12312. }
  12313. if (opera) {
  12314. setTimeout(function () {
  12315. range.setStart(span, 0).collapse(true);
  12316. mergesibling(range, cmdName, value);
  12317. range.select();
  12318. });
  12319. } else {
  12320. range.setStart(span, 0).collapse(true);
  12321. mergesibling(range, cmdName, value);
  12322. range.select();
  12323. }
  12324. //trace:981
  12325. //domUtils.mergeToParent(span)
  12326. }
  12327. domUtils.remove(text);
  12328. }
  12329. }
  12330. return true;
  12331. },
  12332. queryCommandValue: function (cmdName) {
  12333. var startNode = this.selection.getStart();
  12334. //trace:946
  12335. if (cmdName == "underline" || cmdName == "strikethrough") {
  12336. var tmpNode = startNode,
  12337. value;
  12338. while (
  12339. tmpNode &&
  12340. !domUtils.isBlockElm(tmpNode) &&
  12341. !domUtils.isBody(tmpNode)
  12342. ) {
  12343. if (tmpNode.nodeType == 1) {
  12344. value = domUtils.getComputedStyle(tmpNode, style);
  12345. if (value != "none") {
  12346. return value;
  12347. }
  12348. }
  12349. tmpNode = tmpNode.parentNode;
  12350. }
  12351. return "none";
  12352. }
  12353. if (cmdName == "fontborder") {
  12354. var tmp = startNode,
  12355. val;
  12356. while (tmp && dtd.$inline[tmp.tagName]) {
  12357. if ((val = domUtils.getComputedStyle(tmp, "border"))) {
  12358. if (/1px/.test(val) && /solid/.test(val)) {
  12359. return val;
  12360. }
  12361. }
  12362. tmp = tmp.parentNode;
  12363. }
  12364. return "";
  12365. }
  12366. if (cmdName == "FontSize") {
  12367. var styleVal = domUtils.getComputedStyle(startNode, style),
  12368. tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);
  12369. if (tmp) {
  12370. return Math.floor(tmp[1]) + tmp[2];
  12371. }
  12372. return styleVal;
  12373. }
  12374. return domUtils.getComputedStyle(startNode, style);
  12375. },
  12376. queryCommandState: function (cmdName) {
  12377. if (!needCmd[cmdName]) return 0;
  12378. var val = this.queryCommandValue(cmdName);
  12379. if (cmdName == "fontborder") {
  12380. return /1px/.test(val) && /solid/.test(val);
  12381. } else {
  12382. return cmdName == "underline"
  12383. ? /underline/.test(val)
  12384. : /line\-through/.test(val);
  12385. }
  12386. }
  12387. };
  12388. })(p, fonts[p]);
  12389. }
  12390. };
  12391. // plugins/link.js
  12392. /**
  12393. * 超链接
  12394. * @file
  12395. * @since 1.2.6.1
  12396. */
  12397. /**
  12398. * 插入超链接
  12399. * @command link
  12400. * @method execCommand
  12401. * @param { String } cmd 命令字符串
  12402. * @param { Object } options 设置自定义属性,例如:url、title、target
  12403. * @example
  12404. * ```javascript
  12405. * editor.execCommand( 'link', '{
  12406. * url:'neditor.baidu.com',
  12407. * title:'neditor',
  12408. * target:'_blank'
  12409. * }' );
  12410. * ```
  12411. */
  12412. /**
  12413. * 返回当前选中的第一个超链接节点
  12414. * @command link
  12415. * @method queryCommandValue
  12416. * @param { String } cmd 命令字符串
  12417. * @return { Element } 超链接节点
  12418. * @example
  12419. * ```javascript
  12420. * editor.queryCommandValue( 'link' );
  12421. * ```
  12422. */
  12423. /**
  12424. * 取消超链接
  12425. * @command unlink
  12426. * @method execCommand
  12427. * @param { String } cmd 命令字符串
  12428. * @example
  12429. * ```javascript
  12430. * editor.execCommand( 'unlink');
  12431. * ```
  12432. */
  12433. UE.plugins["link"] = function () {
  12434. function optimize(range) {
  12435. var start = range.startContainer,
  12436. end = range.endContainer;
  12437. if ((start = domUtils.findParentByTagName(start, "a", true))) {
  12438. range.setStartBefore(start);
  12439. }
  12440. if ((end = domUtils.findParentByTagName(end, "a", true))) {
  12441. range.setEndAfter(end);
  12442. }
  12443. }
  12444. UE.commands["unlink"] = {
  12445. execCommand: function () {
  12446. var range = this.selection.getRange(),
  12447. bookmark;
  12448. if (
  12449. range.collapsed &&
  12450. !domUtils.findParentByTagName(range.startContainer, "a", true)
  12451. ) {
  12452. return;
  12453. }
  12454. bookmark = range.createBookmark();
  12455. optimize(range);
  12456. range.removeInlineStyle("a").moveToBookmark(bookmark).select();
  12457. },
  12458. queryCommandState: function () {
  12459. return !this.highlight && this.queryCommandValue("link") ? 0 : -1;
  12460. }
  12461. };
  12462. function doLink(range, opt, me) {
  12463. var rngClone = range.cloneRange(),
  12464. link = me.queryCommandValue("link");
  12465. optimize((range = range.adjustmentBoundary()));
  12466. var start = range.startContainer;
  12467. if (start.nodeType == 1 && link) {
  12468. start = start.childNodes[range.startOffset];
  12469. if (
  12470. start &&
  12471. start.nodeType == 1 &&
  12472. start.tagName == "A" &&
  12473. /^(?:https?|ftp|file)\s*:\s*\/\//.test(
  12474. start[browser.ie ? "innerText" : "textContent"]
  12475. )
  12476. ) {
  12477. start[browser.ie ? "innerText" : "textContent"] = utils.html(
  12478. opt.textValue || opt.href
  12479. );
  12480. }
  12481. }
  12482. if (!rngClone.collapsed || link) {
  12483. range.removeInlineStyle("a");
  12484. rngClone = range.cloneRange();
  12485. }
  12486. if (rngClone.collapsed) {
  12487. var a = range.document.createElement("a"),
  12488. text = "";
  12489. if (opt.textValue) {
  12490. text = utils.html(opt.textValue);
  12491. delete opt.textValue;
  12492. } else {
  12493. text = utils.html(opt.href);
  12494. }
  12495. domUtils.setAttributes(a, opt);
  12496. start = domUtils.findParentByTagName(rngClone.startContainer, "a", true);
  12497. if (start && domUtils.isInNodeEndBoundary(rngClone, start)) {
  12498. range.setStartAfter(start).collapse(true);
  12499. }
  12500. a[browser.ie ? "innerText" : "textContent"] = text;
  12501. range.insertNode(a).selectNode(a);
  12502. } else {
  12503. range.applyInlineStyle("a", opt);
  12504. }
  12505. }
  12506. UE.commands["link"] = {
  12507. execCommand: function (cmdName, opt) {
  12508. var range;
  12509. opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g));
  12510. opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g));
  12511. opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g));
  12512. doLink((range = this.selection.getRange()), opt, this);
  12513. //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
  12514. range.collapse().select(true);
  12515. },
  12516. queryCommandValue: function () {
  12517. var range = this.selection.getRange(),
  12518. node;
  12519. if (range.collapsed) {
  12520. // node = this.selection.getStart();
  12521. //在ie下getstart()取值偏上了
  12522. node = range.startContainer;
  12523. node = node.nodeType == 1 ? node : node.parentNode;
  12524. if (
  12525. node &&
  12526. (node = domUtils.findParentByTagName(node, "a", true)) &&
  12527. !domUtils.isInNodeEndBoundary(range, node)
  12528. ) {
  12529. return node;
  12530. }
  12531. } else {
  12532. //trace:1111 如果是<p><a>xx</a></p> startContainer是p就会找不到a
  12533. range.shrinkBoundary();
  12534. var start = range.startContainer.nodeType == 3 ||
  12535. !range.startContainer.childNodes[range.startOffset]
  12536. ? range.startContainer
  12537. : range.startContainer.childNodes[range.startOffset],
  12538. end = range.endContainer.nodeType == 3 || range.endOffset == 0
  12539. ? range.endContainer
  12540. : range.endContainer.childNodes[range.endOffset - 1],
  12541. common = range.getCommonAncestor();
  12542. node = domUtils.findParentByTagName(common, "a", true);
  12543. if (!node && common.nodeType == 1) {
  12544. var as = common.getElementsByTagName("a"),
  12545. ps,
  12546. pe;
  12547. for (var i = 0, ci; (ci = as[i++]);) {
  12548. (ps = domUtils.getPosition(ci, start)), (pe = domUtils.getPosition(
  12549. ci,
  12550. end
  12551. ));
  12552. if (
  12553. (ps & domUtils.POSITION_FOLLOWING ||
  12554. ps & domUtils.POSITION_CONTAINS) &&
  12555. (pe & domUtils.POSITION_PRECEDING ||
  12556. pe & domUtils.POSITION_CONTAINS)
  12557. ) {
  12558. node = ci;
  12559. break;
  12560. }
  12561. }
  12562. }
  12563. return node;
  12564. }
  12565. },
  12566. queryCommandState: function () {
  12567. //判断如果是视频的话连接不可用
  12568. //fix 853
  12569. var img = this.selection.getRange().getClosedNode(),
  12570. flag =
  12571. img &&
  12572. (img.className == "edui-faked-video" ||
  12573. img.className.indexOf("edui-upload-video") != -1);
  12574. return flag ? -1 : 0;
  12575. }
  12576. };
  12577. };
  12578. // plugins/iframe.js
  12579. ///import core
  12580. ///import plugins\inserthtml.js
  12581. ///commands 插入框架
  12582. ///commandsName InsertFrame
  12583. ///commandsTitle 插入Iframe
  12584. ///commandsDialog dialogs\insertframe
  12585. UE.plugins["insertframe"] = function () {
  12586. var me = this;
  12587. function deleteIframe() {
  12588. me._iframe && delete me._iframe;
  12589. }
  12590. me.addListener("selectionchange", function () {
  12591. deleteIframe();
  12592. });
  12593. };
  12594. // plugins/scrawl.js
  12595. ///import core
  12596. ///commands 涂鸦
  12597. ///commandsName Scrawl
  12598. ///commandsTitle 涂鸦
  12599. ///commandsDialog dialogs\scrawl
  12600. UE.commands["scrawl"] = {
  12601. queryCommandState: function () {
  12602. return browser.ie && browser.version <= 8 ? -1 : 0;
  12603. }
  12604. };
  12605. // plugins/removeformat.js
  12606. /**
  12607. * 清除格式
  12608. * @file
  12609. * @since 1.2.6.1
  12610. */
  12611. /**
  12612. * 清除文字样式
  12613. * @command removeformat
  12614. * @method execCommand
  12615. * @param { String } cmd 命令字符串
  12616. * @param {String} tags 以逗号隔开的标签。如:strong
  12617. * @param {String} style 样式如:color
  12618. * @param {String} attrs 属性如:width
  12619. * @example
  12620. * ```javascript
  12621. * editor.execCommand( 'removeformat', 'strong','color','width' );
  12622. * ```
  12623. */
  12624. UE.plugins["removeformat"] = function () {
  12625. var me = this;
  12626. me.setOpt({
  12627. removeFormatTags:
  12628. "b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var",
  12629. removeFormatAttributes: "class,style,lang,width,height,align,hspace,valign"
  12630. });
  12631. me.commands["removeformat"] = {
  12632. execCommand: function (cmdName, tags, style, attrs, notIncludeA) {
  12633. var tagReg = new RegExp(
  12634. "^(?:" +
  12635. (tags || this.options.removeFormatTags).replace(/,/g, "|") +
  12636. ")$",
  12637. "i"
  12638. ),
  12639. removeFormatAttributes = style
  12640. ? []
  12641. : (attrs || this.options.removeFormatAttributes).split(","),
  12642. range = new dom.Range(this.document),
  12643. bookmark,
  12644. node,
  12645. parent,
  12646. filter = function (node) {
  12647. return node.nodeType == 1;
  12648. };
  12649. function isRedundantSpan(node) {
  12650. if (node.nodeType == 3 || node.tagName.toLowerCase() != "span") {
  12651. return 0;
  12652. }
  12653. if (browser.ie) {
  12654. //ie 下判断实效,所以只能简单用style来判断
  12655. //return node.style.cssText == '' ? 1 : 0;
  12656. var attrs = node.attributes;
  12657. if (attrs.length) {
  12658. for (var i = 0, l = attrs.length; i < l; i++) {
  12659. if (attrs[i].specified) {
  12660. return 0;
  12661. }
  12662. }
  12663. return 1;
  12664. }
  12665. }
  12666. return !node.attributes.length;
  12667. }
  12668. function doRemove(range) {
  12669. var bookmark1 = range.createBookmark();
  12670. if (range.collapsed) {
  12671. range.enlarge(true);
  12672. }
  12673. //不能把a标签切了
  12674. if (!notIncludeA) {
  12675. var aNode = domUtils.findParentByTagName(
  12676. range.startContainer,
  12677. "a",
  12678. true
  12679. );
  12680. if (aNode) {
  12681. range.setStartBefore(aNode);
  12682. }
  12683. aNode = domUtils.findParentByTagName(range.endContainer, "a", true);
  12684. if (aNode) {
  12685. range.setEndAfter(aNode);
  12686. }
  12687. }
  12688. bookmark = range.createBookmark();
  12689. node = bookmark.start;
  12690. //切开始
  12691. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  12692. domUtils.breakParent(node, parent);
  12693. domUtils.clearEmptySibling(node);
  12694. }
  12695. if (bookmark.end) {
  12696. //切结束
  12697. node = bookmark.end;
  12698. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  12699. domUtils.breakParent(node, parent);
  12700. domUtils.clearEmptySibling(node);
  12701. }
  12702. //开始去除样式
  12703. var current = domUtils.getNextDomNode(bookmark.start, false, filter),
  12704. next;
  12705. while (current) {
  12706. if (current == bookmark.end) {
  12707. break;
  12708. }
  12709. next = domUtils.getNextDomNode(current, true, filter);
  12710. if (
  12711. !dtd.$empty[current.tagName.toLowerCase()] &&
  12712. !domUtils.isBookmarkNode(current)
  12713. ) {
  12714. if (tagReg.test(current.tagName)) {
  12715. if (style) {
  12716. domUtils.removeStyle(current, style);
  12717. if (isRedundantSpan(current) && style != "text-decoration") {
  12718. domUtils.remove(current, true);
  12719. }
  12720. } else {
  12721. domUtils.remove(current, true);
  12722. }
  12723. } else {
  12724. //trace:939 不能把list上的样式去掉
  12725. if (
  12726. !dtd.$tableContent[current.tagName] &&
  12727. !dtd.$list[current.tagName]
  12728. ) {
  12729. domUtils.removeAttributes(current, removeFormatAttributes);
  12730. if (isRedundantSpan(current)) {
  12731. domUtils.remove(current, true);
  12732. }
  12733. }
  12734. }
  12735. }
  12736. current = next;
  12737. }
  12738. }
  12739. //trace:1035
  12740. //trace:1096 不能把td上的样式去掉,比如边框
  12741. var pN = bookmark.start.parentNode;
  12742. if (
  12743. domUtils.isBlockElm(pN) &&
  12744. !dtd.$tableContent[pN.tagName] &&
  12745. !dtd.$list[pN.tagName]
  12746. ) {
  12747. domUtils.removeAttributes(pN, removeFormatAttributes);
  12748. }
  12749. pN = bookmark.end.parentNode;
  12750. if (
  12751. bookmark.end &&
  12752. domUtils.isBlockElm(pN) &&
  12753. !dtd.$tableContent[pN.tagName] &&
  12754. !dtd.$list[pN.tagName]
  12755. ) {
  12756. domUtils.removeAttributes(pN, removeFormatAttributes);
  12757. }
  12758. range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
  12759. //清除冗余的代码 <b><bookmark></b>
  12760. var node = range.startContainer,
  12761. tmp,
  12762. collapsed = range.collapsed;
  12763. while (
  12764. node.nodeType == 1 &&
  12765. domUtils.isEmptyNode(node) &&
  12766. dtd.$removeEmpty[node.tagName]
  12767. ) {
  12768. tmp = node.parentNode;
  12769. range.setStartBefore(node);
  12770. //trace:937
  12771. //更新结束边界
  12772. if (range.startContainer === range.endContainer) {
  12773. range.endOffset--;
  12774. }
  12775. domUtils.remove(node);
  12776. node = tmp;
  12777. }
  12778. if (!collapsed) {
  12779. node = range.endContainer;
  12780. while (
  12781. node.nodeType == 1 &&
  12782. domUtils.isEmptyNode(node) &&
  12783. dtd.$removeEmpty[node.tagName]
  12784. ) {
  12785. tmp = node.parentNode;
  12786. range.setEndBefore(node);
  12787. domUtils.remove(node);
  12788. node = tmp;
  12789. }
  12790. }
  12791. }
  12792. range = this.selection.getRange();
  12793. doRemove(range);
  12794. range.select();
  12795. }
  12796. };
  12797. };
  12798. // plugins/blockquote.js
  12799. /**
  12800. * 添加引用
  12801. * @file
  12802. * @since 1.2.6.1
  12803. */
  12804. /**
  12805. * 添加引用
  12806. * @command blockquote
  12807. * @method execCommand
  12808. * @param { String } cmd 命令字符串
  12809. * @example
  12810. * ```javascript
  12811. * editor.execCommand( 'blockquote' );
  12812. * ```
  12813. */
  12814. /**
  12815. * 添加引用
  12816. * @command blockquote
  12817. * @method execCommand
  12818. * @param { String } cmd 命令字符串
  12819. * @param { Object } attrs 节点属性
  12820. * @example
  12821. * ```javascript
  12822. * editor.execCommand( 'blockquote',{
  12823. * style: "color: red;"
  12824. * } );
  12825. * ```
  12826. */
  12827. UE.plugins["blockquote"] = function () {
  12828. var me = this;
  12829. function getObj(editor) {
  12830. return domUtils.filterNodeList(
  12831. editor.selection.getStartElementPath(),
  12832. "blockquote"
  12833. );
  12834. }
  12835. me.commands["blockquote"] = {
  12836. execCommand: function (cmdName, attrs) {
  12837. var range = this.selection.getRange(),
  12838. obj = getObj(this),
  12839. blockquote = dtd.blockquote,
  12840. bookmark = range.createBookmark();
  12841. if (obj) {
  12842. var start = range.startContainer,
  12843. startBlock = domUtils.isBlockElm(start)
  12844. ? start
  12845. : domUtils.findParent(start, function (node) {
  12846. return domUtils.isBlockElm(node);
  12847. }),
  12848. end = range.endContainer,
  12849. endBlock = domUtils.isBlockElm(end)
  12850. ? end
  12851. : domUtils.findParent(end, function (node) {
  12852. return domUtils.isBlockElm(node);
  12853. });
  12854. //处理一下li
  12855. startBlock =
  12856. domUtils.findParentByTagName(startBlock, "li", true) || startBlock;
  12857. endBlock =
  12858. domUtils.findParentByTagName(endBlock, "li", true) || endBlock;
  12859. if (
  12860. startBlock.tagName == "LI" ||
  12861. startBlock.tagName == "TD" ||
  12862. startBlock === obj ||
  12863. domUtils.isBody(startBlock)
  12864. ) {
  12865. domUtils.remove(obj, true);
  12866. } else {
  12867. domUtils.breakParent(startBlock, obj);
  12868. }
  12869. if (startBlock !== endBlock) {
  12870. obj = domUtils.findParentByTagName(endBlock, "blockquote");
  12871. if (obj) {
  12872. if (
  12873. endBlock.tagName == "LI" ||
  12874. endBlock.tagName == "TD" ||
  12875. domUtils.isBody(endBlock)
  12876. ) {
  12877. obj.parentNode && domUtils.remove(obj, true);
  12878. } else {
  12879. domUtils.breakParent(endBlock, obj);
  12880. }
  12881. }
  12882. }
  12883. var blockquotes = domUtils.getElementsByTagName(
  12884. this.document,
  12885. "blockquote"
  12886. );
  12887. for (var i = 0, bi; (bi = blockquotes[i++]);) {
  12888. if (!bi.childNodes.length) {
  12889. domUtils.remove(bi);
  12890. } else if (
  12891. domUtils.getPosition(bi, startBlock) &
  12892. domUtils.POSITION_FOLLOWING &&
  12893. domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING
  12894. ) {
  12895. domUtils.remove(bi, true);
  12896. }
  12897. }
  12898. } else {
  12899. var tmpRange = range.cloneRange(),
  12900. node = tmpRange.startContainer.nodeType == 1
  12901. ? tmpRange.startContainer
  12902. : tmpRange.startContainer.parentNode,
  12903. preNode = node,
  12904. doEnd = 1;
  12905. //调整开始
  12906. while (1) {
  12907. if (domUtils.isBody(node)) {
  12908. if (preNode !== node) {
  12909. if (range.collapsed) {
  12910. tmpRange.selectNode(preNode);
  12911. doEnd = 0;
  12912. } else {
  12913. tmpRange.setStartBefore(preNode);
  12914. }
  12915. } else {
  12916. tmpRange.setStart(node, 0);
  12917. }
  12918. break;
  12919. }
  12920. if (!blockquote[node.tagName]) {
  12921. if (range.collapsed) {
  12922. tmpRange.selectNode(preNode);
  12923. } else {
  12924. tmpRange.setStartBefore(preNode);
  12925. }
  12926. break;
  12927. }
  12928. preNode = node;
  12929. node = node.parentNode;
  12930. }
  12931. //调整结束
  12932. if (doEnd) {
  12933. preNode = node = node = tmpRange.endContainer.nodeType == 1
  12934. ? tmpRange.endContainer
  12935. : tmpRange.endContainer.parentNode;
  12936. while (1) {
  12937. if (domUtils.isBody(node)) {
  12938. if (preNode !== node) {
  12939. tmpRange.setEndAfter(preNode);
  12940. } else {
  12941. tmpRange.setEnd(node, node.childNodes.length);
  12942. }
  12943. break;
  12944. }
  12945. if (!blockquote[node.tagName]) {
  12946. tmpRange.setEndAfter(preNode);
  12947. break;
  12948. }
  12949. preNode = node;
  12950. node = node.parentNode;
  12951. }
  12952. }
  12953. node = range.document.createElement("blockquote");
  12954. domUtils.setAttributes(node, attrs);
  12955. node.appendChild(tmpRange.extractContents());
  12956. tmpRange.insertNode(node);
  12957. //去除重复的
  12958. var childs = domUtils.getElementsByTagName(node, "blockquote");
  12959. for (var i = 0, ci; (ci = childs[i++]);) {
  12960. if (ci.parentNode) {
  12961. domUtils.remove(ci, true);
  12962. }
  12963. }
  12964. }
  12965. range.moveToBookmark(bookmark).select();
  12966. },
  12967. queryCommandState: function () {
  12968. return getObj(this) ? 1 : 0;
  12969. }
  12970. };
  12971. };
  12972. // plugins/convertcase.js
  12973. /**
  12974. * 大小写转换
  12975. * @file
  12976. * @since 1.2.6.1
  12977. */
  12978. /**
  12979. * 把选区内文本变大写,与“tolowercase”命令互斥
  12980. * @command touppercase
  12981. * @method execCommand
  12982. * @param { String } cmd 命令字符串
  12983. * @example
  12984. * ```javascript
  12985. * editor.execCommand( 'touppercase' );
  12986. * ```
  12987. */
  12988. /**
  12989. * 把选区内文本变小写,与“touppercase”命令互斥
  12990. * @command tolowercase
  12991. * @method execCommand
  12992. * @param { String } cmd 命令字符串
  12993. * @example
  12994. * ```javascript
  12995. * editor.execCommand( 'tolowercase' );
  12996. * ```
  12997. */
  12998. UE.commands["touppercase"] = UE.commands["tolowercase"] = {
  12999. execCommand: function (cmd) {
  13000. var me = this;
  13001. var rng = me.selection.getRange();
  13002. if (rng.collapsed) {
  13003. return rng;
  13004. }
  13005. var bk = rng.createBookmark(),
  13006. bkEnd = bk.end,
  13007. filterFn = function (node) {
  13008. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  13009. },
  13010. curNode = domUtils.getNextDomNode(bk.start, false, filterFn);
  13011. while (
  13012. curNode &&
  13013. domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING
  13014. ) {
  13015. if (curNode.nodeType == 3) {
  13016. curNode.nodeValue = curNode.nodeValue[
  13017. cmd == "touppercase" ? "toUpperCase" : "toLowerCase"
  13018. ]();
  13019. }
  13020. curNode = domUtils.getNextDomNode(curNode, true, filterFn);
  13021. if (curNode === bkEnd) {
  13022. break;
  13023. }
  13024. }
  13025. rng.moveToBookmark(bk).select();
  13026. }
  13027. };
  13028. // plugins/indent.js
  13029. /**
  13030. * 首行缩进
  13031. * @file
  13032. * @since 1.2.6.1
  13033. */
  13034. /**
  13035. * 缩进
  13036. * @command indent
  13037. * @method execCommand
  13038. * @param { String } cmd 命令字符串
  13039. * @example
  13040. * ```javascript
  13041. * editor.execCommand( 'indent' );
  13042. * ```
  13043. */
  13044. UE.commands["indent"] = {
  13045. execCommand: function () {
  13046. var me = this,
  13047. value = me.queryCommandState("indent")
  13048. ? "0em"
  13049. : me.options.indentValue || "2em";
  13050. me.execCommand("Paragraph", "p", {style: "text-indent:" + value});
  13051. },
  13052. queryCommandState: function () {
  13053. var pN = domUtils.filterNodeList(
  13054. this.selection.getStartElementPath(),
  13055. "p h1 h2 h3 h4 h5 h6"
  13056. );
  13057. return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
  13058. }
  13059. };
  13060. // plugins/print.js
  13061. /**
  13062. * 打印
  13063. * @file
  13064. * @since 1.2.6.1
  13065. */
  13066. /**
  13067. * 打印
  13068. * @command print
  13069. * @method execCommand
  13070. * @param { String } cmd 命令字符串
  13071. * @example
  13072. * ```javascript
  13073. * editor.execCommand( 'print' );
  13074. * ```
  13075. */
  13076. UE.commands["print"] = {
  13077. execCommand: function () {
  13078. this.window.print();
  13079. },
  13080. notNeedUndo: 1
  13081. };
  13082. // plugins/preview.js
  13083. /**
  13084. * 预览
  13085. * @file
  13086. * @since 1.2.6.1
  13087. */
  13088. /**
  13089. * 预览
  13090. * @command preview
  13091. * @method execCommand
  13092. * @param { String } cmd 命令字符串
  13093. * @example
  13094. * ```javascript
  13095. * editor.execCommand( 'preview' );
  13096. * ```
  13097. */
  13098. UE.commands["preview"] = {
  13099. execCommand: function () {
  13100. var w = window.open("", "_blank", ""),
  13101. d = w.document;
  13102. d.open();
  13103. d.write(
  13104. '<!DOCTYPE html><html><head><meta charset="utf-8"/><script src="' +
  13105. this.options.UEDITOR_HOME_URL +
  13106. 'neditor.parse.js"></script><script>' +
  13107. "setTimeout(function(){uParse('div',{rootPath: '" +
  13108. this.options.UEDITOR_HOME_URL +
  13109. "'})},300)" +
  13110. "</script></head><body><div>" +
  13111. this.getContent(null, null, true) +
  13112. "</div></body></html>"
  13113. );
  13114. d.close();
  13115. },
  13116. notNeedUndo: 1
  13117. };
  13118. // plugins/selectall.js
  13119. /**
  13120. * 全选
  13121. * @file
  13122. * @since 1.2.6.1
  13123. */
  13124. /**
  13125. * 选中所有内容
  13126. * @command selectall
  13127. * @method execCommand
  13128. * @param { String } cmd 命令字符串
  13129. * @example
  13130. * ```javascript
  13131. * editor.execCommand( 'selectall' );
  13132. * ```
  13133. */
  13134. UE.plugins["selectall"] = function () {
  13135. var me = this;
  13136. me.commands["selectall"] = {
  13137. execCommand: function () {
  13138. //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
  13139. var me = this,
  13140. body = me.body,
  13141. range = me.selection.getRange();
  13142. range.selectNodeContents(body);
  13143. if (domUtils.isEmptyBlock(body)) {
  13144. //opera不能自动合并到元素的里边,要手动处理一下
  13145. if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
  13146. range.setStartAtFirst(body.firstChild);
  13147. }
  13148. range.collapse(true);
  13149. }
  13150. range.select(true);
  13151. },
  13152. notNeedUndo: 1
  13153. };
  13154. //快捷键
  13155. me.addshortcutkey({
  13156. selectAll: "ctrl+65"
  13157. });
  13158. };
  13159. // plugins/paragraph.js
  13160. /**
  13161. * 段落样式
  13162. * @file
  13163. * @since 1.2.6.1
  13164. */
  13165. /**
  13166. * 段落格式
  13167. * @command paragraph
  13168. * @method execCommand
  13169. * @param { String } cmd 命令字符串
  13170. * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
  13171. * @param {Object} attrs 标签的属性
  13172. * @example
  13173. * ```javascript
  13174. * editor.execCommand( 'Paragraph','h1','{
  13175. * class:'test'
  13176. * }' );
  13177. * ```
  13178. */
  13179. /**
  13180. * 返回选区内节点标签名
  13181. * @command paragraph
  13182. * @method queryCommandValue
  13183. * @param { String } cmd 命令字符串
  13184. * @return { String } 节点标签名
  13185. * @example
  13186. * ```javascript
  13187. * editor.queryCommandValue( 'Paragraph' );
  13188. * ```
  13189. */
  13190. UE.plugins["paragraph"] = function () {
  13191. var me = this,
  13192. block = domUtils.isBlockElm,
  13193. notExchange = ["TD", "LI", "PRE"],
  13194. doParagraph = function (range, style, attrs, sourceCmdName) {
  13195. var bookmark = range.createBookmark(),
  13196. filterFn = function (node) {
  13197. return node.nodeType == 1
  13198. ? node.tagName.toLowerCase() != "br" &&
  13199. !domUtils.isBookmarkNode(node)
  13200. : !domUtils.isWhitespace(node);
  13201. },
  13202. para;
  13203. range.enlarge(true);
  13204. var bookmark2 = range.createBookmark(),
  13205. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  13206. tmpRange = range.cloneRange(),
  13207. tmpNode;
  13208. while (
  13209. current &&
  13210. !(
  13211. domUtils.getPosition(current, bookmark2.end) &
  13212. domUtils.POSITION_FOLLOWING
  13213. )
  13214. ) {
  13215. if (current.nodeType == 3 || !block(current)) {
  13216. tmpRange.setStartBefore(current);
  13217. while (current && current !== bookmark2.end && !block(current)) {
  13218. tmpNode = current;
  13219. current = domUtils.getNextDomNode(current, false, null, function (
  13220. node
  13221. ) {
  13222. return !block(node);
  13223. });
  13224. }
  13225. tmpRange.setEndAfter(tmpNode);
  13226. para = range.document.createElement(style);
  13227. if (attrs) {
  13228. domUtils.setAttributes(para, attrs);
  13229. if (
  13230. sourceCmdName &&
  13231. sourceCmdName == "customstyle" &&
  13232. attrs.style
  13233. ) {
  13234. para.style.cssText = attrs.style;
  13235. }
  13236. }
  13237. para.appendChild(tmpRange.extractContents());
  13238. //需要内容占位
  13239. if (domUtils.isEmptyNode(para)) {
  13240. domUtils.fillChar(range.document, para);
  13241. }
  13242. tmpRange.insertNode(para);
  13243. var parent = para.parentNode;
  13244. //如果para上一级是一个block元素且不是body,td就删除它
  13245. if (
  13246. block(parent) &&
  13247. !domUtils.isBody(para.parentNode) &&
  13248. utils.indexOf(notExchange, parent.tagName) == -1
  13249. ) {
  13250. //存储dir,style
  13251. if (!(sourceCmdName && sourceCmdName == "customstyle")) {
  13252. parent.getAttribute("dir") &&
  13253. para.setAttribute("dir", parent.getAttribute("dir"));
  13254. //trace:1070
  13255. parent.style.cssText &&
  13256. (para.style.cssText =
  13257. parent.style.cssText + ";" + para.style.cssText);
  13258. //trace:1030
  13259. parent.style.textAlign &&
  13260. !para.style.textAlign &&
  13261. (para.style.textAlign = parent.style.textAlign);
  13262. parent.style.textIndent &&
  13263. !para.style.textIndent &&
  13264. (para.style.textIndent = parent.style.textIndent);
  13265. parent.style.padding &&
  13266. !para.style.padding &&
  13267. (para.style.padding = parent.style.padding);
  13268. }
  13269. //trace:1706 选择的就是h1-6要删除
  13270. if (
  13271. attrs &&
  13272. /h\d/i.test(parent.tagName) &&
  13273. !/h\d/i.test(para.tagName)
  13274. ) {
  13275. domUtils.setAttributes(parent, attrs);
  13276. if (
  13277. sourceCmdName &&
  13278. sourceCmdName == "customstyle" &&
  13279. attrs.style
  13280. ) {
  13281. parent.style.cssText = attrs.style;
  13282. }
  13283. domUtils.remove(para.parentNode, true);
  13284. para = parent;
  13285. } else {
  13286. domUtils.remove(para.parentNode, true);
  13287. }
  13288. }
  13289. if (utils.indexOf(notExchange, parent.tagName) != -1) {
  13290. current = parent;
  13291. } else {
  13292. current = para;
  13293. }
  13294. current = domUtils.getNextDomNode(current, false, filterFn);
  13295. } else {
  13296. current = domUtils.getNextDomNode(current, true, filterFn);
  13297. }
  13298. }
  13299. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  13300. };
  13301. me.setOpt("paragraph", {
  13302. p: "",
  13303. h1: "",
  13304. h2: "",
  13305. h3: "",
  13306. h4: "",
  13307. h5: "",
  13308. h6: ""
  13309. });
  13310. me.commands["paragraph"] = {
  13311. execCommand: function (cmdName, style, attrs, sourceCmdName) {
  13312. var range = this.selection.getRange();
  13313. //闭合时单独处理
  13314. if (range.collapsed) {
  13315. var txt = this.document.createTextNode("p");
  13316. range.insertNode(txt);
  13317. //去掉冗余的fillchar
  13318. if (browser.ie) {
  13319. var node = txt.previousSibling;
  13320. if (node && domUtils.isWhitespace(node)) {
  13321. domUtils.remove(node);
  13322. }
  13323. node = txt.nextSibling;
  13324. if (node && domUtils.isWhitespace(node)) {
  13325. domUtils.remove(node);
  13326. }
  13327. }
  13328. }
  13329. range = doParagraph(range, style, attrs, sourceCmdName);
  13330. if (txt) {
  13331. range.setStartBefore(txt).collapse(true);
  13332. pN = txt.parentNode;
  13333. domUtils.remove(txt);
  13334. if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
  13335. domUtils.fillNode(this.document, pN);
  13336. }
  13337. }
  13338. if (
  13339. browser.gecko &&
  13340. range.collapsed &&
  13341. range.startContainer.nodeType == 1
  13342. ) {
  13343. var child = range.startContainer.childNodes[range.startOffset];
  13344. if (
  13345. child &&
  13346. child.nodeType == 1 &&
  13347. child.tagName.toLowerCase() == style
  13348. ) {
  13349. range.setStart(child, 0).collapse(true);
  13350. }
  13351. }
  13352. //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
  13353. range.select();
  13354. return true;
  13355. },
  13356. queryCommandValue: function () {
  13357. var node = domUtils.filterNodeList(
  13358. this.selection.getStartElementPath(),
  13359. "p h1 h2 h3 h4 h5 h6"
  13360. );
  13361. return node ? node.tagName.toLowerCase() : "";
  13362. }
  13363. };
  13364. };
  13365. // plugins/directionality.js
  13366. /**
  13367. * 设置文字输入的方向的插件
  13368. * @file
  13369. * @since 1.2.6.1
  13370. */
  13371. ;(function () {
  13372. var block = domUtils.isBlockElm,
  13373. getObj = function (editor) {
  13374. // var startNode = editor.selection.getStart(),
  13375. // parents;
  13376. // if ( startNode ) {
  13377. // //查找所有的是block的父亲节点
  13378. // parents = domUtils.findParents( startNode, true, block, true );
  13379. // for ( var i = 0,ci; ci = parents[i++]; ) {
  13380. // if ( ci.getAttribute( 'dir' ) ) {
  13381. // return ci;
  13382. // }
  13383. // }
  13384. // }
  13385. return domUtils.filterNodeList(
  13386. editor.selection.getStartElementPath(),
  13387. function (n) {
  13388. return n && n.nodeType == 1 && n.getAttribute("dir");
  13389. }
  13390. );
  13391. },
  13392. doDirectionality = function (range, editor, forward) {
  13393. var bookmark,
  13394. filterFn = function (node) {
  13395. return node.nodeType == 1
  13396. ? !domUtils.isBookmarkNode(node)
  13397. : !domUtils.isWhitespace(node);
  13398. },
  13399. obj = getObj(editor);
  13400. if (obj && range.collapsed) {
  13401. obj.setAttribute("dir", forward);
  13402. return range;
  13403. }
  13404. bookmark = range.createBookmark();
  13405. range.enlarge(true);
  13406. var bookmark2 = range.createBookmark(),
  13407. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  13408. tmpRange = range.cloneRange(),
  13409. tmpNode;
  13410. while (
  13411. current &&
  13412. !(
  13413. domUtils.getPosition(current, bookmark2.end) &
  13414. domUtils.POSITION_FOLLOWING
  13415. )
  13416. ) {
  13417. if (current.nodeType == 3 || !block(current)) {
  13418. tmpRange.setStartBefore(current);
  13419. while (current && current !== bookmark2.end && !block(current)) {
  13420. tmpNode = current;
  13421. current = domUtils.getNextDomNode(current, false, null, function (
  13422. node
  13423. ) {
  13424. return !block(node);
  13425. });
  13426. }
  13427. tmpRange.setEndAfter(tmpNode);
  13428. var common = tmpRange.getCommonAncestor();
  13429. if (!domUtils.isBody(common) && block(common)) {
  13430. //遍历到了block节点
  13431. common.setAttribute("dir", forward);
  13432. current = common;
  13433. } else {
  13434. //没有遍历到,添加一个block节点
  13435. var p = range.document.createElement("p");
  13436. p.setAttribute("dir", forward);
  13437. var frag = tmpRange.extractContents();
  13438. p.appendChild(frag);
  13439. tmpRange.insertNode(p);
  13440. current = p;
  13441. }
  13442. current = domUtils.getNextDomNode(current, false, filterFn);
  13443. } else {
  13444. current = domUtils.getNextDomNode(current, true, filterFn);
  13445. }
  13446. }
  13447. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  13448. };
  13449. /**
  13450. * 文字输入方向
  13451. * @command directionality
  13452. * @method execCommand
  13453. * @param { String } cmdName 命令字符串
  13454. * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入
  13455. * @example
  13456. * ```javascript
  13457. * editor.execCommand( 'directionality', 'ltr');
  13458. * ```
  13459. */
  13460. /**
  13461. * 查询当前选区的文字输入方向
  13462. * @command directionality
  13463. * @method queryCommandValue
  13464. * @param { String } cmdName 命令字符串
  13465. * @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入
  13466. * @example
  13467. * ```javascript
  13468. * editor.queryCommandValue( 'directionality');
  13469. * ```
  13470. */
  13471. UE.commands["directionality"] = {
  13472. execCommand: function (cmdName, forward) {
  13473. var range = this.selection.getRange();
  13474. //闭合时单独处理
  13475. if (range.collapsed) {
  13476. var txt = this.document.createTextNode("d");
  13477. range.insertNode(txt);
  13478. }
  13479. doDirectionality(range, this, forward);
  13480. if (txt) {
  13481. range.setStartBefore(txt).collapse(true);
  13482. domUtils.remove(txt);
  13483. }
  13484. range.select();
  13485. return true;
  13486. },
  13487. queryCommandValue: function () {
  13488. var node = getObj(this);
  13489. return node ? node.getAttribute("dir") : "ltr";
  13490. }
  13491. };
  13492. })();
  13493. // plugins/horizontal.js
  13494. /**
  13495. * 插入分割线插件
  13496. * @file
  13497. * @since 1.2.6.1
  13498. */
  13499. /**
  13500. * 插入分割线
  13501. * @command horizontal
  13502. * @method execCommand
  13503. * @param { String } cmdName 命令字符串
  13504. * @example
  13505. * ```javascript
  13506. * editor.execCommand( 'horizontal' );
  13507. * ```
  13508. */
  13509. UE.plugins["horizontal"] = function () {
  13510. var me = this;
  13511. me.commands["horizontal"] = {
  13512. execCommand: function (cmdName) {
  13513. var me = this;
  13514. if (me.queryCommandState(cmdName) !== -1) {
  13515. me.execCommand("insertHtml", "<hr>");
  13516. var range = me.selection.getRange(),
  13517. start = range.startContainer;
  13518. if (start.nodeType == 1 && !start.childNodes[range.startOffset]) {
  13519. var tmp;
  13520. if ((tmp = start.childNodes[range.startOffset - 1])) {
  13521. if (tmp.nodeType == 1 && tmp.tagName == "HR") {
  13522. if (me.options.enterTag == "p") {
  13523. tmp = me.document.createElement("p");
  13524. range.insertNode(tmp);
  13525. range.setStart(tmp, 0).setCursor();
  13526. } else {
  13527. tmp = me.document.createElement("br");
  13528. range.insertNode(tmp);
  13529. range.setStartBefore(tmp).setCursor();
  13530. }
  13531. }
  13532. }
  13533. }
  13534. return true;
  13535. }
  13536. },
  13537. //边界在table里不能加分隔线
  13538. queryCommandState: function () {
  13539. return domUtils.filterNodeList(
  13540. this.selection.getStartElementPath(),
  13541. "table"
  13542. )
  13543. ? -1
  13544. : 0;
  13545. }
  13546. };
  13547. // me.addListener('delkeyup',function(){
  13548. // var rng = this.selection.getRange();
  13549. // if(browser.ie && browser.version > 8){
  13550. // rng.txtToElmBoundary(true);
  13551. // if(domUtils.isStartInblock(rng)){
  13552. // var tmpNode = rng.startContainer;
  13553. // var pre = tmpNode.previousSibling;
  13554. // if(pre && domUtils.isTagNode(pre,'hr')){
  13555. // domUtils.remove(pre);
  13556. // rng.select();
  13557. // return;
  13558. // }
  13559. // }
  13560. // }
  13561. // if(domUtils.isBody(rng.startContainer)){
  13562. // var hr = rng.startContainer.childNodes[rng.startOffset -1];
  13563. // if(hr && hr.nodeName == 'HR'){
  13564. // var next = hr.nextSibling;
  13565. // if(next){
  13566. // rng.setStart(next,0)
  13567. // }else if(hr.previousSibling){
  13568. // rng.setStartAtLast(hr.previousSibling)
  13569. // }else{
  13570. // var p = this.document.createElement('p');
  13571. // hr.parentNode.insertBefore(p,hr);
  13572. // domUtils.fillNode(this.document,p);
  13573. // rng.setStart(p,0);
  13574. // }
  13575. // domUtils.remove(hr);
  13576. // rng.setCursor(false,true);
  13577. // }
  13578. // }
  13579. // })
  13580. me.addListener("delkeydown", function (name, evt) {
  13581. var rng = this.selection.getRange();
  13582. rng.txtToElmBoundary(true);
  13583. if (domUtils.isStartInblock(rng)) {
  13584. var tmpNode = rng.startContainer;
  13585. var pre = tmpNode.previousSibling;
  13586. if (pre && domUtils.isTagNode(pre, "hr")) {
  13587. domUtils.remove(pre);
  13588. rng.select();
  13589. domUtils.preventDefault(evt);
  13590. return true;
  13591. }
  13592. }
  13593. });
  13594. };
  13595. // plugins/time.js
  13596. /**
  13597. * 插入时间和日期
  13598. * @file
  13599. * @since 1.2.6.1
  13600. */
  13601. /**
  13602. * 插入时间,默认格式:12:59:59
  13603. * @command time
  13604. * @method execCommand
  13605. * @param { String } cmd 命令字符串
  13606. * @example
  13607. * ```javascript
  13608. * editor.execCommand( 'time');
  13609. * ```
  13610. */
  13611. /**
  13612. * 插入日期,默认格式:2013-08-30
  13613. * @command date
  13614. * @method execCommand
  13615. * @param { String } cmd 命令字符串
  13616. * @example
  13617. * ```javascript
  13618. * editor.execCommand( 'date');
  13619. * ```
  13620. */
  13621. UE.commands["time"] = UE.commands["date"] = {
  13622. execCommand: function (cmd, format) {
  13623. var date = new Date();
  13624. function formatTime(date, format) {
  13625. var hh = ("0" + date.getHours()).slice(-2),
  13626. ii = ("0" + date.getMinutes()).slice(-2),
  13627. ss = ("0" + date.getSeconds()).slice(-2);
  13628. format = format || "hh:ii:ss";
  13629. return format.replace(/hh/gi, hh).replace(/ii/gi, ii).replace(/ss/gi, ss);
  13630. }
  13631. function formatDate(date, format) {
  13632. var yyyy = ("000" + date.getFullYear()).slice(-4),
  13633. yy = yyyy.slice(-2),
  13634. mm = ("0" + (date.getMonth() + 1)).slice(-2),
  13635. dd = ("0" + date.getDate()).slice(-2);
  13636. format = format || "yyyy-mm-dd";
  13637. return format
  13638. .replace(/yyyy/gi, yyyy)
  13639. .replace(/yy/gi, yy)
  13640. .replace(/mm/gi, mm)
  13641. .replace(/dd/gi, dd);
  13642. }
  13643. this.execCommand(
  13644. "insertHtml",
  13645. cmd == "time" ? formatTime(date, format) : formatDate(date, format)
  13646. );
  13647. }
  13648. };
  13649. // plugins/rowspacing.js
  13650. /**
  13651. * 段前段后间距插件
  13652. * @file
  13653. * @since 1.2.6.1
  13654. */
  13655. /**
  13656. * 设置段间距
  13657. * @command rowspacing
  13658. * @method execCommand
  13659. * @param { String } cmd 命令字符串
  13660. * @param { String } value 段间距的值,以px为单位
  13661. * @param { String } dir 间距位置,top或bottom,分别表示段前和段后
  13662. * @example
  13663. * ```javascript
  13664. * editor.execCommand( 'rowspacing', '10', 'top' );
  13665. * ```
  13666. */
  13667. UE.plugins["rowspacing"] = function () {
  13668. var me = this;
  13669. me.setOpt({
  13670. rowspacingtop: ["5", "10", "15", "20", "25"],
  13671. rowspacingbottom: ["5", "10", "15", "20", "25"]
  13672. });
  13673. me.commands["rowspacing"] = {
  13674. execCommand: function (cmdName, value, dir) {
  13675. this.execCommand("paragraph", "p", {
  13676. style: "margin-" + dir + ":" + value + "px"
  13677. });
  13678. return true;
  13679. },
  13680. queryCommandValue: function (cmdName, dir) {
  13681. var pN = domUtils.filterNodeList(
  13682. this.selection.getStartElementPath(),
  13683. function (node) {
  13684. return domUtils.isBlockElm(node);
  13685. }
  13686. ),
  13687. value;
  13688. //trace:1026
  13689. if (pN) {
  13690. value = domUtils
  13691. .getComputedStyle(pN, "margin-" + dir)
  13692. .replace(/[^\d]/g, "");
  13693. return !value ? 0 : value;
  13694. }
  13695. return 0;
  13696. }
  13697. };
  13698. };
  13699. // plugins/lineheight.js
  13700. /**
  13701. * 设置行内间距
  13702. * @file
  13703. * @since 1.2.6.1
  13704. */
  13705. UE.plugins["lineheight"] = function () {
  13706. var me = this;
  13707. me.setOpt({lineheight: ["1", "1.5", "1.75", "2", "3", "4", "5"]});
  13708. /**
  13709. * 行距
  13710. * @command lineheight
  13711. * @method execCommand
  13712. * @param { String } cmdName 命令字符串
  13713. * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75
  13714. * @example
  13715. * ```javascript
  13716. * editor.execCommand( 'lineheight', 1.5);
  13717. * ```
  13718. */
  13719. /**
  13720. * 查询当前选区内容的行高大小
  13721. * @command lineheight
  13722. * @method queryCommandValue
  13723. * @param { String } cmd 命令字符串
  13724. * @return { String } 返回当前行高大小
  13725. * @example
  13726. * ```javascript
  13727. * editor.queryCommandValue( 'lineheight' );
  13728. * ```
  13729. */
  13730. me.commands["lineheight"] = {
  13731. execCommand: function (cmdName, value) {
  13732. this.execCommand("paragraph", "p", {
  13733. style: "line-height:" + (value == "1" ? "normal" : value + "em")
  13734. });
  13735. return true;
  13736. },
  13737. queryCommandValue: function () {
  13738. var pN = domUtils.filterNodeList(
  13739. this.selection.getStartElementPath(),
  13740. function (node) {
  13741. return domUtils.isBlockElm(node);
  13742. }
  13743. );
  13744. if (pN) {
  13745. var value = domUtils.getComputedStyle(pN, "line-height");
  13746. return value == "normal" ? 1 : value.replace(/[^\d.]*/gi, "");
  13747. }
  13748. }
  13749. };
  13750. };
  13751. // plugins/insertcode.js
  13752. /**
  13753. * 插入代码插件
  13754. * @file
  13755. * @since 1.2.6.1
  13756. */
  13757. UE.plugins["insertcode"] = function () {
  13758. var me = this;
  13759. me.ready(function () {
  13760. utils.cssRule(
  13761. "pre",
  13762. "pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}",
  13763. me.document
  13764. );
  13765. });
  13766. me.setOpt("insertcode", {
  13767. as3: "ActionScript3",
  13768. bash: "Bash/Shell",
  13769. cpp: "C/C++",
  13770. css: "Css",
  13771. cf: "CodeFunction",
  13772. "c#": "C#",
  13773. delphi: "Delphi",
  13774. diff: "Diff",
  13775. erlang: "Erlang",
  13776. groovy: "Groovy",
  13777. html: "Html",
  13778. java: "Java",
  13779. jfx: "JavaFx",
  13780. js: "Javascript",
  13781. pl: "Perl",
  13782. php: "Php",
  13783. plain: "Plain Text",
  13784. ps: "PowerShell",
  13785. python: "Python",
  13786. ruby: "Ruby",
  13787. scala: "Scala",
  13788. sql: "Sql",
  13789. vb: "Vb",
  13790. xml: "Xml"
  13791. });
  13792. /**
  13793. * 插入代码
  13794. * @command insertcode
  13795. * @method execCommand
  13796. * @param { String } cmd 命令字符串
  13797. * @param { String } lang 插入代码的语言
  13798. * @example
  13799. * ```javascript
  13800. * editor.execCommand( 'insertcode', 'javascript' );
  13801. * ```
  13802. */
  13803. /**
  13804. * 如果选区所在位置是插入插入代码区域,返回代码的语言
  13805. * @command insertcode
  13806. * @method queryCommandValue
  13807. * @param { String } cmd 命令字符串
  13808. * @return { String } 返回代码的语言
  13809. * @example
  13810. * ```javascript
  13811. * editor.queryCommandValue( 'insertcode' );
  13812. * ```
  13813. */
  13814. me.commands["insertcode"] = {
  13815. execCommand: function (cmd, lang) {
  13816. var me = this,
  13817. rng = me.selection.getRange(),
  13818. pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  13819. if (pre) {
  13820. pre.className = "brush:" + lang + ";toolbar:false;";
  13821. } else {
  13822. var code = "";
  13823. if (rng.collapsed) {
  13824. code = browser.ie && browser.ie11below
  13825. ? browser.version <= 8 ? "&nbsp;" : ""
  13826. : "<br/>";
  13827. } else {
  13828. var frag = rng.extractContents();
  13829. var div = me.document.createElement("div");
  13830. div.appendChild(frag);
  13831. utils.each(
  13832. UE.filterNode(
  13833. UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, "")),
  13834. me.options.filterTxtRules
  13835. ).children,
  13836. function (node) {
  13837. if (browser.ie && browser.ie11below && browser.version > 8) {
  13838. if (node.type == "element") {
  13839. if (node.tagName == "br") {
  13840. code += "\n";
  13841. } else if (!dtd.$empty[node.tagName]) {
  13842. utils.each(node.children, function (cn) {
  13843. if (cn.type == "element") {
  13844. if (cn.tagName == "br") {
  13845. code += "\n";
  13846. } else if (!dtd.$empty[node.tagName]) {
  13847. code += cn.innerText();
  13848. }
  13849. } else {
  13850. code += cn.data;
  13851. }
  13852. });
  13853. if (!/\n$/.test(code)) {
  13854. code += "\n";
  13855. }
  13856. }
  13857. } else {
  13858. code += node.data + "\n";
  13859. }
  13860. if (!node.nextSibling() && /\n$/.test(code)) {
  13861. code = code.replace(/\n$/, "");
  13862. }
  13863. } else {
  13864. if (browser.ie && browser.ie11below) {
  13865. if (node.type == "element") {
  13866. if (node.tagName == "br") {
  13867. code += "<br>";
  13868. } else if (!dtd.$empty[node.tagName]) {
  13869. utils.each(node.children, function (cn) {
  13870. if (cn.type == "element") {
  13871. if (cn.tagName == "br") {
  13872. code += "<br>";
  13873. } else if (!dtd.$empty[node.tagName]) {
  13874. code += cn.innerText();
  13875. }
  13876. } else {
  13877. code += cn.data;
  13878. }
  13879. });
  13880. if (!/br>$/.test(code)) {
  13881. code += "<br>";
  13882. }
  13883. }
  13884. } else {
  13885. code += node.data + "<br>";
  13886. }
  13887. if (!node.nextSibling() && /<br>$/.test(code)) {
  13888. code = code.replace(/<br>$/, "");
  13889. }
  13890. } else {
  13891. code += node.type == "element"
  13892. ? dtd.$empty[node.tagName] ? "" : node.innerText()
  13893. : node.data;
  13894. if (!/br\/?\s*>$/.test(code)) {
  13895. if (!node.nextSibling()) return;
  13896. code += "<br>";
  13897. }
  13898. }
  13899. }
  13900. }
  13901. );
  13902. }
  13903. me.execCommand(
  13904. "inserthtml",
  13905. '<pre id="coder"class="brush:' +
  13906. lang +
  13907. ';toolbar:false">' +
  13908. code +
  13909. "</pre>",
  13910. true
  13911. );
  13912. pre = me.document.getElementById("coder");
  13913. domUtils.removeAttributes(pre, "id");
  13914. var tmpNode = pre.previousSibling;
  13915. if (
  13916. tmpNode &&
  13917. ((tmpNode.nodeType == 3 &&
  13918. tmpNode.nodeValue.length == 1 &&
  13919. browser.ie &&
  13920. browser.version == 6) ||
  13921. domUtils.isEmptyBlock(tmpNode))
  13922. ) {
  13923. domUtils.remove(tmpNode);
  13924. }
  13925. var rng = me.selection.getRange();
  13926. if (domUtils.isEmptyBlock(pre)) {
  13927. rng.setStart(pre, 0).setCursor(false, true);
  13928. } else {
  13929. rng.selectNodeContents(pre).select();
  13930. }
  13931. }
  13932. },
  13933. queryCommandValue: function () {
  13934. var path = this.selection.getStartElementPath();
  13935. var lang = "";
  13936. utils.each(path, function (node) {
  13937. if (node.nodeName == "PRE") {
  13938. var match = node.className.match(/brush:([^;]+)/);
  13939. lang = match && match[1] ? match[1] : "";
  13940. return false;
  13941. }
  13942. });
  13943. return lang;
  13944. }
  13945. };
  13946. me.addInputRule(function (root) {
  13947. utils.each(root.getNodesByTagName("pre"), function (pre) {
  13948. var brs = pre.getNodesByTagName("br");
  13949. if (brs.length) {
  13950. browser.ie &&
  13951. browser.ie11below &&
  13952. browser.version > 8 &&
  13953. utils.each(brs, function (br) {
  13954. var txt = UE.uNode.createText("\n");
  13955. br.parentNode.insertBefore(txt, br);
  13956. br.parentNode.removeChild(br);
  13957. });
  13958. return;
  13959. }
  13960. if (browser.ie && browser.ie11below && browser.version > 8) return;
  13961. var code = pre.innerText().split(/\n/);
  13962. pre.innerHTML("");
  13963. utils.each(code, function (c) {
  13964. if (c.length) {
  13965. pre.appendChild(UE.uNode.createText(c));
  13966. }
  13967. pre.appendChild(UE.uNode.createElement("br"));
  13968. });
  13969. });
  13970. });
  13971. me.addOutputRule(function (root) {
  13972. utils.each(root.getNodesByTagName("pre"), function (pre) {
  13973. var code = "";
  13974. utils.each(pre.children, function (n) {
  13975. if (n.type == "text") {
  13976. //在ie下文本内容有可能末尾带有\n要去掉
  13977. //trace:3396
  13978. code += n.data.replace(/[ ]/g, "&nbsp;").replace(/\n$/, "");
  13979. } else {
  13980. if (n.tagName == "br") {
  13981. code += "\n";
  13982. } else {
  13983. code += !dtd.$empty[n.tagName] ? "" : n.innerText();
  13984. }
  13985. }
  13986. });
  13987. pre.innerText(code.replace(/(&nbsp;|\n)+$/, ""));
  13988. });
  13989. });
  13990. //不需要判断highlight的command列表
  13991. me.notNeedCodeQuery = {
  13992. help: 1,
  13993. undo: 1,
  13994. redo: 1,
  13995. source: 1,
  13996. print: 1,
  13997. searchreplace: 1,
  13998. fullscreen: 1,
  13999. preview: 1,
  14000. insertparagraph: 1,
  14001. elementpath: 1,
  14002. insertcode: 1,
  14003. inserthtml: 1,
  14004. selectall: 1
  14005. };
  14006. //将queyCommamndState重置
  14007. var orgQuery = me.queryCommandState;
  14008. me.queryCommandState = function (cmd) {
  14009. var me = this;
  14010. if (
  14011. !me.notNeedCodeQuery[cmd.toLowerCase()] &&
  14012. me.selection &&
  14013. me.queryCommandValue("insertcode")
  14014. ) {
  14015. return -1;
  14016. }
  14017. return UE.Editor.prototype.queryCommandState.apply(this, arguments);
  14018. };
  14019. me.addListener("beforeenterkeydown", function () {
  14020. var rng = me.selection.getRange();
  14021. var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  14022. if (pre) {
  14023. me.fireEvent("saveScene");
  14024. if (!rng.collapsed) {
  14025. rng.deleteContents();
  14026. }
  14027. if (!browser.ie || browser.ie9above) {
  14028. var tmpNode = me.document.createElement("br"),
  14029. pre;
  14030. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
  14031. var next = tmpNode.nextSibling;
  14032. if (!next && (!browser.ie || browser.version > 10)) {
  14033. rng.insertNode(tmpNode.cloneNode(false));
  14034. } else {
  14035. rng.setStartAfter(tmpNode);
  14036. }
  14037. pre = tmpNode.previousSibling;
  14038. var tmp;
  14039. while (pre) {
  14040. tmp = pre;
  14041. pre = pre.previousSibling;
  14042. if (!pre || pre.nodeName == "BR") {
  14043. pre = tmp;
  14044. break;
  14045. }
  14046. }
  14047. if (pre) {
  14048. var str = "";
  14049. while (
  14050. pre &&
  14051. pre.nodeName != "BR" &&
  14052. new RegExp("^[\\s" + domUtils.fillChar + "]*$").test(pre.nodeValue)
  14053. ) {
  14054. str += pre.nodeValue;
  14055. pre = pre.nextSibling;
  14056. }
  14057. if (pre.nodeName != "BR") {
  14058. var match = pre.nodeValue.match(
  14059. new RegExp("^([\\s" + domUtils.fillChar + "]+)")
  14060. );
  14061. if (match && match[1]) {
  14062. str += match[1];
  14063. }
  14064. }
  14065. if (str) {
  14066. str = me.document.createTextNode(str);
  14067. rng.insertNode(str).setStartAfter(str);
  14068. }
  14069. }
  14070. rng.collapse(true).select(true);
  14071. } else {
  14072. if (browser.version > 8) {
  14073. var txt = me.document.createTextNode("\n");
  14074. var start = rng.startContainer;
  14075. if (rng.startOffset == 0) {
  14076. var preNode = start.previousSibling;
  14077. if (preNode) {
  14078. rng.insertNode(txt);
  14079. var fillchar = me.document.createTextNode(" ");
  14080. rng
  14081. .setStartAfter(txt)
  14082. .insertNode(fillchar)
  14083. .setStart(fillchar, 0)
  14084. .collapse(true)
  14085. .select(true);
  14086. }
  14087. } else {
  14088. rng.insertNode(txt).setStartAfter(txt);
  14089. var fillchar = me.document.createTextNode(" ");
  14090. start = rng.startContainer.childNodes[rng.startOffset];
  14091. if (start && !/^\n/.test(start.nodeValue)) {
  14092. rng.setStartBefore(txt);
  14093. }
  14094. rng
  14095. .insertNode(fillchar)
  14096. .setStart(fillchar, 0)
  14097. .collapse(true)
  14098. .select(true);
  14099. }
  14100. } else {
  14101. var tmpNode = me.document.createElement("br");
  14102. rng.insertNode(tmpNode);
  14103. rng.insertNode(me.document.createTextNode(domUtils.fillChar));
  14104. rng.setStartAfter(tmpNode);
  14105. pre = tmpNode.previousSibling;
  14106. var tmp;
  14107. while (pre) {
  14108. tmp = pre;
  14109. pre = pre.previousSibling;
  14110. if (!pre || pre.nodeName == "BR") {
  14111. pre = tmp;
  14112. break;
  14113. }
  14114. }
  14115. if (pre) {
  14116. var str = "";
  14117. while (
  14118. pre &&
  14119. pre.nodeName != "BR" &&
  14120. new RegExp("^[ " + domUtils.fillChar + "]*$").test(pre.nodeValue)
  14121. ) {
  14122. str += pre.nodeValue;
  14123. pre = pre.nextSibling;
  14124. }
  14125. if (pre.nodeName != "BR") {
  14126. var match = pre.nodeValue.match(
  14127. new RegExp("^([ " + domUtils.fillChar + "]+)")
  14128. );
  14129. if (match && match[1]) {
  14130. str += match[1];
  14131. }
  14132. }
  14133. str = me.document.createTextNode(str);
  14134. rng.insertNode(str).setStartAfter(str);
  14135. }
  14136. rng.collapse(true).select();
  14137. }
  14138. }
  14139. me.fireEvent("saveScene");
  14140. return true;
  14141. }
  14142. });
  14143. me.addListener("tabkeydown", function (cmd, evt) {
  14144. var rng = me.selection.getRange();
  14145. var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  14146. if (pre) {
  14147. me.fireEvent("saveScene");
  14148. if (evt.shiftKey) {
  14149. } else {
  14150. if (!rng.collapsed) {
  14151. var bk = rng.createBookmark();
  14152. var start = bk.start.previousSibling;
  14153. while (start) {
  14154. if (pre.firstChild === start && !domUtils.isBr(start)) {
  14155. pre.insertBefore(me.document.createTextNode(" "), start);
  14156. break;
  14157. }
  14158. if (domUtils.isBr(start)) {
  14159. pre.insertBefore(
  14160. me.document.createTextNode(" "),
  14161. start.nextSibling
  14162. );
  14163. break;
  14164. }
  14165. start = start.previousSibling;
  14166. }
  14167. var end = bk.end;
  14168. start = bk.start.nextSibling;
  14169. if (pre.firstChild === bk.start) {
  14170. pre.insertBefore(
  14171. me.document.createTextNode(" "),
  14172. start.nextSibling
  14173. );
  14174. }
  14175. while (start && start !== end) {
  14176. if (domUtils.isBr(start) && start.nextSibling) {
  14177. if (start.nextSibling === end) {
  14178. break;
  14179. }
  14180. pre.insertBefore(
  14181. me.document.createTextNode(" "),
  14182. start.nextSibling
  14183. );
  14184. }
  14185. start = start.nextSibling;
  14186. }
  14187. rng.moveToBookmark(bk).select();
  14188. } else {
  14189. var tmpNode = me.document.createTextNode(" ");
  14190. rng
  14191. .insertNode(tmpNode)
  14192. .setStartAfter(tmpNode)
  14193. .collapse(true)
  14194. .select(true);
  14195. }
  14196. }
  14197. me.fireEvent("saveScene");
  14198. return true;
  14199. }
  14200. });
  14201. me.addListener("beforeinserthtml", function (evtName, html) {
  14202. var me = this,
  14203. rng = me.selection.getRange(),
  14204. pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  14205. if (pre) {
  14206. if (!rng.collapsed) {
  14207. rng.deleteContents();
  14208. }
  14209. var htmlstr = "";
  14210. if (browser.ie && browser.version > 8) {
  14211. utils.each(
  14212. UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
  14213. .children,
  14214. function (node) {
  14215. if (node.type == "element") {
  14216. if (node.tagName == "br") {
  14217. htmlstr += "\n";
  14218. } else if (!dtd.$empty[node.tagName]) {
  14219. utils.each(node.children, function (cn) {
  14220. if (cn.type == "element") {
  14221. if (cn.tagName == "br") {
  14222. htmlstr += "\n";
  14223. } else if (!dtd.$empty[node.tagName]) {
  14224. htmlstr += cn.innerText();
  14225. }
  14226. } else {
  14227. htmlstr += cn.data;
  14228. }
  14229. });
  14230. if (!/\n$/.test(htmlstr)) {
  14231. htmlstr += "\n";
  14232. }
  14233. }
  14234. } else {
  14235. htmlstr += node.data + "\n";
  14236. }
  14237. if (!node.nextSibling() && /\n$/.test(htmlstr)) {
  14238. htmlstr = htmlstr.replace(/\n$/, "");
  14239. }
  14240. }
  14241. );
  14242. var tmpNode = me.document.createTextNode(
  14243. utils.html(htmlstr.replace(/&nbsp;/g, " "))
  14244. );
  14245. rng.insertNode(tmpNode).selectNode(tmpNode).select();
  14246. } else {
  14247. var frag = me.document.createDocumentFragment();
  14248. utils.each(
  14249. UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
  14250. .children,
  14251. function (node) {
  14252. if (node.type == "element") {
  14253. if (node.tagName == "br") {
  14254. frag.appendChild(me.document.createElement("br"));
  14255. } else if (!dtd.$empty[node.tagName]) {
  14256. utils.each(node.children, function (cn) {
  14257. if (cn.type == "element") {
  14258. if (cn.tagName == "br") {
  14259. frag.appendChild(me.document.createElement("br"));
  14260. } else if (!dtd.$empty[node.tagName]) {
  14261. frag.appendChild(
  14262. me.document.createTextNode(
  14263. utils.html(cn.innerText().replace(/&nbsp;/g, " "))
  14264. )
  14265. );
  14266. }
  14267. } else {
  14268. frag.appendChild(
  14269. me.document.createTextNode(
  14270. utils.html(cn.data.replace(/&nbsp;/g, " "))
  14271. )
  14272. );
  14273. }
  14274. });
  14275. if (frag.lastChild.nodeName != "BR") {
  14276. frag.appendChild(me.document.createElement("br"));
  14277. }
  14278. }
  14279. } else {
  14280. frag.appendChild(
  14281. me.document.createTextNode(
  14282. utils.html(node.data.replace(/&nbsp;/g, " "))
  14283. )
  14284. );
  14285. }
  14286. if (!node.nextSibling() && frag.lastChild.nodeName == "BR") {
  14287. frag.removeChild(frag.lastChild);
  14288. }
  14289. }
  14290. );
  14291. rng.insertNode(frag).select();
  14292. }
  14293. return true;
  14294. }
  14295. });
  14296. //方向键的处理
  14297. me.addListener("keydown", function (cmd, evt) {
  14298. var me = this,
  14299. keyCode = evt.keyCode || evt.which;
  14300. if (keyCode == 40) {
  14301. var rng = me.selection.getRange(),
  14302. pre,
  14303. start = rng.startContainer;
  14304. if (
  14305. rng.collapsed &&
  14306. (pre = domUtils.findParentByTagName(rng.startContainer, "pre", true)) &&
  14307. !pre.nextSibling
  14308. ) {
  14309. var last = pre.lastChild;
  14310. while (last && last.nodeName == "BR") {
  14311. last = last.previousSibling;
  14312. }
  14313. if (
  14314. last === start ||
  14315. (rng.startContainer === pre &&
  14316. rng.startOffset == pre.childNodes.length)
  14317. ) {
  14318. me.execCommand("insertparagraph");
  14319. domUtils.preventDefault(evt);
  14320. }
  14321. }
  14322. }
  14323. });
  14324. //trace:3395
  14325. me.addListener("delkeydown", function (type, evt) {
  14326. var rng = this.selection.getRange();
  14327. rng.txtToElmBoundary(true);
  14328. var start = rng.startContainer;
  14329. if (
  14330. domUtils.isTagNode(start, "pre") &&
  14331. rng.collapsed &&
  14332. domUtils.isStartInblock(rng)
  14333. ) {
  14334. var p = me.document.createElement("p");
  14335. domUtils.fillNode(me.document, p);
  14336. start.parentNode.insertBefore(p, start);
  14337. domUtils.remove(start);
  14338. rng.setStart(p, 0).setCursor(false, true);
  14339. domUtils.preventDefault(evt);
  14340. return true;
  14341. }
  14342. });
  14343. };
  14344. // plugins/cleardoc.js
  14345. /**
  14346. * 清空文档插件
  14347. * @file
  14348. * @since 1.2.6.1
  14349. */
  14350. /**
  14351. * 清空文档
  14352. * @command cleardoc
  14353. * @method execCommand
  14354. * @param { String } cmd 命令字符串
  14355. * @example
  14356. * ```javascript
  14357. * //editor 是编辑器实例
  14358. * editor.execCommand('cleardoc');
  14359. * ```
  14360. */
  14361. UE.commands["cleardoc"] = {
  14362. execCommand: function (cmdName) {
  14363. var me = this,
  14364. enterTag = me.options.enterTag,
  14365. range = me.selection.getRange();
  14366. if (enterTag == "br") {
  14367. me.body.innerHTML = "<br/>";
  14368. range.setStart(me.body, 0).setCursor();
  14369. } else {
  14370. me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
  14371. range.setStart(me.body.firstChild, 0).setCursor(false, true);
  14372. }
  14373. setTimeout(function () {
  14374. me.fireEvent("clearDoc");
  14375. }, 0);
  14376. }
  14377. };
  14378. // plugins/anchor.js
  14379. /**
  14380. * 锚点插件,为UEditor提供插入锚点支持
  14381. * @file
  14382. * @since 1.2.6.1
  14383. */
  14384. UE.plugin.register("anchor", function () {
  14385. return {
  14386. bindEvents: {
  14387. ready: function () {
  14388. utils.cssRule(
  14389. "anchor",
  14390. ".anchorclass{background: url('" +
  14391. this.options.themePath +
  14392. this.options.theme +
  14393. "/images/anchor.gif') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}",
  14394. this.document
  14395. );
  14396. }
  14397. },
  14398. outputRule: function (root) {
  14399. utils.each(root.getNodesByTagName("img"), function (a) {
  14400. var val;
  14401. if ((val = a.getAttr("anchorname"))) {
  14402. a.tagName = "a";
  14403. a.setAttr({
  14404. anchorname: "",
  14405. name: val,
  14406. class: ""
  14407. });
  14408. }
  14409. });
  14410. },
  14411. inputRule: function (root) {
  14412. utils.each(root.getNodesByTagName("a"), function (a) {
  14413. var val;
  14414. if ((val = a.getAttr("name")) && !a.getAttr("href")) {
  14415. //过滤掉word冗余标签
  14416. //_Toc\d+有可能勿命中
  14417. if (/^\_Toc\d+$/.test(val)) {
  14418. a.parentNode.removeChild(a);
  14419. return;
  14420. }
  14421. a.tagName = "img";
  14422. a.setAttr({
  14423. anchorname: a.getAttr("name"),
  14424. class: "anchorclass"
  14425. });
  14426. a.setAttr("name");
  14427. }
  14428. });
  14429. },
  14430. commands: {
  14431. /**
  14432. * 插入锚点
  14433. * @command anchor
  14434. * @method execCommand
  14435. * @param { String } cmd 命令字符串
  14436. * @param { String } name 锚点名称字符串
  14437. * @example
  14438. * ```javascript
  14439. * //editor 是编辑器实例
  14440. * editor.execCommand('anchor', 'anchor1');
  14441. * ```
  14442. */
  14443. anchor: {
  14444. execCommand: function (cmd, name) {
  14445. var range = this.selection.getRange(),
  14446. img = range.getClosedNode();
  14447. if (img && img.getAttribute("anchorname")) {
  14448. if (name) {
  14449. img.setAttribute("anchorname", name);
  14450. } else {
  14451. range.setStartBefore(img).setCursor();
  14452. domUtils.remove(img);
  14453. }
  14454. } else {
  14455. if (name) {
  14456. //只在选区的开始插入
  14457. var anchor = this.document.createElement("img");
  14458. range.collapse(true);
  14459. domUtils.setAttributes(anchor, {
  14460. anchorname: name,
  14461. class: "anchorclass"
  14462. });
  14463. range
  14464. .insertNode(anchor)
  14465. .setStartAfter(anchor)
  14466. .setCursor(false, true);
  14467. }
  14468. }
  14469. }
  14470. }
  14471. }
  14472. };
  14473. });
  14474. // plugins/wordcount.js
  14475. ///import core
  14476. ///commands 字数统计
  14477. ///commandsName WordCount,wordCount
  14478. ///commandsTitle 字数统计
  14479. /*
  14480. * Created by JetBrains WebStorm.
  14481. * User: taoqili
  14482. * Date: 11-9-7
  14483. * Time: 下午8:18
  14484. * To change this template use File | Settings | File Templates.
  14485. */
  14486. UE.plugins["wordcount"] = function () {
  14487. var me = this;
  14488. me.setOpt("wordCount", true);
  14489. me.addListener("contentchange", function () {
  14490. me.fireEvent("wordcount");
  14491. });
  14492. var timer;
  14493. me.addListener("ready", function () {
  14494. var me = this;
  14495. domUtils.on(me.body, "keyup", function (evt) {
  14496. var code = evt.keyCode || evt.which,
  14497. //忽略的按键,ctr,alt,shift,方向键
  14498. ignores = {
  14499. "16": 1,
  14500. "18": 1,
  14501. "20": 1,
  14502. "37": 1,
  14503. "38": 1,
  14504. "39": 1,
  14505. "40": 1
  14506. };
  14507. if (code in ignores) return;
  14508. clearTimeout(timer);
  14509. timer = setTimeout(function () {
  14510. me.fireEvent("wordcount");
  14511. }, 200);
  14512. });
  14513. });
  14514. };
  14515. // plugins/pagebreak.js
  14516. /**
  14517. * 分页功能插件
  14518. * @file
  14519. * @since 1.2.6.1
  14520. */
  14521. UE.plugins["pagebreak"] = function () {
  14522. var me = this,
  14523. notBreakTags = ["td"];
  14524. me.setOpt("pageBreakTag", "_ueditor_page_break_tag_");
  14525. function fillNode(node) {
  14526. if (domUtils.isEmptyBlock(node)) {
  14527. var firstChild = node.firstChild,
  14528. tmpNode;
  14529. while (
  14530. firstChild &&
  14531. firstChild.nodeType == 1 &&
  14532. domUtils.isEmptyBlock(firstChild)
  14533. ) {
  14534. tmpNode = firstChild;
  14535. firstChild = firstChild.firstChild;
  14536. }
  14537. !tmpNode && (tmpNode = node);
  14538. domUtils.fillNode(me.document, tmpNode);
  14539. }
  14540. }
  14541. //分页符样式添加
  14542. me.ready(function () {
  14543. utils.cssRule(
  14544. "pagebreak",
  14545. ".pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}",
  14546. me.document
  14547. );
  14548. });
  14549. function isHr(node) {
  14550. return (
  14551. node &&
  14552. node.nodeType == 1 &&
  14553. node.tagName == "HR" &&
  14554. node.className == "pagebreak"
  14555. );
  14556. }
  14557. me.addInputRule(function (root) {
  14558. root.traversal(function (node) {
  14559. if (node.type == "text" && node.data == me.options.pageBreakTag) {
  14560. var hr = UE.uNode.createElement(
  14561. '<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">'
  14562. );
  14563. node.parentNode.insertBefore(hr, node);
  14564. node.parentNode.removeChild(node);
  14565. }
  14566. });
  14567. });
  14568. me.addOutputRule(function (node) {
  14569. utils.each(node.getNodesByTagName("hr"), function (n) {
  14570. if (n.getAttr("class") == "pagebreak") {
  14571. var txt = UE.uNode.createText(me.options.pageBreakTag);
  14572. n.parentNode.insertBefore(txt, n);
  14573. n.parentNode.removeChild(n);
  14574. }
  14575. });
  14576. });
  14577. /**
  14578. * 插入分页符
  14579. * @command pagebreak
  14580. * @method execCommand
  14581. * @param { String } cmd 命令字符串
  14582. * @remind 在表格中插入分页符会把表格切分成两部分
  14583. * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串,
  14584. * 以便于提交数据到服务器端后处理分页。
  14585. * @example
  14586. * ```javascript
  14587. * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
  14588. * ```
  14589. */
  14590. me.commands["pagebreak"] = {
  14591. execCommand: function () {
  14592. var range = me.selection.getRange(),
  14593. hr = me.document.createElement("hr");
  14594. domUtils.setAttributes(hr, {
  14595. class: "pagebreak",
  14596. noshade: "noshade",
  14597. size: "5"
  14598. });
  14599. domUtils.unSelectable(hr);
  14600. //table单独处理
  14601. var node = domUtils.findParentByTagName(
  14602. range.startContainer,
  14603. notBreakTags,
  14604. true
  14605. ),
  14606. parents = [],
  14607. pN;
  14608. if (node) {
  14609. switch (node.tagName) {
  14610. case "TD":
  14611. pN = node.parentNode;
  14612. if (!pN.previousSibling) {
  14613. var table = domUtils.findParentByTagName(pN, "table");
  14614. // var tableWrapDiv = table.parentNode;
  14615. // if(tableWrapDiv && tableWrapDiv.nodeType == 1
  14616. // && tableWrapDiv.tagName == 'DIV'
  14617. // && tableWrapDiv.getAttribute('dropdrag')
  14618. // ){
  14619. // domUtils.remove(tableWrapDiv,true);
  14620. // }
  14621. table.parentNode.insertBefore(hr, table);
  14622. parents = domUtils.findParents(hr, true);
  14623. } else {
  14624. pN.parentNode.insertBefore(hr, pN);
  14625. parents = domUtils.findParents(hr);
  14626. }
  14627. pN = parents[1];
  14628. if (hr !== pN) {
  14629. domUtils.breakParent(hr, pN);
  14630. }
  14631. //table要重写绑定一下拖拽
  14632. me.fireEvent("afteradjusttable", me.document);
  14633. }
  14634. } else {
  14635. if (!range.collapsed) {
  14636. range.deleteContents();
  14637. var start = range.startContainer;
  14638. while (
  14639. !domUtils.isBody(start) &&
  14640. domUtils.isBlockElm(start) &&
  14641. domUtils.isEmptyNode(start)
  14642. ) {
  14643. range.setStartBefore(start).collapse(true);
  14644. domUtils.remove(start);
  14645. start = range.startContainer;
  14646. }
  14647. }
  14648. range.insertNode(hr);
  14649. var pN = hr.parentNode,
  14650. nextNode;
  14651. while (!domUtils.isBody(pN)) {
  14652. domUtils.breakParent(hr, pN);
  14653. nextNode = hr.nextSibling;
  14654. if (nextNode && domUtils.isEmptyBlock(nextNode)) {
  14655. domUtils.remove(nextNode);
  14656. }
  14657. pN = hr.parentNode;
  14658. }
  14659. nextNode = hr.nextSibling;
  14660. var pre = hr.previousSibling;
  14661. if (isHr(pre)) {
  14662. domUtils.remove(pre);
  14663. } else {
  14664. pre && fillNode(pre);
  14665. }
  14666. if (!nextNode) {
  14667. var p = me.document.createElement("p");
  14668. hr.parentNode.appendChild(p);
  14669. domUtils.fillNode(me.document, p);
  14670. range.setStart(p, 0).collapse(true);
  14671. } else {
  14672. if (isHr(nextNode)) {
  14673. domUtils.remove(nextNode);
  14674. } else {
  14675. fillNode(nextNode);
  14676. }
  14677. range.setEndAfter(hr).collapse(false);
  14678. }
  14679. range.select(true);
  14680. }
  14681. }
  14682. };
  14683. };
  14684. // plugins/wordimage.js
  14685. ///import core
  14686. ///commands 本地图片引导上传
  14687. ///commandsName WordImage
  14688. ///commandsTitle 本地图片引导上传
  14689. ///commandsDialog dialogs\wordimage
  14690. UE.plugin.register("wordimage", function () {
  14691. var me = this,
  14692. images = [];
  14693. return {
  14694. commands: {
  14695. wordimage: {
  14696. execCommand: function () {
  14697. var images = domUtils.getElementsByTagName(me.body, "img");
  14698. var urlList = [];
  14699. for (var i = 0, ci; (ci = images[i++]);) {
  14700. var url = ci.getAttribute("word_img");
  14701. url && urlList.push(url);
  14702. }
  14703. return urlList;
  14704. },
  14705. queryCommandState: function () {
  14706. images = domUtils.getElementsByTagName(me.body, "img");
  14707. for (var i = 0, ci; (ci = images[i++]);) {
  14708. if (ci.getAttribute("word_img")) {
  14709. return 1;
  14710. }
  14711. }
  14712. return -1;
  14713. },
  14714. notNeedUndo: true
  14715. }
  14716. },
  14717. inputRule: function (root) {
  14718. utils.each(root.getNodesByTagName("img"), function (img) {
  14719. var attrs = img.attrs,
  14720. flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
  14721. opt = me.options,
  14722. src = opt.UEDITOR_HOME_URL + "themes/notadd/images/spacer.gif";
  14723. if (attrs["src"] && /^(?:(file:\/+))/.test(attrs["src"])) {
  14724. img.setAttr({
  14725. width: attrs.width,
  14726. height: attrs.height,
  14727. alt: attrs.alt,
  14728. word_img: attrs.src,
  14729. src: src,
  14730. style:
  14731. "background:url(" +
  14732. (flag
  14733. ? opt.themePath + opt.theme + "/images/word.gif"
  14734. : opt.langPath + opt.lang + "/images/localimage.png") +
  14735. ") no-repeat center center;border:1px solid #ddd"
  14736. });
  14737. }
  14738. });
  14739. }
  14740. };
  14741. });
  14742. // plugins/dragdrop.js
  14743. UE.plugins["dragdrop"] = function () {
  14744. var me = this;
  14745. me.ready(function () {
  14746. domUtils.on(this.body, "dragend", function () {
  14747. var rng = me.selection.getRange();
  14748. var node = rng.getClosedNode() || me.selection.getStart();
  14749. if (node && node.tagName == "IMG") {
  14750. var pre = node.previousSibling,
  14751. next;
  14752. while ((next = node.nextSibling)) {
  14753. if (
  14754. next.nodeType == 1 &&
  14755. next.tagName == "SPAN" &&
  14756. !next.firstChild
  14757. ) {
  14758. domUtils.remove(next);
  14759. } else {
  14760. break;
  14761. }
  14762. }
  14763. if (
  14764. ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre)) || !pre) &&
  14765. (!next || (next && !domUtils.isEmptyBlock(next)))
  14766. ) {
  14767. if (pre && pre.tagName == "P" && !domUtils.isEmptyBlock(pre)) {
  14768. pre.appendChild(node);
  14769. domUtils.moveChild(next, pre);
  14770. domUtils.remove(next);
  14771. } else if (
  14772. next &&
  14773. next.tagName == "P" &&
  14774. !domUtils.isEmptyBlock(next)
  14775. ) {
  14776. next.insertBefore(node, next.firstChild);
  14777. }
  14778. if (pre && pre.tagName == "P" && domUtils.isEmptyBlock(pre)) {
  14779. domUtils.remove(pre);
  14780. }
  14781. if (next && next.tagName == "P" && domUtils.isEmptyBlock(next)) {
  14782. domUtils.remove(next);
  14783. }
  14784. rng.selectNode(node).select();
  14785. me.fireEvent("saveScene");
  14786. }
  14787. }
  14788. });
  14789. });
  14790. me.addListener("keyup", function (type, evt) {
  14791. var keyCode = evt.keyCode || evt.which;
  14792. if (keyCode == 13) {
  14793. var rng = me.selection.getRange(),
  14794. node;
  14795. if (
  14796. (node = domUtils.findParentByTagName(rng.startContainer, "p", true))
  14797. ) {
  14798. if (domUtils.getComputedStyle(node, "text-align") == "center") {
  14799. domUtils.removeStyle(node, "text-align");
  14800. }
  14801. }
  14802. }
  14803. });
  14804. };
  14805. // plugins/undo.js
  14806. /**
  14807. * undo redo
  14808. * @file
  14809. * @since 1.2.6.1
  14810. */
  14811. /**
  14812. * 撤销上一次执行的命令
  14813. * @command undo
  14814. * @method execCommand
  14815. * @param { String } cmd 命令字符串
  14816. * @example
  14817. * ```javascript
  14818. * editor.execCommand( 'undo' );
  14819. * ```
  14820. */
  14821. /**
  14822. * 重做上一次执行的命令
  14823. * @command redo
  14824. * @method execCommand
  14825. * @param { String } cmd 命令字符串
  14826. * @example
  14827. * ```javascript
  14828. * editor.execCommand( 'redo' );
  14829. * ```
  14830. */
  14831. UE.plugins["undo"] = function () {
  14832. var saveSceneTimer;
  14833. var me = this,
  14834. maxUndoCount = me.options.maxUndoCount || 20,
  14835. maxInputCount = me.options.maxInputCount || 20,
  14836. fillchar = new RegExp(domUtils.fillChar + "|</hr>", "gi"); // ie会产生多余的</hr>
  14837. var noNeedFillCharTags = {
  14838. ol: 1,
  14839. ul: 1,
  14840. table: 1,
  14841. tbody: 1,
  14842. tr: 1,
  14843. body: 1
  14844. };
  14845. var orgState = me.options.autoClearEmptyNode;
  14846. function compareAddr(indexA, indexB) {
  14847. if (indexA.length != indexB.length) return 0;
  14848. for (var i = 0, l = indexA.length; i < l; i++) {
  14849. if (indexA[i] != indexB[i]) return 0;
  14850. }
  14851. return 1;
  14852. }
  14853. function compareRangeAddress(rngAddrA, rngAddrB) {
  14854. if (rngAddrA.collapsed != rngAddrB.collapsed) {
  14855. return 0;
  14856. }
  14857. if (
  14858. !compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) ||
  14859. !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)
  14860. ) {
  14861. return 0;
  14862. }
  14863. return 1;
  14864. }
  14865. function UndoManager() {
  14866. this.list = [];
  14867. this.index = 0;
  14868. this.hasUndo = false;
  14869. this.hasRedo = false;
  14870. this.undo = function () {
  14871. if (this.hasUndo) {
  14872. if (!this.list[this.index - 1] && this.list.length == 1) {
  14873. this.reset();
  14874. return;
  14875. }
  14876. while (
  14877. this.list[this.index].content == this.list[this.index - 1].content
  14878. ) {
  14879. this.index--;
  14880. if (this.index == 0) {
  14881. return this.restore(0);
  14882. }
  14883. }
  14884. this.restore(--this.index);
  14885. }
  14886. };
  14887. this.redo = function () {
  14888. if (this.hasRedo) {
  14889. while (
  14890. this.list[this.index].content == this.list[this.index + 1].content
  14891. ) {
  14892. this.index++;
  14893. if (this.index == this.list.length - 1) {
  14894. return this.restore(this.index);
  14895. }
  14896. }
  14897. this.restore(++this.index);
  14898. }
  14899. };
  14900. this.restore = function () {
  14901. var me = this.editor;
  14902. var scene = this.list[this.index];
  14903. var root = UE.htmlparser(scene.content.replace(fillchar, ""));
  14904. me.options.autoClearEmptyNode = false;
  14905. me.filterInputRule(root);
  14906. me.options.autoClearEmptyNode = orgState;
  14907. //trace:873
  14908. //去掉展位符
  14909. me.document.body.innerHTML = root.toHtml();
  14910. me.fireEvent("afterscencerestore");
  14911. //处理undo后空格不展位的问题
  14912. if (browser.ie) {
  14913. utils.each(
  14914. domUtils.getElementsByTagName(me.document, "td th caption p"),
  14915. function (node) {
  14916. if (domUtils.isEmptyNode(node)) {
  14917. domUtils.fillNode(me.document, node);
  14918. }
  14919. }
  14920. );
  14921. }
  14922. try {
  14923. var rng = new dom.Range(me.document).moveToAddress(scene.address);
  14924. rng.select(
  14925. noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]
  14926. );
  14927. } catch (e) {
  14928. }
  14929. this.update();
  14930. this.clearKey();
  14931. //不能把自己reset了
  14932. me.fireEvent("reset", true);
  14933. };
  14934. this.getScene = function () {
  14935. var me = this.editor;
  14936. var rng = me.selection.getRange(),
  14937. rngAddress = rng.createAddress(false, true);
  14938. me.fireEvent("beforegetscene");
  14939. var root = UE.htmlparser(me.body.innerHTML);
  14940. me.options.autoClearEmptyNode = false;
  14941. me.filterOutputRule(root);
  14942. me.options.autoClearEmptyNode = orgState;
  14943. var cont = root.toHtml();
  14944. //trace:3461
  14945. //这个会引起回退时导致空格丢失的情况
  14946. // browser.ie && (cont = cont.replace(/>&nbsp;</g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
  14947. me.fireEvent("aftergetscene");
  14948. return {
  14949. address: rngAddress,
  14950. content: cont
  14951. };
  14952. };
  14953. this.save = function (notCompareRange, notSetCursor) {
  14954. clearTimeout(saveSceneTimer);
  14955. var currentScene = this.getScene(notSetCursor),
  14956. lastScene = this.list[this.index];
  14957. if (lastScene && lastScene.content != currentScene.content) {
  14958. me.trigger("contentchange");
  14959. }
  14960. //内容相同位置相同不存
  14961. if (
  14962. lastScene &&
  14963. lastScene.content == currentScene.content &&
  14964. (notCompareRange
  14965. ? 1
  14966. : compareRangeAddress(lastScene.address, currentScene.address))
  14967. ) {
  14968. return;
  14969. }
  14970. this.list = this.list.slice(0, this.index + 1);
  14971. this.list.push(currentScene);
  14972. //如果大于最大数量了,就把最前的剔除
  14973. if (this.list.length > maxUndoCount) {
  14974. this.list.shift();
  14975. }
  14976. this.index = this.list.length - 1;
  14977. this.clearKey();
  14978. //跟新undo/redo状态
  14979. this.update();
  14980. };
  14981. this.update = function () {
  14982. this.hasRedo = !!this.list[this.index + 1];
  14983. this.hasUndo = !!this.list[this.index - 1];
  14984. };
  14985. this.reset = function () {
  14986. this.list = [];
  14987. this.index = 0;
  14988. this.hasUndo = false;
  14989. this.hasRedo = false;
  14990. this.clearKey();
  14991. };
  14992. this.clearKey = function () {
  14993. keycont = 0;
  14994. lastKeyCode = null;
  14995. };
  14996. }
  14997. me.undoManger = new UndoManager();
  14998. me.undoManger.editor = me;
  14999. function saveScene() {
  15000. this.undoManger.save();
  15001. }
  15002. me.addListener("saveScene", function () {
  15003. var args = Array.prototype.splice.call(arguments, 1);
  15004. this.undoManger.save.apply(this.undoManger, args);
  15005. });
  15006. // me.addListener('beforeexeccommand', saveScene);
  15007. // me.addListener('afterexeccommand', saveScene);
  15008. me.addListener("reset", function (type, exclude) {
  15009. if (!exclude) {
  15010. this.undoManger.reset();
  15011. }
  15012. });
  15013. me.commands["redo"] = me.commands["undo"] = {
  15014. execCommand: function (cmdName) {
  15015. this.undoManger[cmdName]();
  15016. },
  15017. queryCommandState: function (cmdName) {
  15018. return this.undoManger[
  15019. "has" + (cmdName.toLowerCase() == "undo" ? "Undo" : "Redo")
  15020. ]
  15021. ? 0
  15022. : -1;
  15023. },
  15024. notNeedUndo: 1
  15025. };
  15026. var keys = {
  15027. // /*Backspace*/ 8:1, /*Delete*/ 46:1,
  15028. /*Shift*/ 16: 1,
  15029. /*Ctrl*/ 17: 1,
  15030. /*Alt*/ 18: 1,
  15031. 37: 1,
  15032. 38: 1,
  15033. 39: 1,
  15034. 40: 1
  15035. },
  15036. keycont = 0,
  15037. lastKeyCode;
  15038. //输入法状态下不计算字符数
  15039. var inputType = false;
  15040. me.addListener("ready", function () {
  15041. domUtils.on(this.body, "compositionstart", function () {
  15042. inputType = true;
  15043. });
  15044. domUtils.on(this.body, "compositionend", function () {
  15045. inputType = false;
  15046. });
  15047. });
  15048. //快捷键
  15049. me.addshortcutkey({
  15050. Undo: "ctrl+90", //undo
  15051. Redo: "ctrl+89" //redo
  15052. });
  15053. var isCollapsed = true;
  15054. me.addListener("keydown", function (type, evt) {
  15055. var me = this;
  15056. var keyCode = evt.keyCode || evt.which;
  15057. if (
  15058. !keys[keyCode] &&
  15059. !evt.ctrlKey &&
  15060. !evt.metaKey &&
  15061. !evt.shiftKey &&
  15062. !evt.altKey
  15063. ) {
  15064. if (inputType) return;
  15065. if (!me.selection.getRange().collapsed) {
  15066. me.undoManger.save(false, true);
  15067. isCollapsed = false;
  15068. return;
  15069. }
  15070. if (me.undoManger.list.length == 0) {
  15071. me.undoManger.save(true);
  15072. }
  15073. clearTimeout(saveSceneTimer);
  15074. function save(cont) {
  15075. cont.undoManger.save(false, true);
  15076. cont.fireEvent("selectionchange");
  15077. }
  15078. saveSceneTimer = setTimeout(function () {
  15079. if (inputType) {
  15080. var interalTimer = setInterval(function () {
  15081. if (!inputType) {
  15082. save(me);
  15083. clearInterval(interalTimer);
  15084. }
  15085. }, 300);
  15086. return;
  15087. }
  15088. save(me);
  15089. }, 200);
  15090. lastKeyCode = keyCode;
  15091. keycont++;
  15092. if (keycont >= maxInputCount) {
  15093. save(me);
  15094. }
  15095. }
  15096. });
  15097. me.addListener("keyup", function (type, evt) {
  15098. var keyCode = evt.keyCode || evt.which;
  15099. if (
  15100. !keys[keyCode] &&
  15101. !evt.ctrlKey &&
  15102. !evt.metaKey &&
  15103. !evt.shiftKey &&
  15104. !evt.altKey
  15105. ) {
  15106. if (inputType) return;
  15107. if (!isCollapsed) {
  15108. this.undoManger.save(false, true);
  15109. isCollapsed = true;
  15110. }
  15111. }
  15112. });
  15113. //扩展实例,添加关闭和开启命令undo
  15114. me.stopCmdUndo = function () {
  15115. me.__hasEnterExecCommand = true;
  15116. };
  15117. me.startCmdUndo = function () {
  15118. me.__hasEnterExecCommand = false;
  15119. };
  15120. };
  15121. // plugins/copy.js
  15122. UE.plugin.register("copy", function () {
  15123. var me = this;
  15124. function initZeroClipboard() {
  15125. ZeroClipboard.config({
  15126. debug: false,
  15127. swfPath:
  15128. me.options.UEDITOR_HOME_URL +
  15129. "third-party/zeroclipboard/ZeroClipboard.swf"
  15130. });
  15131. var client = (me.zeroclipboard = new ZeroClipboard());
  15132. // 复制内容
  15133. client.on("copy", function (e) {
  15134. var client = e.client,
  15135. rng = me.selection.getRange(),
  15136. div = document.createElement("div");
  15137. div.appendChild(rng.cloneContents());
  15138. client.setText(div.innerText || div.textContent);
  15139. client.setHtml(div.innerHTML);
  15140. rng.select();
  15141. });
  15142. // hover事件传递到target
  15143. client.on("mouseover mouseout", function (e) {
  15144. var target = e.target;
  15145. if (target) {
  15146. if (e.type == "mouseover") {
  15147. domUtils.addClass(target, "edui-state-hover");
  15148. } else if (e.type == "mouseout") {
  15149. domUtils.removeClasses(target, "edui-state-hover");
  15150. }
  15151. }
  15152. });
  15153. // flash加载不成功
  15154. client.on("wrongflash noflash", function () {
  15155. ZeroClipboard.destroy();
  15156. });
  15157. // 触发事件
  15158. me.fireEvent("zeroclipboardready", client);
  15159. }
  15160. return {
  15161. bindEvents: {
  15162. ready: function () {
  15163. if (!browser.ie) {
  15164. if (window.ZeroClipboard) {
  15165. initZeroClipboard();
  15166. } else {
  15167. utils.loadFile(
  15168. document,
  15169. {
  15170. src:
  15171. me.options.UEDITOR_HOME_URL +
  15172. "third-party/zeroclipboard/ZeroClipboard.js",
  15173. tag: "script",
  15174. type: "text/javascript",
  15175. defer: "defer"
  15176. },
  15177. function () {
  15178. initZeroClipboard();
  15179. }
  15180. );
  15181. }
  15182. }
  15183. }
  15184. },
  15185. commands: {
  15186. copy: {
  15187. execCommand: function (cmd) {
  15188. if (!me.document.execCommand("copy")) {
  15189. alert(me.getLang("copymsg"));
  15190. }
  15191. }
  15192. }
  15193. }
  15194. };
  15195. });
  15196. // plugins/paste.js
  15197. ///import core
  15198. ///import plugins/inserthtml.js
  15199. ///import plugins/undo.js
  15200. ///import plugins/serialize.js
  15201. ///commands 粘贴
  15202. ///commandsName PastePlain
  15203. ///commandsTitle 纯文本粘贴模式
  15204. /**
  15205. * @description 粘贴
  15206. * @author zhanyi
  15207. */
  15208. UE.plugins["paste"] = function () {
  15209. function getClipboardData(callback) {
  15210. var doc = this.document;
  15211. if (doc.getElementById("baidu_pastebin")) {
  15212. return;
  15213. }
  15214. var range = this.selection.getRange(),
  15215. bk = range.createBookmark(),
  15216. //创建剪贴的容器div
  15217. pastebin = doc.createElement("div");
  15218. pastebin.id = "baidu_pastebin";
  15219. // Safari 要求div必须有内容,才能粘贴内容进来
  15220. browser.webkit &&
  15221. pastebin.appendChild(
  15222. doc.createTextNode(domUtils.fillChar + domUtils.fillChar)
  15223. );
  15224. doc.body.appendChild(pastebin);
  15225. //trace:717 隐藏的span不能得到top
  15226. //bk.start.innerHTML = '&nbsp;';
  15227. bk.start.style.display = "";
  15228. pastebin.style.cssText =
  15229. "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
  15230. //要在现在光标平行的位置加入,否则会出现跳动的问题
  15231. domUtils.getXY(bk.start).y +
  15232. "px";
  15233. range.selectNodeContents(pastebin).select(true);
  15234. setTimeout(function () {
  15235. if (browser.webkit) {
  15236. for (
  15237. var i = 0, pastebins = doc.querySelectorAll("#baidu_pastebin"), pi;
  15238. (pi = pastebins[i++]);
  15239. ) {
  15240. if (domUtils.isEmptyNode(pi)) {
  15241. domUtils.remove(pi);
  15242. } else {
  15243. pastebin = pi;
  15244. break;
  15245. }
  15246. }
  15247. }
  15248. try {
  15249. pastebin.parentNode.removeChild(pastebin);
  15250. } catch (e) {
  15251. }
  15252. range.moveToBookmark(bk).select(true);
  15253. callback(pastebin);
  15254. }, 0);
  15255. }
  15256. var me = this;
  15257. me.setOpt({
  15258. retainOnlyLabelPasted: false
  15259. });
  15260. var txtContent, htmlContent, address;
  15261. function getPureHtml(html) {
  15262. return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function (
  15263. a,
  15264. b,
  15265. tagName,
  15266. attrs
  15267. ) {
  15268. tagName = tagName.toLowerCase();
  15269. if ({img: 1}[tagName]) {
  15270. return a;
  15271. }
  15272. attrs = attrs.replace(
  15273. /([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi,
  15274. function (str, atr, val) {
  15275. if (
  15276. {
  15277. src: 1,
  15278. href: 1,
  15279. name: 1
  15280. }[atr.toLowerCase()]
  15281. ) {
  15282. return atr + "=" + val + " ";
  15283. }
  15284. return "";
  15285. }
  15286. );
  15287. if (
  15288. {
  15289. span: 1,
  15290. div: 1
  15291. }[tagName]
  15292. ) {
  15293. return "";
  15294. } else {
  15295. return "<" + b + tagName + " " + utils.trim(attrs) + ">";
  15296. }
  15297. });
  15298. }
  15299. function filter(div) {
  15300. var html;
  15301. if (div.firstChild) {
  15302. //去掉cut中添加的边界值
  15303. var nodes = domUtils.getElementsByTagName(div, "span");
  15304. for (var i = 0, ni; (ni = nodes[i++]);) {
  15305. if (ni.id == "_baidu_cut_start" || ni.id == "_baidu_cut_end") {
  15306. domUtils.remove(ni);
  15307. }
  15308. }
  15309. if (browser.webkit) {
  15310. var brs = div.querySelectorAll("div br");
  15311. for (var i = 0, bi; (bi = brs[i++]);) {
  15312. var pN = bi.parentNode;
  15313. if (pN.tagName == "DIV" && pN.childNodes.length == 1) {
  15314. pN.innerHTML = "<p><br/></p>";
  15315. domUtils.remove(pN);
  15316. }
  15317. }
  15318. var divs = div.querySelectorAll("#baidu_pastebin");
  15319. for (var i = 0, di; (di = divs[i++]);) {
  15320. var tmpP = me.document.createElement("p");
  15321. di.parentNode.insertBefore(tmpP, di);
  15322. while (di.firstChild) {
  15323. tmpP.appendChild(di.firstChild);
  15324. }
  15325. domUtils.remove(di);
  15326. }
  15327. var metas = div.querySelectorAll("meta");
  15328. for (var i = 0, ci; (ci = metas[i++]);) {
  15329. domUtils.remove(ci);
  15330. }
  15331. var brs = div.querySelectorAll("br");
  15332. for (i = 0; (ci = brs[i++]);) {
  15333. if (/^apple-/i.test(ci.className)) {
  15334. domUtils.remove(ci);
  15335. }
  15336. }
  15337. }
  15338. if (browser.gecko) {
  15339. var dirtyNodes = div.querySelectorAll("[_moz_dirty]");
  15340. for (i = 0; (ci = dirtyNodes[i++]);) {
  15341. ci.removeAttribute("_moz_dirty");
  15342. }
  15343. }
  15344. if (!browser.ie) {
  15345. var spans = div.querySelectorAll("span.Apple-style-span");
  15346. for (var i = 0, ci; (ci = spans[i++]);) {
  15347. domUtils.remove(ci, true);
  15348. }
  15349. }
  15350. //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
  15351. html = div.innerHTML; //.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
  15352. //过滤word粘贴过来的冗余属性
  15353. html = UE.filterWord(html);
  15354. //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
  15355. var root = UE.htmlparser(html);
  15356. //如果给了过滤规则就先进行过滤
  15357. if (me.options.filterRules) {
  15358. UE.filterNode(root, me.options.filterRules);
  15359. }
  15360. //执行默认的处理
  15361. me.filterInputRule(root);
  15362. //针对chrome的处理
  15363. if (browser.webkit) {
  15364. var br = root.lastChild();
  15365. if (br && br.type == "element" && br.tagName == "br") {
  15366. root.removeChild(br);
  15367. }
  15368. utils.each(me.body.querySelectorAll("div"), function (node) {
  15369. if (domUtils.isEmptyBlock(node)) {
  15370. domUtils.remove(node, true);
  15371. }
  15372. });
  15373. }
  15374. html = {html: root.toHtml()};
  15375. me.fireEvent("beforepaste", html, root);
  15376. //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
  15377. if (!html.html) {
  15378. return;
  15379. }
  15380. root = UE.htmlparser(html.html, true);
  15381. //如果开启了纯文本模式
  15382. if (me.queryCommandState("pasteplain") === 1) {
  15383. me.execCommand(
  15384. "insertHtml",
  15385. UE.filterNode(root, me.options.filterTxtRules).toHtml(),
  15386. true
  15387. );
  15388. } else {
  15389. //文本模式
  15390. UE.filterNode(root, me.options.filterTxtRules);
  15391. txtContent = root.toHtml();
  15392. //完全模式
  15393. htmlContent = html.html;
  15394. address = me.selection.getRange().createAddress(true);
  15395. me.execCommand(
  15396. "insertHtml",
  15397. me.getOpt("retainOnlyLabelPasted") === true
  15398. ? getPureHtml(htmlContent)
  15399. : htmlContent,
  15400. true
  15401. );
  15402. }
  15403. me.fireEvent("afterpaste", html);
  15404. }
  15405. }
  15406. me.addListener("pasteTransfer", function (cmd, plainType) {
  15407. if (address && txtContent && htmlContent && txtContent != htmlContent) {
  15408. var range = me.selection.getRange();
  15409. range.moveToAddress(address, true);
  15410. if (!range.collapsed) {
  15411. while (!domUtils.isBody(range.startContainer)) {
  15412. var start = range.startContainer;
  15413. if (start.nodeType == 1) {
  15414. start = start.childNodes[range.startOffset];
  15415. if (!start) {
  15416. range.setStartBefore(range.startContainer);
  15417. continue;
  15418. }
  15419. var pre = start.previousSibling;
  15420. if (
  15421. pre &&
  15422. pre.nodeType == 3 &&
  15423. new RegExp("^[\n\r\t " + domUtils.fillChar + "]*$").test(
  15424. pre.nodeValue
  15425. )
  15426. ) {
  15427. range.setStartBefore(pre);
  15428. }
  15429. }
  15430. if (range.startOffset == 0) {
  15431. range.setStartBefore(range.startContainer);
  15432. } else {
  15433. break;
  15434. }
  15435. }
  15436. while (!domUtils.isBody(range.endContainer)) {
  15437. var end = range.endContainer;
  15438. if (end.nodeType == 1) {
  15439. end = end.childNodes[range.endOffset];
  15440. if (!end) {
  15441. range.setEndAfter(range.endContainer);
  15442. continue;
  15443. }
  15444. var next = end.nextSibling;
  15445. if (
  15446. next &&
  15447. next.nodeType == 3 &&
  15448. new RegExp("^[\n\r\t" + domUtils.fillChar + "]*$").test(
  15449. next.nodeValue
  15450. )
  15451. ) {
  15452. range.setEndAfter(next);
  15453. }
  15454. }
  15455. if (
  15456. range.endOffset ==
  15457. range.endContainer[
  15458. range.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  15459. ].length
  15460. ) {
  15461. range.setEndAfter(range.endContainer);
  15462. } else {
  15463. break;
  15464. }
  15465. }
  15466. }
  15467. range.deleteContents();
  15468. range.select(true);
  15469. me.__hasEnterExecCommand = true;
  15470. var html = htmlContent;
  15471. if (plainType === 2) {
  15472. html = getPureHtml(html);
  15473. } else if (plainType) {
  15474. html = txtContent;
  15475. }
  15476. me.execCommand("inserthtml", html, true);
  15477. me.__hasEnterExecCommand = false;
  15478. var rng = me.selection.getRange();
  15479. while (
  15480. !domUtils.isBody(rng.startContainer) &&
  15481. !rng.startOffset &&
  15482. rng.startContainer[
  15483. rng.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  15484. ].length
  15485. ) {
  15486. rng.setStartBefore(rng.startContainer);
  15487. }
  15488. var tmpAddress = rng.createAddress(true);
  15489. address.endAddress = tmpAddress.startAddress;
  15490. }
  15491. });
  15492. me.addListener("ready", function () {
  15493. domUtils.on(me.body, "cut", function () {
  15494. var range = me.selection.getRange();
  15495. if (!range.collapsed && me.undoManger) {
  15496. me.undoManger.save();
  15497. }
  15498. });
  15499. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  15500. domUtils.on(
  15501. me.body,
  15502. browser.ie || browser.opera ? "keydown" : "paste",
  15503. function (e) {
  15504. if (
  15505. (browser.ie || browser.opera) &&
  15506. ((!e.ctrlKey && !e.metaKey) || e.keyCode != "86")
  15507. ) {
  15508. return;
  15509. }
  15510. getClipboardData.call(me, function (div) {
  15511. filter(div);
  15512. });
  15513. }
  15514. );
  15515. });
  15516. me.commands["paste"] = {
  15517. execCommand: function (cmd) {
  15518. if (browser.ie) {
  15519. getClipboardData.call(me, function (div) {
  15520. filter(div);
  15521. });
  15522. me.document.execCommand("paste");
  15523. } else {
  15524. alert(me.getLang("pastemsg"));
  15525. }
  15526. }
  15527. };
  15528. };
  15529. // plugins/puretxtpaste.js
  15530. /**
  15531. * 纯文本粘贴插件
  15532. * @file
  15533. * @since 1.2.6.1
  15534. */
  15535. UE.plugins["pasteplain"] = function () {
  15536. var me = this;
  15537. me.setOpt({
  15538. pasteplain: false,
  15539. filterTxtRules: (function () {
  15540. function transP(node) {
  15541. node.tagName = "p";
  15542. node.setStyle();
  15543. }
  15544. function removeNode(node) {
  15545. node.parentNode.removeChild(node, true);
  15546. }
  15547. return {
  15548. //直接删除及其字节点内容
  15549. "-": "script style object iframe embed input select",
  15550. p: {$: {}},
  15551. br: {$: {}},
  15552. div: function (node) {
  15553. var tmpNode,
  15554. p = UE.uNode.createElement("p");
  15555. while ((tmpNode = node.firstChild())) {
  15556. if (tmpNode.type == "text" || !UE.dom.dtd.$block[tmpNode.tagName]) {
  15557. p.appendChild(tmpNode);
  15558. } else {
  15559. if (p.firstChild()) {
  15560. node.parentNode.insertBefore(p, node);
  15561. p = UE.uNode.createElement("p");
  15562. } else {
  15563. node.parentNode.insertBefore(tmpNode, node);
  15564. }
  15565. }
  15566. }
  15567. if (p.firstChild()) {
  15568. node.parentNode.insertBefore(p, node);
  15569. }
  15570. node.parentNode.removeChild(node);
  15571. },
  15572. ol: removeNode,
  15573. ul: removeNode,
  15574. dl: removeNode,
  15575. dt: removeNode,
  15576. dd: removeNode,
  15577. li: removeNode,
  15578. caption: transP,
  15579. th: transP,
  15580. tr: transP,
  15581. h1: transP,
  15582. h2: transP,
  15583. h3: transP,
  15584. h4: transP,
  15585. h5: transP,
  15586. h6: transP,
  15587. td: function (node) {
  15588. //没有内容的td直接删掉
  15589. var txt = !!node.innerText();
  15590. if (txt) {
  15591. node.parentNode.insertAfter(
  15592. UE.uNode.createText(" &nbsp; &nbsp;"),
  15593. node
  15594. );
  15595. }
  15596. node.parentNode.removeChild(node, node.innerText());
  15597. }
  15598. };
  15599. })()
  15600. });
  15601. //暂时这里支持一下老版本的属性
  15602. var pasteplain = me.options.pasteplain;
  15603. /**
  15604. * 启用或取消纯文本粘贴模式
  15605. * @command pasteplain
  15606. * @method execCommand
  15607. * @param { String } cmd 命令字符串
  15608. * @example
  15609. * ```javascript
  15610. * editor.queryCommandState( 'pasteplain' );
  15611. * ```
  15612. */
  15613. /**
  15614. * 查询当前是否处于纯文本粘贴模式
  15615. * @command pasteplain
  15616. * @method queryCommandState
  15617. * @param { String } cmd 命令字符串
  15618. * @return { int } 如果处于纯文本模式,返回1,否则,返回0
  15619. * @example
  15620. * ```javascript
  15621. * editor.queryCommandState( 'pasteplain' );
  15622. * ```
  15623. */
  15624. me.commands["pasteplain"] = {
  15625. queryCommandState: function () {
  15626. return pasteplain ? 1 : 0;
  15627. },
  15628. execCommand: function () {
  15629. pasteplain = !pasteplain | 0;
  15630. },
  15631. notNeedUndo: 1
  15632. };
  15633. };
  15634. // plugins/list.js
  15635. /**
  15636. * 有序列表,无序列表插件
  15637. * @file
  15638. * @since 1.2.6.1
  15639. */
  15640. UE.plugins["list"] = function () {
  15641. var me = this,
  15642. notExchange = {
  15643. TD: 1,
  15644. PRE: 1,
  15645. BLOCKQUOTE: 1
  15646. };
  15647. var customStyle = {
  15648. cn: "cn-1-",
  15649. cn1: "cn-2-",
  15650. cn2: "cn-3-",
  15651. num: "num-1-",
  15652. num1: "num-2-",
  15653. num2: "num-3-",
  15654. dash: "dash",
  15655. dot: "dot"
  15656. };
  15657. me.setOpt({
  15658. autoTransWordToList: false,
  15659. insertorderedlist: {
  15660. num: "",
  15661. num1: "",
  15662. num2: "",
  15663. cn: "",
  15664. cn1: "",
  15665. cn2: "",
  15666. decimal: "",
  15667. "lower-alpha": "",
  15668. "lower-roman": "",
  15669. "upper-alpha": "",
  15670. "upper-roman": ""
  15671. },
  15672. insertunorderedlist: {
  15673. circle: "",
  15674. disc: "",
  15675. square: "",
  15676. dash: "",
  15677. dot: ""
  15678. },
  15679. listDefaultPaddingLeft: "30",
  15680. listiconpath: "http://bs.baidu.com/listicon/",
  15681. maxListLevel: -1, //-1不限制
  15682. disablePInList: false
  15683. });
  15684. function listToArray(list) {
  15685. var arr = [];
  15686. for (var p in list) {
  15687. arr.push(p);
  15688. }
  15689. return arr;
  15690. }
  15691. var listStyle = {
  15692. OL: listToArray(me.options.insertorderedlist),
  15693. UL: listToArray(me.options.insertunorderedlist)
  15694. };
  15695. var liiconpath = me.options.listiconpath;
  15696. //根据用户配置,调整customStyle
  15697. for (var s in customStyle) {
  15698. if (
  15699. !me.options.insertorderedlist.hasOwnProperty(s) &&
  15700. !me.options.insertunorderedlist.hasOwnProperty(s)
  15701. ) {
  15702. delete customStyle[s];
  15703. }
  15704. }
  15705. me.ready(function () {
  15706. var customCss = [];
  15707. for (var p in customStyle) {
  15708. if (p == "dash" || p == "dot") {
  15709. customCss.push(
  15710. "li.list-" +
  15711. customStyle[p] +
  15712. "{background-image:url(" +
  15713. liiconpath +
  15714. customStyle[p] +
  15715. ".gif)}"
  15716. );
  15717. customCss.push(
  15718. "ul.custom_" +
  15719. p +
  15720. "{list-style:none;}ul.custom_" +
  15721. p +
  15722. " li{background-position:0 3px;background-repeat:no-repeat}"
  15723. );
  15724. } else {
  15725. for (var i = 0; i < 99; i++) {
  15726. customCss.push(
  15727. "li.list-" +
  15728. customStyle[p] +
  15729. i +
  15730. "{background-image:url(" +
  15731. liiconpath +
  15732. "list-" +
  15733. customStyle[p] +
  15734. i +
  15735. ".gif)}"
  15736. );
  15737. }
  15738. customCss.push(
  15739. "ol.custom_" +
  15740. p +
  15741. "{list-style:none;}ol.custom_" +
  15742. p +
  15743. " li{background-position:0 3px;background-repeat:no-repeat}"
  15744. );
  15745. }
  15746. switch (p) {
  15747. case "cn":
  15748. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:25px}");
  15749. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
  15750. customCss.push("li.list-" + p + "-paddingleft-3{padding-left:55px}");
  15751. break;
  15752. case "cn1":
  15753. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:30px}");
  15754. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
  15755. customCss.push("li.list-" + p + "-paddingleft-3{padding-left:55px}");
  15756. break;
  15757. case "cn2":
  15758. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:40px}");
  15759. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:55px}");
  15760. customCss.push("li.list-" + p + "-paddingleft-3{padding-left:68px}");
  15761. break;
  15762. case "num":
  15763. case "num1":
  15764. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:25px}");
  15765. break;
  15766. case "num2":
  15767. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:35px}");
  15768. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
  15769. break;
  15770. case "dash":
  15771. customCss.push("li.list-" + p + "-paddingleft{padding-left:35px}");
  15772. break;
  15773. case "dot":
  15774. customCss.push("li.list-" + p + "-paddingleft{padding-left:20px}");
  15775. }
  15776. }
  15777. customCss.push(".list-paddingleft-1{padding-left:0}");
  15778. customCss.push(
  15779. ".list-paddingleft-2{padding-left:" +
  15780. me.options.listDefaultPaddingLeft +
  15781. "px}"
  15782. );
  15783. customCss.push(
  15784. ".list-paddingleft-3{padding-left:" +
  15785. me.options.listDefaultPaddingLeft * 2 +
  15786. "px}"
  15787. );
  15788. //如果不给宽度会在自定应样式里出现滚动条
  15789. utils.cssRule(
  15790. "list",
  15791. "ol,ul{margin:0;pading:0;" +
  15792. (browser.ie ? "" : "width:95%") +
  15793. "}li{clear:both;}" +
  15794. customCss.join("\n"),
  15795. me.document
  15796. );
  15797. });
  15798. //单独处理剪切的问题
  15799. me.ready(function () {
  15800. domUtils.on(me.body, "cut", function () {
  15801. setTimeout(function () {
  15802. var rng = me.selection.getRange(),
  15803. li;
  15804. //trace:3416
  15805. if (!rng.collapsed) {
  15806. if (
  15807. (li = domUtils.findParentByTagName(rng.startContainer, "li", true))
  15808. ) {
  15809. if (!li.nextSibling && domUtils.isEmptyBlock(li)) {
  15810. var pn = li.parentNode,
  15811. node;
  15812. if ((node = pn.previousSibling)) {
  15813. domUtils.remove(pn);
  15814. rng.setStartAtLast(node).collapse(true);
  15815. rng.select(true);
  15816. } else if ((node = pn.nextSibling)) {
  15817. domUtils.remove(pn);
  15818. rng.setStartAtFirst(node).collapse(true);
  15819. rng.select(true);
  15820. } else {
  15821. var tmpNode = me.document.createElement("p");
  15822. domUtils.fillNode(me.document, tmpNode);
  15823. pn.parentNode.insertBefore(tmpNode, pn);
  15824. domUtils.remove(pn);
  15825. rng.setStart(tmpNode, 0).collapse(true);
  15826. rng.select(true);
  15827. }
  15828. }
  15829. }
  15830. }
  15831. });
  15832. });
  15833. });
  15834. function getStyle(node) {
  15835. var cls = node.className;
  15836. if (domUtils.hasClass(node, /custom_/)) {
  15837. return cls.match(/custom_(\w+)/)[1];
  15838. }
  15839. return domUtils.getStyle(node, "list-style-type");
  15840. }
  15841. me.addListener("beforepaste", function (type, html) {
  15842. var me = this,
  15843. rng = me.selection.getRange(),
  15844. li;
  15845. var root = UE.htmlparser(html.html, true);
  15846. if ((li = domUtils.findParentByTagName(rng.startContainer, "li", true))) {
  15847. var list = li.parentNode,
  15848. tagName = list.tagName == "OL" ? "ul" : "ol";
  15849. utils.each(root.getNodesByTagName(tagName), function (n) {
  15850. n.tagName = list.tagName;
  15851. n.setAttr();
  15852. if (n.parentNode === root) {
  15853. type = getStyle(list) || (list.tagName == "OL" ? "decimal" : "disc");
  15854. } else {
  15855. var className = n.parentNode.getAttr("class");
  15856. if (className && /custom_/.test(className)) {
  15857. type = className.match(/custom_(\w+)/)[1];
  15858. } else {
  15859. type = n.parentNode.getStyle("list-style-type");
  15860. }
  15861. if (!type) {
  15862. type = list.tagName == "OL" ? "decimal" : "disc";
  15863. }
  15864. }
  15865. var index = utils.indexOf(listStyle[list.tagName], type);
  15866. if (n.parentNode !== root)
  15867. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  15868. var currentStyle = listStyle[list.tagName][index];
  15869. if (customStyle[currentStyle]) {
  15870. n.setAttr("class", "custom_" + currentStyle);
  15871. } else {
  15872. n.setStyle("list-style-type", currentStyle);
  15873. }
  15874. });
  15875. }
  15876. html.html = root.toHtml();
  15877. });
  15878. //导出时,去掉p标签
  15879. me.getOpt("disablePInList") === true &&
  15880. me.addOutputRule(function (root) {
  15881. utils.each(root.getNodesByTagName("li"), function (li) {
  15882. var newChildrens = [],
  15883. index = 0;
  15884. utils.each(li.children, function (n) {
  15885. if (n.tagName == "p") {
  15886. var tmpNode;
  15887. while ((tmpNode = n.children.pop())) {
  15888. newChildrens.splice(index, 0, tmpNode);
  15889. tmpNode.parentNode = li;
  15890. lastNode = tmpNode;
  15891. }
  15892. tmpNode = newChildrens[newChildrens.length - 1];
  15893. if (
  15894. !tmpNode ||
  15895. tmpNode.type != "element" ||
  15896. tmpNode.tagName != "br"
  15897. ) {
  15898. var br = UE.uNode.createElement("br");
  15899. br.parentNode = li;
  15900. newChildrens.push(br);
  15901. }
  15902. index = newChildrens.length;
  15903. }
  15904. });
  15905. if (newChildrens.length) {
  15906. li.children = newChildrens;
  15907. }
  15908. });
  15909. });
  15910. //进入编辑器的li要套p标签
  15911. me.addInputRule(function (root) {
  15912. utils.each(root.getNodesByTagName("li"), function (li) {
  15913. var tmpP = UE.uNode.createElement("p");
  15914. for (var i = 0, ci; (ci = li.children[i]);) {
  15915. if (ci.type == "text" || dtd.p[ci.tagName]) {
  15916. tmpP.appendChild(ci);
  15917. } else {
  15918. if (tmpP.firstChild()) {
  15919. li.insertBefore(tmpP, ci);
  15920. tmpP = UE.uNode.createElement("p");
  15921. i = i + 2;
  15922. } else {
  15923. i++;
  15924. }
  15925. }
  15926. }
  15927. if ((tmpP.firstChild() && !tmpP.parentNode) || !li.firstChild()) {
  15928. li.appendChild(tmpP);
  15929. }
  15930. //trace:3357
  15931. //p不能为空
  15932. if (!tmpP.firstChild()) {
  15933. tmpP.innerHTML(browser.ie ? "&nbsp;" : "<br/>");
  15934. }
  15935. //去掉末尾的空白
  15936. var p = li.firstChild();
  15937. var lastChild = p.lastChild();
  15938. if (
  15939. lastChild &&
  15940. lastChild.type == "text" &&
  15941. /^\s*$/.test(lastChild.data)
  15942. ) {
  15943. p.removeChild(lastChild);
  15944. }
  15945. });
  15946. if (me.options.autoTransWordToList) {
  15947. var orderlisttype = {
  15948. num1: /^\d+\)/,
  15949. decimal: /^\d+\./,
  15950. "lower-alpha": /^[a-z]+\)/,
  15951. "upper-alpha": /^[A-Z]+\./,
  15952. cn: /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
  15953. cn2: /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
  15954. },
  15955. unorderlisttype = {
  15956. square: "n"
  15957. };
  15958. function checkListType(content, container) {
  15959. var span = container.firstChild();
  15960. if (
  15961. span &&
  15962. span.type == "element" &&
  15963. span.tagName == "span" &&
  15964. /Wingdings|Symbol/.test(span.getStyle("font-family"))
  15965. ) {
  15966. for (var p in unorderlisttype) {
  15967. if (unorderlisttype[p] == span.data) {
  15968. return p;
  15969. }
  15970. }
  15971. return "disc";
  15972. }
  15973. for (var p in orderlisttype) {
  15974. if (orderlisttype[p].test(content)) {
  15975. return p;
  15976. }
  15977. }
  15978. }
  15979. utils.each(root.getNodesByTagName("p"), function (node) {
  15980. if (node.getAttr("class") != "MsoListParagraph") {
  15981. return;
  15982. }
  15983. //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
  15984. node.setStyle("margin", "");
  15985. node.setStyle("margin-left", "");
  15986. node.setAttr("class", "");
  15987. function appendLi(list, p, type) {
  15988. if (list.tagName == "ol") {
  15989. if (browser.ie) {
  15990. var first = p.firstChild();
  15991. if (
  15992. first.type == "element" &&
  15993. first.tagName == "span" &&
  15994. orderlisttype[type].test(first.innerText())
  15995. ) {
  15996. p.removeChild(first);
  15997. }
  15998. } else {
  15999. p.innerHTML(p.innerHTML().replace(orderlisttype[type], ""));
  16000. }
  16001. } else {
  16002. p.removeChild(p.firstChild());
  16003. }
  16004. var li = UE.uNode.createElement("li");
  16005. li.appendChild(p);
  16006. list.appendChild(li);
  16007. }
  16008. var tmp = node,
  16009. type,
  16010. cacheNode = node;
  16011. if (
  16012. node.parentNode.tagName != "li" &&
  16013. (type = checkListType(node.innerText(), node))
  16014. ) {
  16015. var list = UE.uNode.createElement(
  16016. me.options.insertorderedlist.hasOwnProperty(type) ? "ol" : "ul"
  16017. );
  16018. if (customStyle[type]) {
  16019. list.setAttr("class", "custom_" + type);
  16020. } else {
  16021. list.setStyle("list-style-type", type);
  16022. }
  16023. while (
  16024. node &&
  16025. node.parentNode.tagName != "li" &&
  16026. checkListType(node.innerText(), node)
  16027. ) {
  16028. tmp = node.nextSibling();
  16029. if (!tmp) {
  16030. node.parentNode.insertBefore(list, node);
  16031. }
  16032. appendLi(list, node, type);
  16033. node = tmp;
  16034. }
  16035. if (!list.parentNode && node && node.parentNode) {
  16036. node.parentNode.insertBefore(list, node);
  16037. }
  16038. }
  16039. var span = cacheNode.firstChild();
  16040. if (
  16041. span &&
  16042. span.type == "element" &&
  16043. span.tagName == "span" &&
  16044. /^\s*(&nbsp;)+\s*$/.test(span.innerText())
  16045. ) {
  16046. span.parentNode.removeChild(span);
  16047. }
  16048. });
  16049. }
  16050. });
  16051. //调整索引标签
  16052. me.addListener("contentchange", function () {
  16053. adjustListStyle(me.document);
  16054. });
  16055. function adjustListStyle(doc, ignore) {
  16056. utils.each(domUtils.getElementsByTagName(doc, "ol ul"), function (node) {
  16057. if (!domUtils.inDoc(node, doc)) return;
  16058. var parent = node.parentNode;
  16059. if (parent.tagName == node.tagName) {
  16060. var nodeStyleType =
  16061. getStyle(node) || (node.tagName == "OL" ? "decimal" : "disc"),
  16062. parentStyleType =
  16063. getStyle(parent) || (parent.tagName == "OL" ? "decimal" : "disc");
  16064. if (nodeStyleType == parentStyleType) {
  16065. var styleIndex = utils.indexOf(
  16066. listStyle[node.tagName],
  16067. nodeStyleType
  16068. );
  16069. styleIndex = styleIndex + 1 == listStyle[node.tagName].length
  16070. ? 0
  16071. : styleIndex + 1;
  16072. setListStyle(node, listStyle[node.tagName][styleIndex]);
  16073. }
  16074. }
  16075. var index = 0,
  16076. type = 2;
  16077. if (domUtils.hasClass(node, /custom_/)) {
  16078. if (
  16079. !(
  16080. /[ou]l/i.test(parent.tagName) &&
  16081. domUtils.hasClass(parent, /custom_/)
  16082. )
  16083. ) {
  16084. type = 1;
  16085. }
  16086. } else {
  16087. if (
  16088. /[ou]l/i.test(parent.tagName) &&
  16089. domUtils.hasClass(parent, /custom_/)
  16090. ) {
  16091. type = 3;
  16092. }
  16093. }
  16094. var style = domUtils.getStyle(node, "list-style-type");
  16095. style && (node.style.cssText = "list-style-type:" + style);
  16096. node.className =
  16097. utils.trim(node.className.replace(/list-paddingleft-\w+/, "")) +
  16098. " list-paddingleft-" +
  16099. type;
  16100. utils.each(domUtils.getElementsByTagName(node, "li"), function (li) {
  16101. li.style.cssText && (li.style.cssText = "");
  16102. if (!li.firstChild) {
  16103. domUtils.remove(li);
  16104. return;
  16105. }
  16106. if (li.parentNode !== node) {
  16107. return;
  16108. }
  16109. index++;
  16110. if (domUtils.hasClass(node, /custom_/)) {
  16111. var paddingLeft = 1,
  16112. currentStyle = getStyle(node);
  16113. if (node.tagName == "OL") {
  16114. if (currentStyle) {
  16115. switch (currentStyle) {
  16116. case "cn":
  16117. case "cn1":
  16118. case "cn2":
  16119. if (
  16120. index > 10 &&
  16121. (index % 10 == 0 || (index > 10 && index < 20))
  16122. ) {
  16123. paddingLeft = 2;
  16124. } else if (index > 20) {
  16125. paddingLeft = 3;
  16126. }
  16127. break;
  16128. case "num2":
  16129. if (index > 9) {
  16130. paddingLeft = 2;
  16131. }
  16132. }
  16133. }
  16134. li.className =
  16135. "list-" +
  16136. customStyle[currentStyle] +
  16137. index +
  16138. " " +
  16139. "list-" +
  16140. currentStyle +
  16141. "-paddingleft-" +
  16142. paddingLeft;
  16143. } else {
  16144. li.className =
  16145. "list-" +
  16146. customStyle[currentStyle] +
  16147. " " +
  16148. "list-" +
  16149. currentStyle +
  16150. "-paddingleft";
  16151. }
  16152. } else {
  16153. li.className = li.className.replace(/list-[\w\-]+/gi, "");
  16154. }
  16155. var className = li.getAttribute("class");
  16156. if (className !== null && !className.replace(/\s/g, "")) {
  16157. domUtils.removeAttributes(li, "class");
  16158. }
  16159. });
  16160. !ignore &&
  16161. adjustList(
  16162. node,
  16163. node.tagName.toLowerCase(),
  16164. getStyle(node) || domUtils.getStyle(node, "list-style-type"),
  16165. true
  16166. );
  16167. });
  16168. }
  16169. function adjustList(list, tag, style, ignoreEmpty) {
  16170. var nextList = list.nextSibling;
  16171. if (
  16172. nextList &&
  16173. nextList.nodeType == 1 &&
  16174. nextList.tagName.toLowerCase() == tag &&
  16175. (getStyle(nextList) ||
  16176. domUtils.getStyle(nextList, "list-style-type") ||
  16177. (tag == "ol" ? "decimal" : "disc")) == style
  16178. ) {
  16179. domUtils.moveChild(nextList, list);
  16180. if (nextList.childNodes.length == 0) {
  16181. domUtils.remove(nextList);
  16182. }
  16183. }
  16184. if (nextList && domUtils.isFillChar(nextList)) {
  16185. domUtils.remove(nextList);
  16186. }
  16187. var preList = list.previousSibling;
  16188. if (
  16189. preList &&
  16190. preList.nodeType == 1 &&
  16191. preList.tagName.toLowerCase() == tag &&
  16192. (getStyle(preList) ||
  16193. domUtils.getStyle(preList, "list-style-type") ||
  16194. (tag == "ol" ? "decimal" : "disc")) == style
  16195. ) {
  16196. domUtils.moveChild(list, preList);
  16197. }
  16198. if (preList && domUtils.isFillChar(preList)) {
  16199. domUtils.remove(preList);
  16200. }
  16201. !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
  16202. if (getStyle(list)) {
  16203. adjustListStyle(list.ownerDocument, true);
  16204. }
  16205. }
  16206. function setListStyle(list, style) {
  16207. if (customStyle[style]) {
  16208. list.className = "custom_" + style;
  16209. }
  16210. try {
  16211. domUtils.setStyle(list, "list-style-type", style);
  16212. } catch (e) {
  16213. }
  16214. }
  16215. function clearEmptySibling(node) {
  16216. var tmpNode = node.previousSibling;
  16217. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  16218. domUtils.remove(tmpNode);
  16219. }
  16220. tmpNode = node.nextSibling;
  16221. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  16222. domUtils.remove(tmpNode);
  16223. }
  16224. }
  16225. me.addListener("keydown", function (type, evt) {
  16226. function preventAndSave() {
  16227. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  16228. me.fireEvent("contentchange");
  16229. me.undoManger && me.undoManger.save();
  16230. }
  16231. function findList(node, filterFn) {
  16232. while (node && !domUtils.isBody(node)) {
  16233. if (filterFn(node)) {
  16234. return null;
  16235. }
  16236. if (node.nodeType == 1 && /[ou]l/i.test(node.tagName)) {
  16237. return node;
  16238. }
  16239. node = node.parentNode;
  16240. }
  16241. return null;
  16242. }
  16243. var keyCode = evt.keyCode || evt.which;
  16244. if (keyCode == 13 && !evt.shiftKey) {
  16245. //回车
  16246. var rng = me.selection.getRange(),
  16247. parent = domUtils.findParent(
  16248. rng.startContainer,
  16249. function (node) {
  16250. return domUtils.isBlockElm(node);
  16251. },
  16252. true
  16253. ),
  16254. li = domUtils.findParentByTagName(rng.startContainer, "li", true);
  16255. if (parent && parent.tagName != "PRE" && !li) {
  16256. var html = parent.innerHTML.replace(
  16257. new RegExp(domUtils.fillChar, "g"),
  16258. ""
  16259. );
  16260. if (/^\s*1\s*\.[^\d]/.test(html)) {
  16261. parent.innerHTML = html.replace(/^\s*1\s*\./, "");
  16262. rng.setStartAtLast(parent).collapse(true).select();
  16263. me.__hasEnterExecCommand = true;
  16264. me.execCommand("insertorderedlist");
  16265. me.__hasEnterExecCommand = false;
  16266. }
  16267. }
  16268. var range = me.selection.getRange(),
  16269. start = findList(range.startContainer, function (node) {
  16270. return node.tagName == "TABLE";
  16271. }),
  16272. end = range.collapsed
  16273. ? start
  16274. : findList(range.endContainer, function (node) {
  16275. return node.tagName == "TABLE";
  16276. });
  16277. if (start && end && start === end) {
  16278. if (!range.collapsed) {
  16279. start = domUtils.findParentByTagName(
  16280. range.startContainer,
  16281. "li",
  16282. true
  16283. );
  16284. end = domUtils.findParentByTagName(range.endContainer, "li", true);
  16285. if (start && end && start === end) {
  16286. range.deleteContents();
  16287. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16288. if (li && domUtils.isEmptyBlock(li)) {
  16289. pre = li.previousSibling;
  16290. next = li.nextSibling;
  16291. p = me.document.createElement("p");
  16292. domUtils.fillNode(me.document, p);
  16293. parentList = li.parentNode;
  16294. if (pre && next) {
  16295. range.setStart(next, 0).collapse(true).select(true);
  16296. domUtils.remove(li);
  16297. } else {
  16298. if ((!pre && !next) || !pre) {
  16299. parentList.parentNode.insertBefore(p, parentList);
  16300. } else {
  16301. li.parentNode.parentNode.insertBefore(
  16302. p,
  16303. parentList.nextSibling
  16304. );
  16305. }
  16306. domUtils.remove(li);
  16307. if (!parentList.firstChild) {
  16308. domUtils.remove(parentList);
  16309. }
  16310. range.setStart(p, 0).setCursor();
  16311. }
  16312. preventAndSave();
  16313. return;
  16314. }
  16315. } else {
  16316. var tmpRange = range.cloneRange(),
  16317. bk = tmpRange.collapse(false).createBookmark();
  16318. range.deleteContents();
  16319. tmpRange.moveToBookmark(bk);
  16320. var li = domUtils.findParentByTagName(
  16321. tmpRange.startContainer,
  16322. "li",
  16323. true
  16324. );
  16325. clearEmptySibling(li);
  16326. tmpRange.select();
  16327. preventAndSave();
  16328. return;
  16329. }
  16330. }
  16331. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16332. if (li) {
  16333. if (domUtils.isEmptyBlock(li)) {
  16334. bk = range.createBookmark();
  16335. var parentList = li.parentNode;
  16336. if (li !== parentList.lastChild) {
  16337. domUtils.breakParent(li, parentList);
  16338. clearEmptySibling(li);
  16339. } else {
  16340. parentList.parentNode.insertBefore(li, parentList.nextSibling);
  16341. if (domUtils.isEmptyNode(parentList)) {
  16342. domUtils.remove(parentList);
  16343. }
  16344. }
  16345. //嵌套不处理
  16346. if (!dtd.$list[li.parentNode.tagName]) {
  16347. if (!domUtils.isBlockElm(li.firstChild)) {
  16348. p = me.document.createElement("p");
  16349. li.parentNode.insertBefore(p, li);
  16350. while (li.firstChild) {
  16351. p.appendChild(li.firstChild);
  16352. }
  16353. domUtils.remove(li);
  16354. } else {
  16355. domUtils.remove(li, true);
  16356. }
  16357. }
  16358. range.moveToBookmark(bk).select();
  16359. } else {
  16360. var first = li.firstChild;
  16361. if (!first || !domUtils.isBlockElm(first)) {
  16362. var p = me.document.createElement("p");
  16363. !li.firstChild && domUtils.fillNode(me.document, p);
  16364. while (li.firstChild) {
  16365. p.appendChild(li.firstChild);
  16366. }
  16367. li.appendChild(p);
  16368. first = p;
  16369. }
  16370. var span = me.document.createElement("span");
  16371. range.insertNode(span);
  16372. domUtils.breakParent(span, li);
  16373. var nextLi = span.nextSibling;
  16374. first = nextLi.firstChild;
  16375. if (!first) {
  16376. p = me.document.createElement("p");
  16377. domUtils.fillNode(me.document, p);
  16378. nextLi.appendChild(p);
  16379. first = p;
  16380. }
  16381. if (domUtils.isEmptyNode(first)) {
  16382. first.innerHTML = "";
  16383. domUtils.fillNode(me.document, first);
  16384. }
  16385. range.setStart(first, 0).collapse(true).shrinkBoundary().select();
  16386. domUtils.remove(span);
  16387. var pre = nextLi.previousSibling;
  16388. if (pre && domUtils.isEmptyBlock(pre)) {
  16389. pre.innerHTML = "<p></p>";
  16390. domUtils.fillNode(me.document, pre.firstChild);
  16391. }
  16392. }
  16393. // }
  16394. preventAndSave();
  16395. }
  16396. }
  16397. }
  16398. if (keyCode == 8) {
  16399. //修中ie中li下的问题
  16400. range = me.selection.getRange();
  16401. if (range.collapsed && domUtils.isStartInblock(range)) {
  16402. tmpRange = range.cloneRange().trimBoundary();
  16403. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16404. //要在li的最左边,才能处理
  16405. if (li && domUtils.isStartInblock(tmpRange)) {
  16406. start = domUtils.findParentByTagName(range.startContainer, "p", true);
  16407. if (start && start !== li.firstChild) {
  16408. var parentList = domUtils.findParentByTagName(start, ["ol", "ul"]);
  16409. domUtils.breakParent(start, parentList);
  16410. clearEmptySibling(start);
  16411. me.fireEvent("contentchange");
  16412. range.setStart(start, 0).setCursor(false, true);
  16413. me.fireEvent("saveScene");
  16414. domUtils.preventDefault(evt);
  16415. return;
  16416. }
  16417. if (li && (pre = li.previousSibling)) {
  16418. if (keyCode == 46 && li.childNodes.length) {
  16419. return;
  16420. }
  16421. //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
  16422. if (dtd.$list[pre.tagName]) {
  16423. pre = pre.lastChild;
  16424. }
  16425. me.undoManger && me.undoManger.save();
  16426. first = li.firstChild;
  16427. if (domUtils.isBlockElm(first)) {
  16428. if (domUtils.isEmptyNode(first)) {
  16429. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  16430. pre.appendChild(first);
  16431. range.setStart(first, 0).setCursor(false, true);
  16432. //first不是唯一的节点
  16433. while (li.firstChild) {
  16434. pre.appendChild(li.firstChild);
  16435. }
  16436. } else {
  16437. span = me.document.createElement("span");
  16438. range.insertNode(span);
  16439. //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
  16440. if (domUtils.isEmptyBlock(pre)) {
  16441. pre.innerHTML = "";
  16442. }
  16443. domUtils.moveChild(li, pre);
  16444. range.setStartBefore(span).collapse(true).select(true);
  16445. domUtils.remove(span);
  16446. }
  16447. } else {
  16448. if (domUtils.isEmptyNode(li)) {
  16449. var p = me.document.createElement("p");
  16450. pre.appendChild(p);
  16451. range.setStart(p, 0).setCursor();
  16452. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  16453. } else {
  16454. range
  16455. .setEnd(pre, pre.childNodes.length)
  16456. .collapse()
  16457. .select(true);
  16458. while (li.firstChild) {
  16459. pre.appendChild(li.firstChild);
  16460. }
  16461. }
  16462. }
  16463. domUtils.remove(li);
  16464. me.fireEvent("contentchange");
  16465. me.fireEvent("saveScene");
  16466. domUtils.preventDefault(evt);
  16467. return;
  16468. }
  16469. //trace:980
  16470. if (li && !li.previousSibling) {
  16471. var parentList = li.parentNode;
  16472. var bk = range.createBookmark();
  16473. if (domUtils.isTagNode(parentList.parentNode, "ol ul")) {
  16474. parentList.parentNode.insertBefore(li, parentList);
  16475. if (domUtils.isEmptyNode(parentList)) {
  16476. domUtils.remove(parentList);
  16477. }
  16478. } else {
  16479. while (li.firstChild) {
  16480. parentList.parentNode.insertBefore(li.firstChild, parentList);
  16481. }
  16482. domUtils.remove(li);
  16483. if (domUtils.isEmptyNode(parentList)) {
  16484. domUtils.remove(parentList);
  16485. }
  16486. }
  16487. range.moveToBookmark(bk).setCursor(false, true);
  16488. me.fireEvent("contentchange");
  16489. me.fireEvent("saveScene");
  16490. domUtils.preventDefault(evt);
  16491. return;
  16492. }
  16493. }
  16494. }
  16495. }
  16496. });
  16497. me.addListener("keyup", function (type, evt) {
  16498. var keyCode = evt.keyCode || evt.which;
  16499. if (keyCode == 8) {
  16500. var rng = me.selection.getRange(),
  16501. list;
  16502. if (
  16503. (list = domUtils.findParentByTagName(
  16504. rng.startContainer,
  16505. ["ol", "ul"],
  16506. true
  16507. ))
  16508. ) {
  16509. adjustList(
  16510. list,
  16511. list.tagName.toLowerCase(),
  16512. getStyle(list) || domUtils.getComputedStyle(list, "list-style-type"),
  16513. true
  16514. );
  16515. }
  16516. }
  16517. });
  16518. //处理tab键
  16519. me.addListener("tabkeydown", function () {
  16520. var range = me.selection.getRange();
  16521. //控制级数
  16522. function checkLevel(li) {
  16523. if (me.options.maxListLevel != -1) {
  16524. var level = li.parentNode,
  16525. levelNum = 0;
  16526. while (/[ou]l/i.test(level.tagName)) {
  16527. levelNum++;
  16528. level = level.parentNode;
  16529. }
  16530. if (levelNum >= me.options.maxListLevel) {
  16531. return true;
  16532. }
  16533. }
  16534. }
  16535. //只以开始为准
  16536. //todo 后续改进
  16537. var li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16538. if (li) {
  16539. var bk;
  16540. if (range.collapsed) {
  16541. if (checkLevel(li)) return true;
  16542. var parentLi = li.parentNode,
  16543. list = me.document.createElement(parentLi.tagName),
  16544. index = utils.indexOf(
  16545. listStyle[list.tagName],
  16546. getStyle(parentLi) ||
  16547. domUtils.getComputedStyle(parentLi, "list-style-type")
  16548. );
  16549. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  16550. var currentStyle = listStyle[list.tagName][index];
  16551. setListStyle(list, currentStyle);
  16552. if (domUtils.isStartInblock(range)) {
  16553. me.fireEvent("saveScene");
  16554. bk = range.createBookmark();
  16555. parentLi.insertBefore(list, li);
  16556. list.appendChild(li);
  16557. adjustList(list, list.tagName.toLowerCase(), currentStyle);
  16558. me.fireEvent("contentchange");
  16559. range.moveToBookmark(bk).select(true);
  16560. return true;
  16561. }
  16562. } else {
  16563. me.fireEvent("saveScene");
  16564. bk = range.createBookmark();
  16565. for (
  16566. var i = 0, closeList, parents = domUtils.findParents(li), ci;
  16567. (ci = parents[i++]);
  16568. ) {
  16569. if (domUtils.isTagNode(ci, "ol ul")) {
  16570. closeList = ci;
  16571. break;
  16572. }
  16573. }
  16574. var current = li;
  16575. if (bk.end) {
  16576. while (
  16577. current &&
  16578. !(
  16579. domUtils.getPosition(current, bk.end) &
  16580. domUtils.POSITION_FOLLOWING
  16581. )
  16582. ) {
  16583. if (checkLevel(current)) {
  16584. current = domUtils.getNextDomNode(current, false, null, function (
  16585. node
  16586. ) {
  16587. return node !== closeList;
  16588. });
  16589. continue;
  16590. }
  16591. var parentLi = current.parentNode,
  16592. list = me.document.createElement(parentLi.tagName),
  16593. index = utils.indexOf(
  16594. listStyle[list.tagName],
  16595. getStyle(parentLi) ||
  16596. domUtils.getComputedStyle(parentLi, "list-style-type")
  16597. );
  16598. var currentIndex = index + 1 == listStyle[list.tagName].length
  16599. ? 0
  16600. : index + 1;
  16601. var currentStyle = listStyle[list.tagName][currentIndex];
  16602. setListStyle(list, currentStyle);
  16603. parentLi.insertBefore(list, current);
  16604. while (
  16605. current &&
  16606. !(
  16607. domUtils.getPosition(current, bk.end) &
  16608. domUtils.POSITION_FOLLOWING
  16609. )
  16610. ) {
  16611. li = current.nextSibling;
  16612. list.appendChild(current);
  16613. if (!li || domUtils.isTagNode(li, "ol ul")) {
  16614. if (li) {
  16615. while ((li = li.firstChild)) {
  16616. if (li.tagName == "LI") {
  16617. break;
  16618. }
  16619. }
  16620. } else {
  16621. li = domUtils.getNextDomNode(current, false, null, function (
  16622. node
  16623. ) {
  16624. return node !== closeList;
  16625. });
  16626. }
  16627. break;
  16628. }
  16629. current = li;
  16630. }
  16631. adjustList(list, list.tagName.toLowerCase(), currentStyle);
  16632. current = li;
  16633. }
  16634. }
  16635. me.fireEvent("contentchange");
  16636. range.moveToBookmark(bk).select();
  16637. return true;
  16638. }
  16639. }
  16640. });
  16641. function getLi(start) {
  16642. while (start && !domUtils.isBody(start)) {
  16643. if (start.nodeName == "TABLE") {
  16644. return null;
  16645. }
  16646. if (start.nodeName == "LI") {
  16647. return start;
  16648. }
  16649. start = start.parentNode;
  16650. }
  16651. }
  16652. /**
  16653. * 有序列表,与“insertunorderedlist”命令互斥
  16654. * @command insertorderedlist
  16655. * @method execCommand
  16656. * @param { String } command 命令字符串
  16657. * @param { String } style 插入的有序列表类型,值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  16658. * @example
  16659. * ```javascript
  16660. * editor.execCommand( 'insertorderedlist','decimal');
  16661. * ```
  16662. */
  16663. /**
  16664. * 查询当前选区内容是否有序列表
  16665. * @command insertorderedlist
  16666. * @method queryCommandState
  16667. * @param { String } cmd 命令字符串
  16668. * @return { int } 如果当前选区是有序列表返回1,否则返回0
  16669. * @example
  16670. * ```javascript
  16671. * editor.queryCommandState( 'insertorderedlist' );
  16672. * ```
  16673. */
  16674. /**
  16675. * 查询当前选区内容是否有序列表
  16676. * @command insertorderedlist
  16677. * @method queryCommandValue
  16678. * @param { String } cmd 命令字符串
  16679. * @return { String } 返回当前有序列表的类型,值为null或decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  16680. * @example
  16681. * ```javascript
  16682. * editor.queryCommandValue( 'insertorderedlist' );
  16683. * ```
  16684. */
  16685. /**
  16686. * 无序列表,与“insertorderedlist”命令互斥
  16687. * @command insertunorderedlist
  16688. * @method execCommand
  16689. * @param { String } command 命令字符串
  16690. * @param { String } style 插入的无序列表类型,值为:circle,disc,square,dash,dot
  16691. * @example
  16692. * ```javascript
  16693. * editor.execCommand( 'insertunorderedlist','circle');
  16694. * ```
  16695. */
  16696. /**
  16697. * 查询当前是否有word文档粘贴进来的图片
  16698. * @command insertunorderedlist
  16699. * @method insertunorderedlist
  16700. * @param { String } command 命令字符串
  16701. * @return { int } 如果当前选区是无序列表返回1,否则返回0
  16702. * @example
  16703. * ```javascript
  16704. * editor.queryCommandState( 'insertunorderedlist' );
  16705. * ```
  16706. */
  16707. /**
  16708. * 查询当前选区内容是否有序列表
  16709. * @command insertunorderedlist
  16710. * @method queryCommandValue
  16711. * @param { String } command 命令字符串
  16712. * @return { String } 返回当前无序列表的类型,值为null或circle,disc,square,dash,dot
  16713. * @example
  16714. * ```javascript
  16715. * editor.queryCommandValue( 'insertunorderedlist' );
  16716. * ```
  16717. */
  16718. me.commands["insertorderedlist"] = me.commands["insertunorderedlist"] = {
  16719. execCommand: function (command, style) {
  16720. if (!style) {
  16721. style = command.toLowerCase() == "insertorderedlist"
  16722. ? "decimal"
  16723. : "disc";
  16724. }
  16725. var me = this,
  16726. range = this.selection.getRange(),
  16727. filterFn = function (node) {
  16728. return node.nodeType == 1
  16729. ? node.tagName.toLowerCase() != "br"
  16730. : !domUtils.isWhitespace(node);
  16731. },
  16732. tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul",
  16733. frag = me.document.createDocumentFragment();
  16734. //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
  16735. //range.shrinkBoundary();//.adjustmentBoundary();
  16736. range.adjustmentBoundary().shrinkBoundary();
  16737. var bko = range.createBookmark(true),
  16738. start = getLi(me.document.getElementById(bko.start)),
  16739. modifyStart = 0,
  16740. end = getLi(me.document.getElementById(bko.end)),
  16741. modifyEnd = 0,
  16742. startParent,
  16743. endParent,
  16744. list,
  16745. tmp;
  16746. if (start || end) {
  16747. start && (startParent = start.parentNode);
  16748. if (!bko.end) {
  16749. end = start;
  16750. }
  16751. end && (endParent = end.parentNode);
  16752. if (startParent === endParent) {
  16753. while (start !== end) {
  16754. tmp = start;
  16755. start = start.nextSibling;
  16756. if (!domUtils.isBlockElm(tmp.firstChild)) {
  16757. var p = me.document.createElement("p");
  16758. while (tmp.firstChild) {
  16759. p.appendChild(tmp.firstChild);
  16760. }
  16761. tmp.appendChild(p);
  16762. }
  16763. frag.appendChild(tmp);
  16764. }
  16765. tmp = me.document.createElement("span");
  16766. startParent.insertBefore(tmp, end);
  16767. if (!domUtils.isBlockElm(end.firstChild)) {
  16768. p = me.document.createElement("p");
  16769. while (end.firstChild) {
  16770. p.appendChild(end.firstChild);
  16771. }
  16772. end.appendChild(p);
  16773. }
  16774. frag.appendChild(end);
  16775. domUtils.breakParent(tmp, startParent);
  16776. if (domUtils.isEmptyNode(tmp.previousSibling)) {
  16777. domUtils.remove(tmp.previousSibling);
  16778. }
  16779. if (domUtils.isEmptyNode(tmp.nextSibling)) {
  16780. domUtils.remove(tmp.nextSibling);
  16781. }
  16782. var nodeStyle =
  16783. getStyle(startParent) ||
  16784. domUtils.getComputedStyle(startParent, "list-style-type") ||
  16785. (command.toLowerCase() == "insertorderedlist" ? "decimal" : "disc");
  16786. if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
  16787. for (
  16788. var i = 0, ci, tmpFrag = me.document.createDocumentFragment();
  16789. (ci = frag.firstChild);
  16790. ) {
  16791. if (domUtils.isTagNode(ci, "ol ul")) {
  16792. // 删除时,子列表不处理
  16793. // utils.each(domUtils.getElementsByTagName(ci,'li'),function(li){
  16794. // while(li.firstChild){
  16795. // tmpFrag.appendChild(li.firstChild);
  16796. // }
  16797. //
  16798. // });
  16799. tmpFrag.appendChild(ci);
  16800. } else {
  16801. while (ci.firstChild) {
  16802. tmpFrag.appendChild(ci.firstChild);
  16803. domUtils.remove(ci);
  16804. }
  16805. }
  16806. }
  16807. tmp.parentNode.insertBefore(tmpFrag, tmp);
  16808. } else {
  16809. list = me.document.createElement(tag);
  16810. setListStyle(list, style);
  16811. list.appendChild(frag);
  16812. tmp.parentNode.insertBefore(list, tmp);
  16813. }
  16814. domUtils.remove(tmp);
  16815. list && adjustList(list, tag, style);
  16816. range.moveToBookmark(bko).select();
  16817. return;
  16818. }
  16819. //开始
  16820. if (start) {
  16821. while (start) {
  16822. tmp = start.nextSibling;
  16823. if (domUtils.isTagNode(start, "ol ul")) {
  16824. frag.appendChild(start);
  16825. } else {
  16826. var tmpfrag = me.document.createDocumentFragment(),
  16827. hasBlock = 0;
  16828. while (start.firstChild) {
  16829. if (domUtils.isBlockElm(start.firstChild)) {
  16830. hasBlock = 1;
  16831. }
  16832. tmpfrag.appendChild(start.firstChild);
  16833. }
  16834. if (!hasBlock) {
  16835. var tmpP = me.document.createElement("p");
  16836. tmpP.appendChild(tmpfrag);
  16837. frag.appendChild(tmpP);
  16838. } else {
  16839. frag.appendChild(tmpfrag);
  16840. }
  16841. domUtils.remove(start);
  16842. }
  16843. start = tmp;
  16844. }
  16845. startParent.parentNode.insertBefore(frag, startParent.nextSibling);
  16846. if (domUtils.isEmptyNode(startParent)) {
  16847. range.setStartBefore(startParent);
  16848. domUtils.remove(startParent);
  16849. } else {
  16850. range.setStartAfter(startParent);
  16851. }
  16852. modifyStart = 1;
  16853. }
  16854. if (end && domUtils.inDoc(endParent, me.document)) {
  16855. //结束
  16856. start = endParent.firstChild;
  16857. while (start && start !== end) {
  16858. tmp = start.nextSibling;
  16859. if (domUtils.isTagNode(start, "ol ul")) {
  16860. frag.appendChild(start);
  16861. } else {
  16862. tmpfrag = me.document.createDocumentFragment();
  16863. hasBlock = 0;
  16864. while (start.firstChild) {
  16865. if (domUtils.isBlockElm(start.firstChild)) {
  16866. hasBlock = 1;
  16867. }
  16868. tmpfrag.appendChild(start.firstChild);
  16869. }
  16870. if (!hasBlock) {
  16871. tmpP = me.document.createElement("p");
  16872. tmpP.appendChild(tmpfrag);
  16873. frag.appendChild(tmpP);
  16874. } else {
  16875. frag.appendChild(tmpfrag);
  16876. }
  16877. domUtils.remove(start);
  16878. }
  16879. start = tmp;
  16880. }
  16881. var tmpDiv = domUtils.createElement(me.document, "div", {
  16882. tmpDiv: 1
  16883. });
  16884. domUtils.moveChild(end, tmpDiv);
  16885. frag.appendChild(tmpDiv);
  16886. domUtils.remove(end);
  16887. endParent.parentNode.insertBefore(frag, endParent);
  16888. range.setEndBefore(endParent);
  16889. if (domUtils.isEmptyNode(endParent)) {
  16890. domUtils.remove(endParent);
  16891. }
  16892. modifyEnd = 1;
  16893. }
  16894. }
  16895. if (!modifyStart) {
  16896. range.setStartBefore(me.document.getElementById(bko.start));
  16897. }
  16898. if (bko.end && !modifyEnd) {
  16899. range.setEndAfter(me.document.getElementById(bko.end));
  16900. }
  16901. range.enlarge(true, function (node) {
  16902. return notExchange[node.tagName];
  16903. });
  16904. frag = me.document.createDocumentFragment();
  16905. var bk = range.createBookmark(),
  16906. current = domUtils.getNextDomNode(bk.start, false, filterFn),
  16907. tmpRange = range.cloneRange(),
  16908. tmpNode,
  16909. block = domUtils.isBlockElm;
  16910. while (
  16911. current &&
  16912. current !== bk.end &&
  16913. domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING
  16914. ) {
  16915. if (current.nodeType == 3 || dtd.li[current.tagName]) {
  16916. if (current.nodeType == 1 && dtd.$list[current.tagName]) {
  16917. while (current.firstChild) {
  16918. frag.appendChild(current.firstChild);
  16919. }
  16920. tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  16921. domUtils.remove(current);
  16922. current = tmpNode;
  16923. continue;
  16924. }
  16925. tmpNode = current;
  16926. tmpRange.setStartBefore(current);
  16927. while (
  16928. current &&
  16929. current !== bk.end &&
  16930. (!block(current) || domUtils.isBookmarkNode(current))
  16931. ) {
  16932. tmpNode = current;
  16933. current = domUtils.getNextDomNode(current, false, null, function (
  16934. node
  16935. ) {
  16936. return !notExchange[node.tagName];
  16937. });
  16938. }
  16939. if (current && block(current)) {
  16940. tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
  16941. if (tmp && domUtils.isBookmarkNode(tmp)) {
  16942. current = domUtils.getNextDomNode(tmp, false, filterFn);
  16943. tmpNode = tmp;
  16944. }
  16945. }
  16946. tmpRange.setEndAfter(tmpNode);
  16947. current = domUtils.getNextDomNode(tmpNode, false, filterFn);
  16948. var li = range.document.createElement("li");
  16949. li.appendChild(tmpRange.extractContents());
  16950. if (domUtils.isEmptyNode(li)) {
  16951. var tmpNode = range.document.createElement("p");
  16952. while (li.firstChild) {
  16953. tmpNode.appendChild(li.firstChild);
  16954. }
  16955. li.appendChild(tmpNode);
  16956. }
  16957. frag.appendChild(li);
  16958. } else {
  16959. current = domUtils.getNextDomNode(current, true, filterFn);
  16960. }
  16961. }
  16962. range.moveToBookmark(bk).collapse(true);
  16963. list = me.document.createElement(tag);
  16964. setListStyle(list, style);
  16965. list.appendChild(frag);
  16966. range.insertNode(list);
  16967. //当前list上下看能否合并
  16968. adjustList(list, tag, style);
  16969. //去掉冗余的tmpDiv
  16970. for (
  16971. var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, "div");
  16972. (ci = tmpDivs[i++]);
  16973. ) {
  16974. if (ci.getAttribute("tmpDiv")) {
  16975. domUtils.remove(ci, true);
  16976. }
  16977. }
  16978. range.moveToBookmark(bko).select();
  16979. },
  16980. queryCommandState: function (command) {
  16981. var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
  16982. var path = this.selection.getStartElementPath();
  16983. for (var i = 0, ci; (ci = path[i++]);) {
  16984. if (ci.nodeName == "TABLE") {
  16985. return 0;
  16986. }
  16987. if (tag == ci.nodeName.toLowerCase()) {
  16988. return 1;
  16989. }
  16990. }
  16991. return 0;
  16992. },
  16993. queryCommandValue: function (command) {
  16994. var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
  16995. var path = this.selection.getStartElementPath(),
  16996. node;
  16997. for (var i = 0, ci; (ci = path[i++]);) {
  16998. if (ci.nodeName == "TABLE") {
  16999. node = null;
  17000. break;
  17001. }
  17002. if (tag == ci.nodeName.toLowerCase()) {
  17003. node = ci;
  17004. break;
  17005. }
  17006. }
  17007. return node
  17008. ? getStyle(node) || domUtils.getComputedStyle(node, "list-style-type")
  17009. : null;
  17010. }
  17011. };
  17012. };
  17013. // plugins/source.js
  17014. /**
  17015. * 源码编辑插件
  17016. * @file
  17017. * @since 1.2.6.1
  17018. */
  17019. ;(function () {
  17020. var sourceEditors = {
  17021. textarea: function (editor, holder) {
  17022. var textarea = holder.ownerDocument.createElement("textarea");
  17023. textarea.style.cssText =
  17024. "position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;";
  17025. // todo: IE下只有onresize属性可用... 很纠结
  17026. if (browser.ie && browser.version < 8) {
  17027. textarea.style.width = holder.offsetWidth + "px";
  17028. textarea.style.height = holder.offsetHeight + "px";
  17029. holder.onresize = function () {
  17030. textarea.style.width = holder.offsetWidth + "px";
  17031. textarea.style.height = holder.offsetHeight + "px";
  17032. };
  17033. }
  17034. holder.appendChild(textarea);
  17035. return {
  17036. setContent: function (content) {
  17037. textarea.value = content;
  17038. },
  17039. getContent: function () {
  17040. return textarea.value;
  17041. },
  17042. select: function () {
  17043. var range;
  17044. if (browser.ie) {
  17045. range = textarea.createTextRange();
  17046. range.collapse(true);
  17047. range.select();
  17048. } else {
  17049. //todo: chrome下无法设置焦点
  17050. textarea.setSelectionRange(0, 0);
  17051. textarea.focus();
  17052. }
  17053. },
  17054. dispose: function () {
  17055. holder.removeChild(textarea);
  17056. // todo
  17057. holder.onresize = null;
  17058. textarea = null;
  17059. holder = null;
  17060. },
  17061. focus: function () {
  17062. textarea.focus();
  17063. },
  17064. blur: function () {
  17065. textarea.blur();
  17066. }
  17067. };
  17068. },
  17069. codemirror: function (editor, holder) {
  17070. var codeEditor = window.CodeMirror(holder, {
  17071. mode: "text/html",
  17072. tabMode: "indent",
  17073. lineNumbers: true,
  17074. lineWrapping: true
  17075. });
  17076. var dom = codeEditor.getWrapperElement();
  17077. dom.style.cssText =
  17078. 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
  17079. codeEditor.getScrollerElement().style.cssText =
  17080. "position:absolute;left:0;top:0;width:100%;height:100%;";
  17081. codeEditor.refresh();
  17082. return {
  17083. getCodeMirror: function () {
  17084. return codeEditor;
  17085. },
  17086. setContent: function (content) {
  17087. codeEditor.setValue(content);
  17088. },
  17089. getContent: function () {
  17090. return codeEditor.getValue();
  17091. },
  17092. select: function () {
  17093. codeEditor.focus();
  17094. },
  17095. dispose: function () {
  17096. holder.removeChild(dom);
  17097. dom = null;
  17098. codeEditor = null;
  17099. },
  17100. focus: function () {
  17101. codeEditor.focus();
  17102. },
  17103. blur: function () {
  17104. // codeEditor.blur();
  17105. // since codemirror not support blur()
  17106. codeEditor.setOption('readOnly', true);
  17107. codeEditor.setOption('readOnly', false);
  17108. }
  17109. };
  17110. }
  17111. };
  17112. UE.plugins["source"] = function () {
  17113. var me = this;
  17114. var opt = this.options;
  17115. var sourceMode = false;
  17116. var sourceEditor;
  17117. var orgSetContent;
  17118. var orgFocus;
  17119. var orgBlur;
  17120. opt.sourceEditor = browser.ie
  17121. ? "textarea"
  17122. : opt.sourceEditor || "codemirror";
  17123. me.setOpt({
  17124. sourceEditorFirst: false
  17125. });
  17126. function createSourceEditor(holder) {
  17127. return sourceEditors[
  17128. opt.sourceEditor == "codemirror" && window.CodeMirror
  17129. ? "codemirror"
  17130. : "textarea"
  17131. ](me, holder);
  17132. }
  17133. var bakCssText;
  17134. //解决在源码模式下getContent不能得到最新的内容问题
  17135. var oldGetContent, bakAddress;
  17136. /**
  17137. * 切换源码模式和编辑模式
  17138. * @command source
  17139. * @method execCommand
  17140. * @param { String } cmd 命令字符串
  17141. * @example
  17142. * ```javascript
  17143. * editor.execCommand( 'source');
  17144. * ```
  17145. */
  17146. /**
  17147. * 查询当前编辑区域的状态是源码模式还是可视化模式
  17148. * @command source
  17149. * @method queryCommandState
  17150. * @param { String } cmd 命令字符串
  17151. * @return { int } 如果当前是源码编辑模式,返回1,否则返回0
  17152. * @example
  17153. * ```javascript
  17154. * editor.queryCommandState( 'source' );
  17155. * ```
  17156. */
  17157. me.commands["source"] = {
  17158. execCommand: function () {
  17159. sourceMode = !sourceMode;
  17160. if (sourceMode) {
  17161. bakAddress = me.selection.getRange().createAddress(false, true);
  17162. me.undoManger && me.undoManger.save(true);
  17163. if (browser.gecko) {
  17164. me.body.contentEditable = false;
  17165. }
  17166. bakCssText = me.iframe.style.cssText;
  17167. me.iframe.style.cssText +=
  17168. "position:absolute;left:-32768px;top:-32768px;";
  17169. me.fireEvent("beforegetcontent");
  17170. var root = UE.htmlparser(me.body.innerHTML);
  17171. me.filterOutputRule(root);
  17172. root.traversal(function (node) {
  17173. if (node.type == "element") {
  17174. switch (node.tagName) {
  17175. case "td":
  17176. case "th":
  17177. case "caption":
  17178. if (node.children && node.children.length == 1) {
  17179. if (node.firstChild().tagName == "br") {
  17180. node.removeChild(node.firstChild());
  17181. }
  17182. }
  17183. break;
  17184. case "pre":
  17185. node.innerText(node.innerText().replace(/&nbsp;/g, " "));
  17186. }
  17187. }
  17188. });
  17189. me.fireEvent("aftergetcontent");
  17190. var content = root.toHtml(true);
  17191. sourceEditor = createSourceEditor(me.iframe.parentNode);
  17192. sourceEditor.setContent(content);
  17193. orgSetContent = me.setContent;
  17194. me.setContent = function (html) {
  17195. //这里暂时不触发事件,防止报错
  17196. var root = UE.htmlparser(html);
  17197. me.filterInputRule(root);
  17198. html = root.toHtml();
  17199. sourceEditor.setContent(html);
  17200. };
  17201. setTimeout(function () {
  17202. sourceEditor.select();
  17203. me.addListener("fullscreenchanged", function () {
  17204. try {
  17205. sourceEditor.getCodeMirror().refresh();
  17206. } catch (e) {
  17207. }
  17208. });
  17209. });
  17210. //重置getContent,源码模式下取值也能是最新的数据
  17211. oldGetContent = me.getContent;
  17212. me.getContent = function () {
  17213. return (
  17214. sourceEditor.getContent() ||
  17215. "<p>" + (browser.ie ? "" : "<br/>") + "</p>"
  17216. );
  17217. };
  17218. orgFocus = me.focus;
  17219. orgBlur = me.blur;
  17220. me.focus = function () {
  17221. sourceEditor.focus();
  17222. };
  17223. me.blur = function () {
  17224. orgBlur.call(me);
  17225. sourceEditor.blur();
  17226. };
  17227. } else {
  17228. me.iframe.style.cssText = bakCssText;
  17229. var cont =
  17230. sourceEditor.getContent() ||
  17231. "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  17232. //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
  17233. cont = cont.replace(
  17234. new RegExp("[\\r\\t\\n ]*</?(\\w+)\\s*(?:[^>]*)>", "g"),
  17235. function (a, b) {
  17236. if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
  17237. return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, "");
  17238. }
  17239. return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, "");
  17240. }
  17241. );
  17242. me.setContent = orgSetContent;
  17243. me.setContent(cont);
  17244. sourceEditor.dispose();
  17245. sourceEditor = null;
  17246. //还原getContent方法
  17247. me.getContent = oldGetContent;
  17248. me.focus = orgFocus;
  17249. me.blur = orgBlur;
  17250. var first = me.body.firstChild;
  17251. //trace:1106 都删除空了,下边会报错,所以补充一个p占位
  17252. if (!first) {
  17253. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  17254. first = me.body.firstChild;
  17255. }
  17256. //要在ifm为显示时ff才能取到selection,否则报错
  17257. //这里不能比较位置了
  17258. me.undoManger && me.undoManger.save(true);
  17259. if (browser.gecko) {
  17260. var input = document.createElement("input");
  17261. input.style.cssText = "position:absolute;left:0;top:-32768px";
  17262. document.body.appendChild(input);
  17263. me.body.contentEditable = false;
  17264. setTimeout(function () {
  17265. domUtils.setViewportOffset(input, {left: -32768, top: 0});
  17266. input.focus();
  17267. setTimeout(function () {
  17268. me.body.contentEditable = true;
  17269. me.selection.getRange().moveToAddress(bakAddress).select(true);
  17270. domUtils.remove(input);
  17271. });
  17272. });
  17273. } else {
  17274. //ie下有可能报错,比如在代码顶头的情况
  17275. try {
  17276. me.selection.getRange().moveToAddress(bakAddress).select(true);
  17277. } catch (e) {
  17278. }
  17279. }
  17280. }
  17281. this.fireEvent("sourcemodechanged", sourceMode);
  17282. },
  17283. queryCommandState: function () {
  17284. return sourceMode | 0;
  17285. },
  17286. notNeedUndo: 1
  17287. };
  17288. var oldQueryCommandState = me.queryCommandState;
  17289. me.queryCommandState = function (cmdName) {
  17290. cmdName = cmdName.toLowerCase();
  17291. if (sourceMode) {
  17292. //源码模式下可以开启的命令
  17293. return cmdName in
  17294. {
  17295. source: 1,
  17296. fullscreen: 1
  17297. }
  17298. ? 1
  17299. : -1;
  17300. }
  17301. return oldQueryCommandState.apply(this, arguments);
  17302. };
  17303. if (opt.sourceEditor == "codemirror") {
  17304. me.addListener("ready", function () {
  17305. utils.loadFile(
  17306. document,
  17307. {
  17308. src:
  17309. opt.codeMirrorJsUrl ||
  17310. opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js",
  17311. tag: "script",
  17312. type: "text/javascript",
  17313. defer: "defer"
  17314. },
  17315. function () {
  17316. if (opt.sourceEditorFirst) {
  17317. setTimeout(function () {
  17318. me.execCommand("source");
  17319. }, 0);
  17320. }
  17321. }
  17322. );
  17323. utils.loadFile(document, {
  17324. tag: "link",
  17325. rel: "stylesheet",
  17326. type: "text/css",
  17327. href:
  17328. opt.codeMirrorCssUrl ||
  17329. opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css"
  17330. });
  17331. });
  17332. }
  17333. };
  17334. })();
  17335. // plugins/enterkey.js
  17336. ///import core
  17337. ///import plugins/undo.js
  17338. ///commands 设置回车标签p或br
  17339. ///commandsName EnterKey
  17340. ///commandsTitle 设置回车标签p或br
  17341. /**
  17342. * @description 处理回车
  17343. * @author zhanyi
  17344. */
  17345. UE.plugins["enterkey"] = function () {
  17346. var hTag,
  17347. me = this,
  17348. tag = me.options.enterTag;
  17349. me.addListener("keyup", function (type, evt) {
  17350. var keyCode = evt.keyCode || evt.which;
  17351. if (keyCode == 13) {
  17352. var range = me.selection.getRange(),
  17353. start = range.startContainer,
  17354. doSave;
  17355. //修正在h1-h6里边回车后不能嵌套p的问题
  17356. if (!browser.ie) {
  17357. if (/h\d/i.test(hTag)) {
  17358. if (browser.gecko) {
  17359. var h = domUtils.findParentByTagName(
  17360. start,
  17361. [
  17362. "h1",
  17363. "h2",
  17364. "h3",
  17365. "h4",
  17366. "h5",
  17367. "h6",
  17368. "blockquote",
  17369. "caption",
  17370. "table"
  17371. ],
  17372. true
  17373. );
  17374. if (!h) {
  17375. me.document.execCommand("formatBlock", false, "<p>");
  17376. doSave = 1;
  17377. }
  17378. } else {
  17379. //chrome remove div
  17380. if (start.nodeType == 1) {
  17381. var tmp = me.document.createTextNode(""),
  17382. div;
  17383. range.insertNode(tmp);
  17384. div = domUtils.findParentByTagName(tmp, "div", true);
  17385. if (div) {
  17386. var p = me.document.createElement("p");
  17387. while (div.firstChild) {
  17388. p.appendChild(div.firstChild);
  17389. }
  17390. div.parentNode.insertBefore(p, div);
  17391. domUtils.remove(div);
  17392. range.setStartBefore(tmp).setCursor();
  17393. doSave = 1;
  17394. }
  17395. domUtils.remove(tmp);
  17396. }
  17397. }
  17398. if (me.undoManger && doSave) {
  17399. me.undoManger.save();
  17400. }
  17401. }
  17402. //没有站位符,会出现多行的问题
  17403. browser.opera && range.select();
  17404. } else {
  17405. me.fireEvent("saveScene", true, true);
  17406. }
  17407. }
  17408. });
  17409. me.addListener("keydown", function (type, evt) {
  17410. var keyCode = evt.keyCode || evt.which;
  17411. if (keyCode == 13) {
  17412. //回车
  17413. if (me.fireEvent("beforeenterkeydown")) {
  17414. domUtils.preventDefault(evt);
  17415. return;
  17416. }
  17417. me.fireEvent("saveScene", true, true);
  17418. hTag = "";
  17419. var range = me.selection.getRange();
  17420. if (!range.collapsed) {
  17421. //跨td不能删
  17422. var start = range.startContainer,
  17423. end = range.endContainer,
  17424. startTd = domUtils.findParentByTagName(start, "td", true),
  17425. endTd = domUtils.findParentByTagName(end, "td", true);
  17426. if (
  17427. (startTd && endTd && startTd !== endTd) ||
  17428. (!startTd && endTd) ||
  17429. (startTd && !endTd)
  17430. ) {
  17431. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  17432. return;
  17433. }
  17434. }
  17435. if (tag == "p") {
  17436. if (!browser.ie) {
  17437. start = domUtils.findParentByTagName(
  17438. range.startContainer,
  17439. [
  17440. "ol",
  17441. "ul",
  17442. "p",
  17443. "h1",
  17444. "h2",
  17445. "h3",
  17446. "h4",
  17447. "h5",
  17448. "h6",
  17449. "blockquote",
  17450. "caption"
  17451. ],
  17452. true
  17453. );
  17454. //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
  17455. //trace:2431
  17456. if (!start && !browser.opera) {
  17457. me.document.execCommand("formatBlock", false, "<p>");
  17458. if (browser.gecko) {
  17459. range = me.selection.getRange();
  17460. start = domUtils.findParentByTagName(
  17461. range.startContainer,
  17462. "p",
  17463. true
  17464. );
  17465. start && domUtils.removeDirtyAttr(start);
  17466. }
  17467. } else {
  17468. hTag = start.tagName;
  17469. start.tagName.toLowerCase() == "p" &&
  17470. browser.gecko &&
  17471. domUtils.removeDirtyAttr(start);
  17472. }
  17473. }
  17474. } else {
  17475. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  17476. if (!range.collapsed) {
  17477. range.deleteContents();
  17478. start = range.startContainer;
  17479. if (
  17480. start.nodeType == 1 &&
  17481. (start = start.childNodes[range.startOffset])
  17482. ) {
  17483. while (start.nodeType == 1) {
  17484. if (dtd.$empty[start.tagName]) {
  17485. range.setStartBefore(start).setCursor();
  17486. if (me.undoManger) {
  17487. me.undoManger.save();
  17488. }
  17489. return false;
  17490. }
  17491. if (!start.firstChild) {
  17492. var br = range.document.createElement("br");
  17493. start.appendChild(br);
  17494. range.setStart(start, 0).setCursor();
  17495. if (me.undoManger) {
  17496. me.undoManger.save();
  17497. }
  17498. return false;
  17499. }
  17500. start = start.firstChild;
  17501. }
  17502. if (start === range.startContainer.childNodes[range.startOffset]) {
  17503. br = range.document.createElement("br");
  17504. range.insertNode(br).setCursor();
  17505. } else {
  17506. range.setStart(start, 0).setCursor();
  17507. }
  17508. } else {
  17509. br = range.document.createElement("br");
  17510. range.insertNode(br).setStartAfter(br).setCursor();
  17511. }
  17512. } else {
  17513. br = range.document.createElement("br");
  17514. range.insertNode(br);
  17515. var parent = br.parentNode;
  17516. if (parent.lastChild === br) {
  17517. br.parentNode.insertBefore(br.cloneNode(true), br);
  17518. range.setStartBefore(br);
  17519. } else {
  17520. range.setStartAfter(br);
  17521. }
  17522. range.setCursor();
  17523. }
  17524. }
  17525. }
  17526. });
  17527. };
  17528. // plugins/keystrokes.js
  17529. /* 处理特殊键的兼容性问题 */
  17530. UE.plugins["keystrokes"] = function () {
  17531. var me = this;
  17532. var collapsed = true;
  17533. me.addListener("keydown", function (type, evt) {
  17534. var keyCode = evt.keyCode || evt.which,
  17535. rng = me.selection.getRange();
  17536. //处理全选的情况
  17537. if (
  17538. !rng.collapsed &&
  17539. !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) &&
  17540. ((keyCode >= 65 && keyCode <= 90) ||
  17541. (keyCode >= 48 && keyCode <= 57) ||
  17542. (keyCode >= 96 && keyCode <= 111) ||
  17543. {
  17544. 13: 1,
  17545. 8: 1,
  17546. 46: 1
  17547. }[keyCode])
  17548. ) {
  17549. var tmpNode = rng.startContainer;
  17550. if (domUtils.isFillChar(tmpNode)) {
  17551. rng.setStartBefore(tmpNode);
  17552. }
  17553. tmpNode = rng.endContainer;
  17554. if (domUtils.isFillChar(tmpNode)) {
  17555. rng.setEndAfter(tmpNode);
  17556. }
  17557. rng.txtToElmBoundary();
  17558. //结束边界可能放到了br的前边,要把br包含进来
  17559. // x[xxx]<br/>
  17560. if (rng.endContainer && rng.endContainer.nodeType == 1) {
  17561. tmpNode = rng.endContainer.childNodes[rng.endOffset];
  17562. if (tmpNode && domUtils.isBr(tmpNode)) {
  17563. rng.setEndAfter(tmpNode);
  17564. }
  17565. }
  17566. if (rng.startOffset == 0) {
  17567. tmpNode = rng.startContainer;
  17568. if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
  17569. tmpNode = rng.endContainer;
  17570. if (
  17571. rng.endOffset ==
  17572. (tmpNode.nodeType == 3
  17573. ? tmpNode.nodeValue.length
  17574. : tmpNode.childNodes.length) &&
  17575. domUtils.isBoundaryNode(tmpNode, "lastChild")
  17576. ) {
  17577. me.fireEvent("saveScene");
  17578. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  17579. rng.setStart(me.body.firstChild, 0).setCursor(false, true);
  17580. me._selectionChange();
  17581. return;
  17582. }
  17583. }
  17584. }
  17585. }
  17586. //处理backspace
  17587. if (keyCode == keymap.Backspace) {
  17588. rng = me.selection.getRange();
  17589. collapsed = rng.collapsed;
  17590. if (me.fireEvent("delkeydown", evt)) {
  17591. return;
  17592. }
  17593. var start, end;
  17594. //避免按两次删除才能生效的问题
  17595. if (rng.collapsed && rng.inFillChar()) {
  17596. start = rng.startContainer;
  17597. if (domUtils.isFillChar(start)) {
  17598. rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
  17599. domUtils.remove(start);
  17600. } else {
  17601. start.nodeValue = start.nodeValue.replace(
  17602. new RegExp("^" + domUtils.fillChar),
  17603. ""
  17604. );
  17605. rng.startOffset--;
  17606. rng.collapse(true).select(true);
  17607. }
  17608. }
  17609. //解决选中control元素不能删除的问题
  17610. if ((start = rng.getClosedNode())) {
  17611. me.fireEvent("saveScene");
  17612. rng.setStartBefore(start);
  17613. domUtils.remove(start);
  17614. rng.setCursor();
  17615. me.fireEvent("saveScene");
  17616. domUtils.preventDefault(evt);
  17617. return;
  17618. }
  17619. //阻止在table上的删除
  17620. if (!browser.ie) {
  17621. start = domUtils.findParentByTagName(rng.startContainer, "table", true);
  17622. end = domUtils.findParentByTagName(rng.endContainer, "table", true);
  17623. if ((start && !end) || (!start && end) || start !== end) {
  17624. evt.preventDefault();
  17625. return;
  17626. }
  17627. }
  17628. }
  17629. //处理tab键的逻辑
  17630. if (keyCode == keymap.Tab) {
  17631. //不处理以下标签
  17632. var excludeTagNameForTabKey = {
  17633. ol: 1,
  17634. ul: 1,
  17635. table: 1
  17636. };
  17637. //处理组件里的tab按下事件
  17638. if (me.fireEvent("tabkeydown", evt)) {
  17639. domUtils.preventDefault(evt);
  17640. return;
  17641. }
  17642. var range = me.selection.getRange();
  17643. me.fireEvent("saveScene");
  17644. for (
  17645. var i = 0,
  17646. txt = "",
  17647. tabSize = me.options.tabSize || 4,
  17648. tabNode = me.options.tabNode || "&nbsp;";
  17649. i < tabSize;
  17650. i++
  17651. ) {
  17652. txt += tabNode;
  17653. }
  17654. var span = me.document.createElement("span");
  17655. span.innerHTML = txt + domUtils.fillChar;
  17656. if (range.collapsed) {
  17657. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  17658. } else {
  17659. var filterFn = function (node) {
  17660. return (
  17661. domUtils.isBlockElm(node) &&
  17662. !excludeTagNameForTabKey[node.tagName.toLowerCase()]
  17663. );
  17664. };
  17665. //普通的情况
  17666. start = domUtils.findParent(range.startContainer, filterFn, true);
  17667. end = domUtils.findParent(range.endContainer, filterFn, true);
  17668. if (start && end && start === end) {
  17669. range.deleteContents();
  17670. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  17671. } else {
  17672. var bookmark = range.createBookmark();
  17673. range.enlarge(true);
  17674. var bookmark2 = range.createBookmark(),
  17675. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
  17676. while (
  17677. current &&
  17678. !(
  17679. domUtils.getPosition(current, bookmark2.end) &
  17680. domUtils.POSITION_FOLLOWING
  17681. )
  17682. ) {
  17683. current.insertBefore(
  17684. span.cloneNode(true).firstChild,
  17685. current.firstChild
  17686. );
  17687. current = domUtils.getNextDomNode(current, false, filterFn);
  17688. }
  17689. range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
  17690. }
  17691. }
  17692. domUtils.preventDefault(evt);
  17693. }
  17694. //trace:1634
  17695. //ff的del键在容器空的时候,也会删除
  17696. if (browser.gecko && keyCode == 46) {
  17697. range = me.selection.getRange();
  17698. if (range.collapsed) {
  17699. start = range.startContainer;
  17700. if (domUtils.isEmptyBlock(start)) {
  17701. var parent = start.parentNode;
  17702. while (
  17703. domUtils.getChildCount(parent) == 1 &&
  17704. !domUtils.isBody(parent)
  17705. ) {
  17706. start = parent;
  17707. parent = parent.parentNode;
  17708. }
  17709. if (start === parent.lastChild) evt.preventDefault();
  17710. return;
  17711. }
  17712. }
  17713. }
  17714. /* 修复在编辑区域快捷键 (Mac:meta+alt+I; Win:ctrl+shift+I) 打不开 chrome 控制台的问题 */
  17715. browser.chrome &&
  17716. me.on("keydown", function (type, e) {
  17717. var keyCode = e.keyCode || e.which;
  17718. if (
  17719. ((e.metaKey && e.altKey) || (e.ctrlKey && e.shiftKey)) &&
  17720. keyCode == 73
  17721. ) {
  17722. return true;
  17723. }
  17724. });
  17725. });
  17726. me.addListener("keyup", function (type, evt) {
  17727. var keyCode = evt.keyCode || evt.which,
  17728. rng,
  17729. me = this;
  17730. if (keyCode == keymap.Backspace) {
  17731. if (me.fireEvent("delkeyup")) {
  17732. return;
  17733. }
  17734. rng = me.selection.getRange();
  17735. if (rng.collapsed) {
  17736. var tmpNode,
  17737. autoClearTagName = ["h1", "h2", "h3", "h4", "h5", "h6"];
  17738. if (
  17739. (tmpNode = domUtils.findParentByTagName(
  17740. rng.startContainer,
  17741. autoClearTagName,
  17742. true
  17743. ))
  17744. ) {
  17745. if (domUtils.isEmptyBlock(tmpNode)) {
  17746. var pre = tmpNode.previousSibling;
  17747. if (pre && pre.nodeName != "TABLE") {
  17748. domUtils.remove(tmpNode);
  17749. rng.setStartAtLast(pre).setCursor(false, true);
  17750. return;
  17751. } else {
  17752. var next = tmpNode.nextSibling;
  17753. if (next && next.nodeName != "TABLE") {
  17754. domUtils.remove(tmpNode);
  17755. rng.setStartAtFirst(next).setCursor(false, true);
  17756. return;
  17757. }
  17758. }
  17759. }
  17760. }
  17761. //处理当删除到body时,要重新给p标签展位
  17762. if (domUtils.isBody(rng.startContainer)) {
  17763. var tmpNode = domUtils.createElement(me.document, "p", {
  17764. innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
  17765. });
  17766. rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true);
  17767. }
  17768. }
  17769. //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
  17770. if (
  17771. !collapsed &&
  17772. (rng.startContainer.nodeType == 3 ||
  17773. (rng.startContainer.nodeType == 1 &&
  17774. domUtils.isEmptyBlock(rng.startContainer)))
  17775. ) {
  17776. if (browser.ie) {
  17777. var span = rng.document.createElement("span");
  17778. rng.insertNode(span).setStartBefore(span).collapse(true);
  17779. rng.select();
  17780. domUtils.remove(span);
  17781. } else {
  17782. rng.select();
  17783. }
  17784. }
  17785. }
  17786. });
  17787. };
  17788. // plugins/fiximgclick.js
  17789. ///import core
  17790. ///commands 修复chrome下图片不能点击的问题,出现八个角可改变大小
  17791. ///commandsName FixImgClick
  17792. ///commandsTitle 修复chrome下图片不能点击的问题,出现八个角可改变大小
  17793. //修复chrome下图片不能点击的问题,出现八个角可改变大小
  17794. UE.plugins["fiximgclick"] = (function () {
  17795. var elementUpdated = false;
  17796. function Scale() {
  17797. this.editor = null;
  17798. this.resizer = null;
  17799. this.cover = null;
  17800. this.doc = document;
  17801. this.prePos = {x: 0, y: 0};
  17802. this.startPos = {x: 0, y: 0};
  17803. }
  17804. (function () {
  17805. var rect = [
  17806. //[left, top, width, height]
  17807. [0, 0, -1, -1],
  17808. [0, 0, 0, -1],
  17809. [0, 0, 1, -1],
  17810. [0, 0, -1, 0],
  17811. [0, 0, 1, 0],
  17812. [0, 0, -1, 1],
  17813. [0, 0, 0, 1],
  17814. [0, 0, 1, 1]
  17815. ];
  17816. Scale.prototype = {
  17817. init: function (editor) {
  17818. var me = this;
  17819. me.editor = editor;
  17820. me.startPos = this.prePos = {x: 0, y: 0};
  17821. me.dragId = -1;
  17822. var hands = [],
  17823. cover = (me.cover = document.createElement("div")),
  17824. resizer = (me.resizer = document.createElement("div"));
  17825. cover.id = me.editor.ui.id + "_imagescale_cover";
  17826. cover.style.cssText =
  17827. "position:absolute;display:none;z-index:" +
  17828. me.editor.options.zIndex +
  17829. ";filter:alpha(opacity=0); opacity:0;background:#CCC;";
  17830. domUtils.on(cover, "mousedown click", function () {
  17831. me.hide();
  17832. });
  17833. for (i = 0; i < 8; i++) {
  17834. hands.push(
  17835. '<span class="edui-editor-imagescale-hand' + i + '"></span>'
  17836. );
  17837. }
  17838. resizer.id = me.editor.ui.id + "_imagescale";
  17839. resizer.className = "edui-editor-imagescale";
  17840. resizer.innerHTML = hands.join("");
  17841. resizer.style.cssText +=
  17842. ";display:none;border:1px solid #3b77ff;z-index:" +
  17843. me.editor.options.zIndex +
  17844. ";";
  17845. me.editor.ui.getDom().appendChild(cover);
  17846. me.editor.ui.getDom().appendChild(resizer);
  17847. me.initStyle();
  17848. me.initEvents();
  17849. },
  17850. initStyle: function () {
  17851. utils.cssRule(
  17852. "imagescale",
  17853. ".edui-editor-imagescale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}" +
  17854. ".edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}" +
  17855. ".edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}" +
  17856. ".edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}" +
  17857. ".edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}" +
  17858. ".edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}" +
  17859. ".edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}" +
  17860. ".edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}" +
  17861. ".edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}" +
  17862. ".edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}"
  17863. );
  17864. },
  17865. initEvents: function () {
  17866. var me = this;
  17867. me.startPos.x = me.startPos.y = 0;
  17868. me.isDraging = false;
  17869. },
  17870. _eventHandler: function (e) {
  17871. var me = this;
  17872. switch (e.type) {
  17873. case "mousedown":
  17874. var hand = e.target || e.srcElement,
  17875. hand;
  17876. if (
  17877. hand.className.indexOf("edui-editor-imagescale-hand") != -1 &&
  17878. me.dragId == -1
  17879. ) {
  17880. me.dragId = hand.className.slice(-1);
  17881. me.startPos.x = me.prePos.x = e.clientX;
  17882. me.startPos.y = me.prePos.y = e.clientY;
  17883. domUtils.on(me.doc, "mousemove", me.proxy(me._eventHandler, me));
  17884. }
  17885. break;
  17886. case "mousemove":
  17887. if (me.dragId != -1) {
  17888. me.updateContainerStyle(me.dragId, {
  17889. x: e.clientX - me.prePos.x,
  17890. y: e.clientY - me.prePos.y
  17891. });
  17892. me.prePos.x = e.clientX;
  17893. me.prePos.y = e.clientY;
  17894. elementUpdated = true;
  17895. me.updateTargetElement();
  17896. }
  17897. break;
  17898. case "mouseup":
  17899. if (me.dragId != -1) {
  17900. me.updateContainerStyle(me.dragId, {
  17901. x: e.clientX - me.prePos.x,
  17902. y: e.clientY - me.prePos.y
  17903. });
  17904. me.updateTargetElement();
  17905. if (me.target.parentNode) me.attachTo(me.target);
  17906. me.dragId = -1;
  17907. }
  17908. domUtils.un(me.doc, "mousemove", me.proxy(me._eventHandler, me));
  17909. //修复只是点击挪动点,但没有改变大小,不应该触发contentchange
  17910. if (elementUpdated) {
  17911. elementUpdated = false;
  17912. me.editor.fireEvent("contentchange");
  17913. }
  17914. break;
  17915. default:
  17916. break;
  17917. }
  17918. },
  17919. updateTargetElement: function () {
  17920. var me = this;
  17921. domUtils.setStyles(me.target, {
  17922. width: me.resizer.style.width,
  17923. height: me.resizer.style.height
  17924. });
  17925. me.target.width = parseInt(me.resizer.style.width);
  17926. me.target.height = parseInt(me.resizer.style.height);
  17927. me.attachTo(me.target);
  17928. },
  17929. updateContainerStyle: function (dir, offset) {
  17930. var me = this,
  17931. dom = me.resizer,
  17932. tmp;
  17933. if (rect[dir][0] != 0) {
  17934. tmp = parseInt(dom.style.left) + offset.x;
  17935. dom.style.left = me._validScaledProp("left", tmp) + "px";
  17936. }
  17937. if (rect[dir][1] != 0) {
  17938. tmp = parseInt(dom.style.top) + offset.y;
  17939. dom.style.top = me._validScaledProp("top", tmp) + "px";
  17940. }
  17941. if (rect[dir][2] != 0) {
  17942. tmp = dom.clientWidth + rect[dir][2] * offset.x;
  17943. dom.style.width = me._validScaledProp("width", tmp) + "px";
  17944. }
  17945. if (rect[dir][3] != 0) {
  17946. tmp = dom.clientHeight + rect[dir][3] * offset.y;
  17947. dom.style.height = me._validScaledProp("height", tmp) + "px";
  17948. }
  17949. },
  17950. _validScaledProp: function (prop, value) {
  17951. var ele = this.resizer,
  17952. wrap = document;
  17953. value = isNaN(value) ? 0 : value;
  17954. switch (prop) {
  17955. case "left":
  17956. return value < 0
  17957. ? 0
  17958. : value + ele.clientWidth > wrap.clientWidth
  17959. ? wrap.clientWidth - ele.clientWidth
  17960. : value;
  17961. case "top":
  17962. return value < 0
  17963. ? 0
  17964. : value + ele.clientHeight > wrap.clientHeight
  17965. ? wrap.clientHeight - ele.clientHeight
  17966. : value;
  17967. case "width":
  17968. return value <= 0
  17969. ? 1
  17970. : value + ele.offsetLeft > wrap.clientWidth
  17971. ? wrap.clientWidth - ele.offsetLeft
  17972. : value;
  17973. case "height":
  17974. return value <= 0
  17975. ? 1
  17976. : value + ele.offsetTop > wrap.clientHeight
  17977. ? wrap.clientHeight - ele.offsetTop
  17978. : value;
  17979. }
  17980. },
  17981. hideCover: function () {
  17982. this.cover.style.display = "none";
  17983. },
  17984. showCover: function () {
  17985. var me = this,
  17986. editorPos = domUtils.getXY(me.editor.ui.getDom()),
  17987. iframePos = domUtils.getXY(me.editor.iframe);
  17988. domUtils.setStyles(me.cover, {
  17989. width: me.editor.iframe.offsetWidth + "px",
  17990. height: me.editor.iframe.offsetHeight + "px",
  17991. top: iframePos.y - editorPos.y + "px",
  17992. left: iframePos.x - editorPos.x + "px",
  17993. position: "absolute",
  17994. display: ""
  17995. });
  17996. },
  17997. show: function (targetObj) {
  17998. var me = this;
  17999. me.resizer.style.display = "block";
  18000. if (targetObj) me.attachTo(targetObj);
  18001. domUtils.on(this.resizer, "mousedown", me.proxy(me._eventHandler, me));
  18002. domUtils.on(me.doc, "mouseup", me.proxy(me._eventHandler, me));
  18003. me.showCover();
  18004. me.editor.fireEvent("afterscaleshow", me);
  18005. me.editor.fireEvent("saveScene");
  18006. },
  18007. hide: function () {
  18008. var me = this;
  18009. me.hideCover();
  18010. me.resizer.style.display = "none";
  18011. domUtils.un(me.resizer, "mousedown", me.proxy(me._eventHandler, me));
  18012. domUtils.un(me.doc, "mouseup", me.proxy(me._eventHandler, me));
  18013. me.editor.fireEvent("afterscalehide", me);
  18014. },
  18015. proxy: function (fn, context) {
  18016. return function (e) {
  18017. return fn.apply(context || this, arguments);
  18018. };
  18019. },
  18020. attachTo: function (targetObj) {
  18021. var me = this,
  18022. target = (me.target = targetObj),
  18023. resizer = this.resizer,
  18024. imgPos = domUtils.getXY(target),
  18025. iframePos = domUtils.getXY(me.editor.iframe),
  18026. editorPos = domUtils.getXY(resizer.parentNode);
  18027. var doc = me.editor.document;
  18028. domUtils.setStyles(resizer, {
  18029. width: target.width + "px",
  18030. height: target.height + "px",
  18031. left:
  18032. iframePos.x +
  18033. imgPos.x -
  18034. (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0) -
  18035. editorPos.x -
  18036. parseInt(resizer.style.borderLeftWidth) +
  18037. "px",
  18038. top:
  18039. iframePos.y +
  18040. imgPos.y -
  18041. (doc.documentElement.scrollTop || doc.body.scrollTop || 0) -
  18042. editorPos.y -
  18043. parseInt(resizer.style.borderTopWidth) +
  18044. "px"
  18045. });
  18046. }
  18047. };
  18048. })();
  18049. return function () {
  18050. var me = this,
  18051. imageScale;
  18052. me.setOpt("imageScaleEnabled", true);
  18053. if (!browser.ie && me.options.imageScaleEnabled) {
  18054. me.addListener("click", function (type, e) {
  18055. var range = me.selection.getRange(),
  18056. img = range.getClosedNode();
  18057. if (img && img.tagName == "IMG" && me.body.contentEditable != "false") {
  18058. if (
  18059. img.className.indexOf("edui-faked-music") != -1 ||
  18060. img.getAttribute("anchorname") ||
  18061. domUtils.hasClass(img, "loadingclass") ||
  18062. domUtils.hasClass(img, "loaderrorclass")
  18063. ) {
  18064. return;
  18065. }
  18066. if (!imageScale) {
  18067. imageScale = new Scale();
  18068. imageScale.init(me);
  18069. me.ui.getDom().appendChild(imageScale.resizer);
  18070. var _keyDownHandler = function (e) {
  18071. imageScale.hide();
  18072. if (imageScale.target)
  18073. me.selection.getRange().selectNode(imageScale.target).select();
  18074. },
  18075. _mouseDownHandler = function (e) {
  18076. var ele = e.target || e.srcElement;
  18077. if (
  18078. ele &&
  18079. (ele.className === undefined ||
  18080. ele.className.indexOf("edui-editor-imagescale") == -1)
  18081. ) {
  18082. _keyDownHandler(e);
  18083. }
  18084. },
  18085. timer;
  18086. me.addListener("afterscaleshow", function (e) {
  18087. me.addListener("beforekeydown", _keyDownHandler);
  18088. me.addListener("beforemousedown", _mouseDownHandler);
  18089. domUtils.on(document, "keydown", _keyDownHandler);
  18090. domUtils.on(document, "mousedown", _mouseDownHandler);
  18091. me.selection.getNative().removeAllRanges();
  18092. });
  18093. me.addListener("afterscalehide", function (e) {
  18094. me.removeListener("beforekeydown", _keyDownHandler);
  18095. me.removeListener("beforemousedown", _mouseDownHandler);
  18096. domUtils.un(document, "keydown", _keyDownHandler);
  18097. domUtils.un(document, "mousedown", _mouseDownHandler);
  18098. var target = imageScale.target;
  18099. if (target.parentNode) {
  18100. me.selection.getRange().selectNode(target).select();
  18101. }
  18102. });
  18103. //TODO 有iframe的情况,mousedown不能往下传。。
  18104. domUtils.on(imageScale.resizer, "mousedown", function (e) {
  18105. me.selection.getNative().removeAllRanges();
  18106. var ele = e.target || e.srcElement;
  18107. if (
  18108. ele &&
  18109. ele.className.indexOf("edui-editor-imagescale-hand") == -1
  18110. ) {
  18111. timer = setTimeout(function () {
  18112. imageScale.hide();
  18113. if (imageScale.target)
  18114. me.selection.getRange().selectNode(ele).select();
  18115. }, 200);
  18116. }
  18117. });
  18118. domUtils.on(imageScale.resizer, "mouseup", function (e) {
  18119. var ele = e.target || e.srcElement;
  18120. if (
  18121. ele &&
  18122. ele.className.indexOf("edui-editor-imagescale-hand") == -1
  18123. ) {
  18124. clearTimeout(timer);
  18125. }
  18126. });
  18127. }
  18128. imageScale.show(img);
  18129. } else {
  18130. if (imageScale && imageScale.resizer.style.display != "none")
  18131. imageScale.hide();
  18132. }
  18133. });
  18134. }
  18135. if (browser.webkit) {
  18136. me.addListener("click", function (type, e) {
  18137. if (e.target.tagName == "IMG" && me.body.contentEditable != "false") {
  18138. var range = new dom.Range(me.document);
  18139. range.selectNode(e.target).select();
  18140. }
  18141. });
  18142. }
  18143. };
  18144. })();
  18145. // plugins/autolink.js
  18146. ///import core
  18147. ///commands 为非ie浏览器自动添加a标签
  18148. ///commandsName AutoLink
  18149. ///commandsTitle 自动增加链接
  18150. /**
  18151. * @description 为非ie浏览器自动添加a标签
  18152. * @author zhanyi
  18153. */
  18154. UE.plugin.register(
  18155. "autolink",
  18156. function () {
  18157. var cont = 0;
  18158. return !browser.ie
  18159. ? {
  18160. bindEvents: {
  18161. reset: function () {
  18162. cont = 0;
  18163. },
  18164. keydown: function (type, evt) {
  18165. var me = this;
  18166. var keyCode = evt.keyCode || evt.which;
  18167. if (keyCode == 32 || keyCode == 13) {
  18168. var sel = me.selection.getNative(),
  18169. range = sel.getRangeAt(0).cloneRange(),
  18170. offset,
  18171. charCode;
  18172. var start = range.startContainer;
  18173. while (start.nodeType == 1 && range.startOffset > 0) {
  18174. start =
  18175. range.startContainer.childNodes[range.startOffset - 1];
  18176. if (!start) {
  18177. break;
  18178. }
  18179. range.setStart(
  18180. start,
  18181. start.nodeType == 1
  18182. ? start.childNodes.length
  18183. : start.nodeValue.length
  18184. );
  18185. range.collapse(true);
  18186. start = range.startContainer;
  18187. }
  18188. do {
  18189. if (range.startOffset == 0) {
  18190. start = range.startContainer.previousSibling;
  18191. while (start && start.nodeType == 1) {
  18192. start = start.lastChild;
  18193. }
  18194. if (!start || domUtils.isFillChar(start)) {
  18195. break;
  18196. }
  18197. offset = start.nodeValue.length;
  18198. } else {
  18199. start = range.startContainer;
  18200. offset = range.startOffset;
  18201. }
  18202. range.setStart(start, offset - 1);
  18203. charCode = range.toString().charCodeAt(0);
  18204. } while (charCode != 160 && charCode != 32);
  18205. if (
  18206. range
  18207. .toString()
  18208. .replace(new RegExp(domUtils.fillChar, "g"), "")
  18209. .match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)
  18210. ) {
  18211. while (range.toString().length) {
  18212. if (
  18213. /^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(
  18214. range.toString()
  18215. )
  18216. ) {
  18217. break;
  18218. }
  18219. try {
  18220. range.setStart(
  18221. range.startContainer,
  18222. range.startOffset + 1
  18223. );
  18224. } catch (e) {
  18225. //trace:2121
  18226. var start = range.startContainer;
  18227. while (!(next = start.nextSibling)) {
  18228. if (domUtils.isBody(start)) {
  18229. return;
  18230. }
  18231. start = start.parentNode;
  18232. }
  18233. range.setStart(next, 0);
  18234. }
  18235. }
  18236. //range的开始边界已经在a标签里的不再处理
  18237. if (
  18238. domUtils.findParentByTagName(
  18239. range.startContainer,
  18240. "a",
  18241. true
  18242. )
  18243. ) {
  18244. return;
  18245. }
  18246. var a = me.document.createElement("a"),
  18247. text = me.document.createTextNode(" "),
  18248. href;
  18249. me.undoManger && me.undoManger.save();
  18250. a.appendChild(range.extractContents());
  18251. a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, "");
  18252. href = a
  18253. .getAttribute("href")
  18254. .replace(new RegExp(domUtils.fillChar, "g"), "");
  18255. href = /^(?:https?:\/\/)/gi.test(href)
  18256. ? href
  18257. : "http://" + href;
  18258. a.setAttribute("_src", utils.html(href));
  18259. a.href = utils.html(href);
  18260. range.insertNode(a);
  18261. a.parentNode.insertBefore(text, a.nextSibling);
  18262. range.setStart(text, 0);
  18263. range.collapse(true);
  18264. sel.removeAllRanges();
  18265. sel.addRange(range);
  18266. me.undoManger && me.undoManger.save();
  18267. }
  18268. }
  18269. }
  18270. }
  18271. }
  18272. : {};
  18273. },
  18274. function () {
  18275. var keyCodes = {
  18276. 37: 1,
  18277. 38: 1,
  18278. 39: 1,
  18279. 40: 1,
  18280. 13: 1,
  18281. 32: 1
  18282. };
  18283. function checkIsCludeLink(node) {
  18284. if (node.nodeType == 3) {
  18285. return null;
  18286. }
  18287. if (node.nodeName == "A") {
  18288. return node;
  18289. }
  18290. var lastChild = node.lastChild;
  18291. while (lastChild) {
  18292. if (lastChild.nodeName == "A") {
  18293. return lastChild;
  18294. }
  18295. if (lastChild.nodeType == 3) {
  18296. if (domUtils.isWhitespace(lastChild)) {
  18297. lastChild = lastChild.previousSibling;
  18298. continue;
  18299. }
  18300. return null;
  18301. }
  18302. lastChild = lastChild.lastChild;
  18303. }
  18304. }
  18305. browser.ie &&
  18306. this.addListener("keyup", function (cmd, evt) {
  18307. var me = this,
  18308. keyCode = evt.keyCode;
  18309. if (keyCodes[keyCode]) {
  18310. var rng = me.selection.getRange();
  18311. var start = rng.startContainer;
  18312. if (keyCode == 13) {
  18313. while (
  18314. start &&
  18315. !domUtils.isBody(start) &&
  18316. !domUtils.isBlockElm(start)
  18317. ) {
  18318. start = start.parentNode;
  18319. }
  18320. if (start && !domUtils.isBody(start) && start.nodeName == "P") {
  18321. var pre = start.previousSibling;
  18322. if (pre && pre.nodeType == 1) {
  18323. var pre = checkIsCludeLink(pre);
  18324. if (pre && !pre.getAttribute("_href")) {
  18325. domUtils.remove(pre, true);
  18326. }
  18327. }
  18328. }
  18329. } else if (keyCode == 32) {
  18330. if (start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
  18331. start = start.previousSibling;
  18332. if (
  18333. start &&
  18334. start.nodeName == "A" &&
  18335. !start.getAttribute("_href")
  18336. ) {
  18337. domUtils.remove(start, true);
  18338. }
  18339. }
  18340. } else {
  18341. start = domUtils.findParentByTagName(start, "a", true);
  18342. if (start && !start.getAttribute("_href")) {
  18343. var bk = rng.createBookmark();
  18344. domUtils.remove(start, true);
  18345. rng.moveToBookmark(bk).select(true);
  18346. }
  18347. }
  18348. }
  18349. });
  18350. }
  18351. );
  18352. // plugins/autoheight.js
  18353. ///import core
  18354. ///commands 当输入内容超过编辑器高度时,编辑器自动增高
  18355. ///commandsName AutoHeight,autoHeightEnabled
  18356. ///commandsTitle 自动增高
  18357. /**
  18358. * @description 自动伸展
  18359. * @author zhanyi
  18360. */
  18361. UE.plugins["autoheight"] = function () {
  18362. var me = this;
  18363. //提供开关,就算加载也可以关闭
  18364. me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
  18365. if (!me.autoHeightEnabled) {
  18366. return;
  18367. }
  18368. var bakOverflow,
  18369. lastHeight = 0,
  18370. options = me.options,
  18371. currentHeight,
  18372. timer;
  18373. function adjustHeight() {
  18374. var me = this;
  18375. clearTimeout(timer);
  18376. if (isFullscreen) return;
  18377. if (
  18378. !me.queryCommandState ||
  18379. (me.queryCommandState && me.queryCommandState("source") != 1)
  18380. ) {
  18381. timer = setTimeout(function () {
  18382. var node = me.body.lastChild;
  18383. while (node && node.nodeType != 1) {
  18384. node = node.previousSibling;
  18385. }
  18386. if (node && node.nodeType == 1) {
  18387. node.style.clear = "both";
  18388. currentHeight = Math.max(
  18389. domUtils.getXY(node).y + node.offsetHeight + 25,
  18390. Math.max(options.minFrameHeight, options.initialFrameHeight)
  18391. );
  18392. if (currentHeight != lastHeight) {
  18393. if (currentHeight !== parseInt(me.iframe.parentNode.style.height)) {
  18394. me.iframe.parentNode.style.height = currentHeight + "px";
  18395. }
  18396. me.body.style.height = currentHeight + "px";
  18397. lastHeight = currentHeight;
  18398. }
  18399. domUtils.removeStyle(node, "clear");
  18400. }
  18401. }, 50);
  18402. }
  18403. }
  18404. var isFullscreen;
  18405. me.addListener("fullscreenchanged", function (cmd, f) {
  18406. isFullscreen = f;
  18407. });
  18408. me.addListener("destroy", function () {
  18409. domUtils.un(me.window, "scroll", fixedScrollTop);
  18410. me.removeListener(
  18411. "contentchange afterinserthtml keyup mouseup",
  18412. adjustHeight
  18413. );
  18414. });
  18415. me.enableAutoHeight = function () {
  18416. var me = this;
  18417. if (!me.autoHeightEnabled) {
  18418. return;
  18419. }
  18420. var doc = me.document;
  18421. me.autoHeightEnabled = true;
  18422. bakOverflow = doc.body.style.overflowY;
  18423. doc.body.style.overflowY = "hidden";
  18424. me.addListener("contentchange afterinserthtml keyup mouseup", adjustHeight);
  18425. //ff不给事件算得不对
  18426. setTimeout(function () {
  18427. adjustHeight.call(me);
  18428. }, browser.gecko ? 100 : 0);
  18429. me.fireEvent("autoheightchanged", me.autoHeightEnabled);
  18430. };
  18431. me.disableAutoHeight = function () {
  18432. me.body.style.overflowY = bakOverflow || "";
  18433. me.removeListener("contentchange", adjustHeight);
  18434. me.removeListener("keyup", adjustHeight);
  18435. me.removeListener("mouseup", adjustHeight);
  18436. me.autoHeightEnabled = false;
  18437. me.fireEvent("autoheightchanged", me.autoHeightEnabled);
  18438. };
  18439. me.on("setHeight", function () {
  18440. me.disableAutoHeight();
  18441. });
  18442. me.addListener("ready", function () {
  18443. me.enableAutoHeight();
  18444. //trace:1764
  18445. var timer;
  18446. domUtils.on(
  18447. browser.ie ? me.body : me.document,
  18448. browser.webkit ? "dragover" : "drop",
  18449. function () {
  18450. clearTimeout(timer);
  18451. timer = setTimeout(function () {
  18452. //trace:3681
  18453. adjustHeight.call(me);
  18454. }, 100);
  18455. }
  18456. );
  18457. //修复内容过多时,回到顶部,顶部内容被工具栏遮挡问题
  18458. domUtils.on(me.window, "scroll", fixedScrollTop);
  18459. });
  18460. var lastScrollY;
  18461. function fixedScrollTop() {
  18462. if (!me.window) return;
  18463. if (lastScrollY === null) {
  18464. lastScrollY = me.window.scrollY;
  18465. } else if (me.window.scrollY == 0 && lastScrollY != 0) {
  18466. me.window.scrollTo(0, 0);
  18467. lastScrollY = null;
  18468. }
  18469. }
  18470. };
  18471. // plugins/autofloat.js
  18472. ///import core
  18473. ///commands 悬浮工具栏
  18474. ///commandsName AutoFloat,autoFloatEnabled
  18475. ///commandsTitle 悬浮工具栏
  18476. /**
  18477. * modified by chengchao01
  18478. * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
  18479. */
  18480. UE.plugins["autofloat"] = function () {
  18481. var me = this,
  18482. lang = me.getLang();
  18483. me.setOpt({
  18484. topOffset: 0
  18485. });
  18486. var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
  18487. topOffset = me.options.topOffset;
  18488. //如果不固定toolbar的位置,则直接退出
  18489. if (!optsAutoFloatEnabled) {
  18490. return;
  18491. }
  18492. var uiUtils = UE.ui.uiUtils,
  18493. LteIE6 = browser.ie && browser.version <= 6,
  18494. quirks = browser.quirks;
  18495. function checkHasUI() {
  18496. if (!UE.ui) {
  18497. alert(lang.autofloatMsg);
  18498. return 0;
  18499. }
  18500. return 1;
  18501. }
  18502. function fixIE6FixedPos() {
  18503. var docStyle = document.body.style;
  18504. docStyle.backgroundImage = 'url("about:blank")';
  18505. docStyle.backgroundAttachment = "fixed";
  18506. }
  18507. var bakCssText,
  18508. placeHolder = document.createElement("div"),
  18509. toolbarBox,
  18510. orgTop,
  18511. getPosition,
  18512. flag = true; //ie7模式下需要偏移
  18513. function setFloating() {
  18514. var toobarBoxPos = domUtils.getXY(toolbarBox),
  18515. origalFloat = domUtils.getComputedStyle(toolbarBox, "position"),
  18516. origalLeft = domUtils.getComputedStyle(toolbarBox, "left");
  18517. toolbarBox.style.width = toolbarBox.offsetWidth + "px";
  18518. toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
  18519. toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
  18520. if (LteIE6 || (quirks && browser.ie)) {
  18521. if (toolbarBox.style.position != "absolute") {
  18522. toolbarBox.style.position = "absolute";
  18523. }
  18524. toolbarBox.style.top =
  18525. (document.body.scrollTop || document.documentElement.scrollTop) -
  18526. orgTop +
  18527. topOffset +
  18528. "px";
  18529. } else {
  18530. if (browser.ie7Compat && flag) {
  18531. flag = false;
  18532. toolbarBox.style.left =
  18533. domUtils.getXY(toolbarBox).x -
  18534. document.documentElement.getBoundingClientRect().left +
  18535. 2 +
  18536. "px";
  18537. }
  18538. if (toolbarBox.style.position != "fixed") {
  18539. toolbarBox.style.position = "fixed";
  18540. toolbarBox.style.top = topOffset + "px";
  18541. (origalFloat == "absolute" || origalFloat == "relative") &&
  18542. parseFloat(origalLeft) &&
  18543. (toolbarBox.style.left = toobarBoxPos.x + "px");
  18544. }
  18545. }
  18546. }
  18547. function unsetFloating() {
  18548. flag = true;
  18549. if (placeHolder.parentNode) {
  18550. placeHolder.parentNode.removeChild(placeHolder);
  18551. }
  18552. toolbarBox.style.cssText = bakCssText;
  18553. }
  18554. function updateFloating() {
  18555. var rect3 = getPosition(me.container);
  18556. var offset = me.options.toolbarTopOffset || 0;
  18557. if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
  18558. setFloating();
  18559. } else {
  18560. unsetFloating();
  18561. }
  18562. }
  18563. var defer_updateFloating = utils.defer(
  18564. function () {
  18565. updateFloating();
  18566. },
  18567. browser.ie ? 200 : 100,
  18568. true
  18569. );
  18570. me.addListener("destroy", function () {
  18571. domUtils.un(window, ["scroll", "resize"], updateFloating);
  18572. me.removeListener("keydown", defer_updateFloating);
  18573. //适用于在DIV scrollbox中滚动,但页面不滚动的浮动toolbar
  18574. var scrollBox = document.getElementById("scrollBox");
  18575. if (scrollBox) {
  18576. domUtils.un(scrollBox, ['scroll', 'resize'], updateFloating);
  18577. }
  18578. });
  18579. me.addListener("ready", function () {
  18580. if (checkHasUI(me)) {
  18581. //加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断
  18582. if (!me.ui) {
  18583. return;
  18584. }
  18585. getPosition = uiUtils.getClientRect;
  18586. toolbarBox = me.ui.getDom("toolbarbox");
  18587. orgTop = getPosition(toolbarBox).top;
  18588. bakCssText = toolbarBox.style.cssText;
  18589. placeHolder.style.height = toolbarBox.offsetHeight + "px";
  18590. if (LteIE6) {
  18591. fixIE6FixedPos();
  18592. }
  18593. domUtils.on(window, ["scroll", "resize"], updateFloating);
  18594. me.addListener("keydown", defer_updateFloating);
  18595. //适用于在DIV scrollbox中滚动,但页面不滚动的浮动toolbar
  18596. var scrollBox = document.getElementById("scrollBox");
  18597. if (scrollBox) {
  18598. domUtils.on(scrollBox, ['scroll', 'resize'], updateFloating);
  18599. }
  18600. me.addListener("beforefullscreenchange", function (t, enabled) {
  18601. if (enabled) {
  18602. unsetFloating();
  18603. }
  18604. });
  18605. me.addListener("fullscreenchanged", function (t, enabled) {
  18606. if (!enabled) {
  18607. updateFloating();
  18608. }
  18609. });
  18610. me.addListener("sourcemodechanged", function (t, enabled) {
  18611. setTimeout(function () {
  18612. updateFloating();
  18613. }, 0);
  18614. });
  18615. me.addListener("clearDoc", function () {
  18616. setTimeout(function () {
  18617. updateFloating();
  18618. }, 0);
  18619. });
  18620. }
  18621. });
  18622. };
  18623. // plugins/video.js
  18624. /**
  18625. * video插件, 为UEditor提供视频插入支持
  18626. * @file
  18627. * @since 1.2.6.1
  18628. */
  18629. UE.plugins["video"] = function () {
  18630. var me = this;
  18631. /**
  18632. * 创建插入视频字符窜
  18633. * @param url 视频地址
  18634. * @param width 视频宽度
  18635. * @param height 视频高度
  18636. * @param align 视频对齐
  18637. * @param toEmbed 是否以flash代替显示
  18638. * @param addParagraph 是否需要添加P 标签
  18639. */
  18640. function creatInsertStr(url, width, height, id, align, classname, type) {
  18641. var str;
  18642. switch (type) {
  18643. case "image":
  18644. str =
  18645. "<img " +
  18646. (id ? 'id="' + id + '"' : "") +
  18647. ' width="' +
  18648. width +
  18649. '" height="' +
  18650. height +
  18651. '" _url="' +
  18652. url +
  18653. '" class="' +
  18654. classname.replace(/\bvideo-js\b/, "") +
  18655. '"' +
  18656. ' src="' +
  18657. me.options.UEDITOR_HOME_URL +
  18658. 'themes/notadd/images/spacer.gif" style="background:url(' +
  18659. me.options.UEDITOR_HOME_URL +
  18660. "themes/notadd/images/videologo.gif) no-repeat center center; border:1px solid gray;" +
  18661. (align ? "float:" + align + ";" : "") +
  18662. '" />';
  18663. break;
  18664. case "embed":
  18665. str =
  18666. '<embed type="application/x-shockwave-flash" class="' +
  18667. classname +
  18668. '" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  18669. ' src="' +
  18670. utils.html(url) +
  18671. '" width="' +
  18672. width +
  18673. '" height="' +
  18674. height +
  18675. '"' +
  18676. (align ? ' style="float:' + align + '"' : "") +
  18677. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  18678. break;
  18679. case "video":
  18680. var ext = url.substr(url.lastIndexOf(".") + 1);
  18681. if (ext == "ogv") ext = "ogg";
  18682. str =
  18683. "<video" +
  18684. (id ? ' id="' + id + '"' : "") +
  18685. ' class="' +
  18686. classname +
  18687. ' video-js" ' +
  18688. (align ? ' style="float:' + align + '"' : "") +
  18689. ' controls preload="none" width="' +
  18690. width +
  18691. '" height="' +
  18692. height +
  18693. '" src="' +
  18694. url +
  18695. '" data-setup="{}">' +
  18696. '<source src="' +
  18697. url +
  18698. '" type="video/' +
  18699. ext +
  18700. '" /></video>';
  18701. break;
  18702. }
  18703. return str;
  18704. }
  18705. function switchImgAndVideo(root, img2video) {
  18706. utils.each(
  18707. root.getNodesByTagName(img2video ? "img" : "embed video"),
  18708. function (node) {
  18709. var className = node.getAttr("class");
  18710. if (className && className.indexOf("edui-faked-video") != -1) {
  18711. var html = creatInsertStr(
  18712. img2video ? node.getAttr("_url") : node.getAttr("src"),
  18713. node.getAttr("width"),
  18714. node.getAttr("height"),
  18715. null,
  18716. node.getStyle("float") || "",
  18717. className,
  18718. img2video ? "embed" : "image"
  18719. );
  18720. node.parentNode.replaceChild(UE.uNode.createElement(html), node);
  18721. }
  18722. if (className && className.indexOf("edui-upload-video") != -1) {
  18723. var html = creatInsertStr(
  18724. img2video ? node.getAttr("_url") : node.getAttr("src"),
  18725. node.getAttr("width"),
  18726. node.getAttr("height"),
  18727. null,
  18728. node.getStyle("float") || "",
  18729. className,
  18730. img2video ? "video" : "image"
  18731. );
  18732. node.parentNode.replaceChild(UE.uNode.createElement(html), node);
  18733. }
  18734. }
  18735. );
  18736. }
  18737. me.addOutputRule(function (root) {
  18738. switchImgAndVideo(root, true);
  18739. });
  18740. me.addInputRule(function (root) {
  18741. switchImgAndVideo(root);
  18742. });
  18743. /**
  18744. * 插入视频
  18745. * @command insertvideo
  18746. * @method execCommand
  18747. * @param { String } cmd 命令字符串
  18748. * @param { Object } videoAttr 键值对对象, 描述一个视频的所有属性
  18749. * @example
  18750. * ```javascript
  18751. *
  18752. * var videoAttr = {
  18753. * //视频地址
  18754. * url: 'http://www.youku.com/xxx',
  18755. * //视频宽高值, 单位px
  18756. * width: 200,
  18757. * height: 100
  18758. * };
  18759. *
  18760. * //editor 是编辑器实例
  18761. * //向编辑器插入单个视频
  18762. * editor.execCommand( 'insertvideo', videoAttr );
  18763. * ```
  18764. */
  18765. /**
  18766. * 插入视频
  18767. * @command insertvideo
  18768. * @method execCommand
  18769. * @param { String } cmd 命令字符串
  18770. * @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
  18771. * @example
  18772. * ```javascript
  18773. *
  18774. * var videoAttr1 = {
  18775. * //视频地址
  18776. * url: 'http://www.youku.com/xxx',
  18777. * //视频宽高值, 单位px
  18778. * width: 200,
  18779. * height: 100
  18780. * },
  18781. * videoAttr2 = {
  18782. * //视频地址
  18783. * url: 'http://www.youku.com/xxx',
  18784. * //视频宽高值, 单位px
  18785. * width: 200,
  18786. * height: 100
  18787. * }
  18788. *
  18789. * //editor 是编辑器实例
  18790. * //该方法将会向编辑器内插入两个视频
  18791. * editor.execCommand( 'insertvideo', [ videoAttr1, videoAttr2 ] );
  18792. * ```
  18793. */
  18794. /**
  18795. * 查询当前光标所在处是否是一个视频
  18796. * @command insertvideo
  18797. * @method queryCommandState
  18798. * @param { String } cmd 需要查询的命令字符串
  18799. * @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
  18800. * @example
  18801. * ```javascript
  18802. *
  18803. * //editor 是编辑器实例
  18804. * editor.queryCommandState( 'insertvideo' );
  18805. * ```
  18806. */
  18807. me.commands["insertvideo"] = {
  18808. execCommand: function (cmd, videoObjs, type) {
  18809. videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs];
  18810. if (me.fireEvent("beforeinsertvideo", videoObjs) === true) {
  18811. return;
  18812. }
  18813. var html = [],
  18814. id = "tmpVedio",
  18815. cl;
  18816. for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
  18817. vi = videoObjs[i];
  18818. cl = type == "upload"
  18819. ? "edui-upload-video video-js vjs-default-skin"
  18820. : "edui-faked-video";
  18821. html.push(
  18822. creatInsertStr(
  18823. vi.url,
  18824. vi.width || 420,
  18825. vi.height || 280,
  18826. id + i,
  18827. null,
  18828. cl,
  18829. "image"
  18830. )
  18831. );
  18832. }
  18833. me.execCommand("inserthtml", html.join(""), true);
  18834. var rng = this.selection.getRange();
  18835. for (var i = 0, len = videoObjs.length; i < len; i++) {
  18836. var img = this.document.getElementById("tmpVedio" + i);
  18837. domUtils.removeAttributes(img, "id");
  18838. rng.selectNode(img).select();
  18839. me.execCommand("imagefloat", videoObjs[i].align);
  18840. }
  18841. me.fireEvent("afterinsertvideo", videoObjs);
  18842. },
  18843. queryCommandState: function () {
  18844. var img = me.selection.getRange().getClosedNode(),
  18845. flag =
  18846. img &&
  18847. (img.className == "edui-faked-video" ||
  18848. img.className.indexOf("edui-upload-video") != -1);
  18849. return flag ? 1 : 0;
  18850. }
  18851. };
  18852. };
  18853. // plugins/table.core.js
  18854. /**
  18855. * Created with JetBrains WebStorm.
  18856. * User: taoqili
  18857. * Date: 13-1-18
  18858. * Time: 上午11:09
  18859. * To change this template use File | Settings | File Templates.
  18860. */
  18861. /**
  18862. * UE表格操作类
  18863. * @param table
  18864. * @constructor
  18865. */
  18866. ;(function () {
  18867. var UETable = (UE.UETable = function (table) {
  18868. this.table = table;
  18869. this.indexTable = [];
  18870. this.selectedTds = [];
  18871. this.cellsRange = {};
  18872. this.update(table);
  18873. });
  18874. //===以下为静态工具方法===
  18875. UETable.removeSelectedClass = function (cells) {
  18876. utils.each(cells, function (cell) {
  18877. domUtils.removeClasses(cell, "selectTdClass");
  18878. });
  18879. };
  18880. UETable.addSelectedClass = function (cells) {
  18881. utils.each(cells, function (cell) {
  18882. domUtils.addClass(cell, "selectTdClass");
  18883. });
  18884. };
  18885. UETable.isEmptyBlock = function (node) {
  18886. var reg = new RegExp(domUtils.fillChar, "g");
  18887. if (
  18888. node[browser.ie ? "innerText" : "textContent"]
  18889. .replace(/^\s*$/, "")
  18890. .replace(reg, "").length > 0
  18891. ) {
  18892. return 0;
  18893. }
  18894. for (var i in dtd.$isNotEmpty)
  18895. if (dtd.$isNotEmpty.hasOwnProperty(i)) {
  18896. if (node.getElementsByTagName(i).length) {
  18897. return 0;
  18898. }
  18899. }
  18900. return 1;
  18901. };
  18902. UETable.getWidth = function (cell) {
  18903. if (!cell) return 0;
  18904. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  18905. };
  18906. /**
  18907. * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
  18908. * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
  18909. * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
  18910. * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
  18911. */
  18912. UETable.getTableCellAlignState = function (cells) {
  18913. !utils.isArray(cells) && (cells = [cells]);
  18914. var result = {},
  18915. status = ["align", "valign"],
  18916. tempStatus = null,
  18917. isSame = true; //状态是否相同
  18918. utils.each(cells, function (cellNode) {
  18919. utils.each(status, function (currentState) {
  18920. tempStatus = cellNode.getAttribute(currentState);
  18921. if (!result[currentState] && tempStatus) {
  18922. result[currentState] = tempStatus;
  18923. } else if (
  18924. !result[currentState] ||
  18925. tempStatus !== result[currentState]
  18926. ) {
  18927. isSame = false;
  18928. return false;
  18929. }
  18930. });
  18931. return isSame;
  18932. });
  18933. return isSame ? result : null;
  18934. };
  18935. /**
  18936. * 根据当前选区获取相关的table信息
  18937. * @return {Object}
  18938. */
  18939. UETable.getTableItemsByRange = function (editor) {
  18940. var start = editor.selection.getStart();
  18941. //ff下会选中bookmark
  18942. if (
  18943. start &&
  18944. start.id &&
  18945. start.id.indexOf("_baidu_bookmark_start_") === 0 &&
  18946. start.nextSibling
  18947. ) {
  18948. start = start.nextSibling;
  18949. }
  18950. //在table或者td边缘有可能存在选中tr的情况
  18951. var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
  18952. tr = cell && cell.parentNode,
  18953. table = tr && domUtils.findParentByTagName(tr, ["table"]),
  18954. caption = table && table.getElementsByTagName("caption")[0];
  18955. return {
  18956. cell: cell,
  18957. tr: tr,
  18958. table: table,
  18959. caption: caption
  18960. };
  18961. };
  18962. UETable.getUETableBySelected = function (editor) {
  18963. var table = UETable.getTableItemsByRange(editor).table;
  18964. if (table && table.ueTable && table.ueTable.selectedTds.length) {
  18965. return table.ueTable;
  18966. }
  18967. return null;
  18968. };
  18969. UETable.getDefaultValue = function (editor, table) {
  18970. var borderMap = {
  18971. thin: "0px",
  18972. medium: "1px",
  18973. thick: "2px"
  18974. },
  18975. tableBorder,
  18976. tdPadding,
  18977. tdBorder,
  18978. tmpValue;
  18979. if (!table) {
  18980. table = editor.document.createElement("table");
  18981. table.insertRow(0).insertCell(0).innerHTML = "xxx";
  18982. editor.body.appendChild(table);
  18983. var td = table.getElementsByTagName("td")[0];
  18984. tmpValue = domUtils.getComputedStyle(table, "border-left-width");
  18985. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18986. tmpValue = domUtils.getComputedStyle(td, "padding-left");
  18987. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18988. tmpValue = domUtils.getComputedStyle(td, "border-left-width");
  18989. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18990. domUtils.remove(table);
  18991. return {
  18992. tableBorder: tableBorder,
  18993. tdPadding: tdPadding,
  18994. tdBorder: tdBorder
  18995. };
  18996. } else {
  18997. td = table.getElementsByTagName("td")[0];
  18998. tmpValue = domUtils.getComputedStyle(table, "border-left-width");
  18999. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  19000. tmpValue = domUtils.getComputedStyle(td, "padding-left");
  19001. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  19002. tmpValue = domUtils.getComputedStyle(td, "border-left-width");
  19003. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  19004. return {
  19005. tableBorder: tableBorder,
  19006. tdPadding: tdPadding,
  19007. tdBorder: tdBorder
  19008. };
  19009. }
  19010. };
  19011. /**
  19012. * 根据当前点击的td或者table获取索引对象
  19013. * @param tdOrTable
  19014. */
  19015. UETable.getUETable = function (tdOrTable) {
  19016. var tag = tdOrTable.tagName.toLowerCase();
  19017. tdOrTable = tag == "td" || tag == "th" || tag == "caption"
  19018. ? domUtils.findParentByTagName(tdOrTable, "table", true)
  19019. : tdOrTable;
  19020. if (!tdOrTable.ueTable) {
  19021. tdOrTable.ueTable = new UETable(tdOrTable);
  19022. }
  19023. return tdOrTable.ueTable;
  19024. };
  19025. UETable.cloneCell = function (cell, ignoreMerge, keepPro) {
  19026. if (!cell || utils.isString(cell)) {
  19027. return this.table.ownerDocument.createElement(cell || "td");
  19028. }
  19029. var flag = domUtils.hasClass(cell, "selectTdClass");
  19030. flag && domUtils.removeClasses(cell, "selectTdClass");
  19031. var tmpCell = cell.cloneNode(true);
  19032. if (ignoreMerge) {
  19033. tmpCell.rowSpan = tmpCell.colSpan = 1;
  19034. }
  19035. //去掉宽高
  19036. !keepPro && domUtils.removeAttributes(tmpCell, "width height");
  19037. !keepPro && domUtils.removeAttributes(tmpCell, "style");
  19038. tmpCell.style.borderLeftStyle = "";
  19039. tmpCell.style.borderTopStyle = "";
  19040. tmpCell.style.borderLeftColor = cell.style.borderRightColor;
  19041. tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
  19042. tmpCell.style.borderTopColor = cell.style.borderBottomColor;
  19043. tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
  19044. flag && domUtils.addClass(cell, "selectTdClass");
  19045. return tmpCell;
  19046. };
  19047. UETable.prototype = {
  19048. getMaxRows: function () {
  19049. var rows = this.table.rows,
  19050. maxLen = 1;
  19051. for (var i = 0, row; (row = rows[i]); i++) {
  19052. var currentMax = 1;
  19053. for (var j = 0, cj; (cj = row.cells[j++]);) {
  19054. currentMax = Math.max(cj.rowSpan || 1, currentMax);
  19055. }
  19056. maxLen = Math.max(currentMax + i, maxLen);
  19057. }
  19058. return maxLen;
  19059. },
  19060. /**
  19061. * 获取当前表格的最大列数
  19062. */
  19063. getMaxCols: function () {
  19064. var rows = this.table.rows,
  19065. maxLen = 0,
  19066. cellRows = {};
  19067. for (var i = 0, row; (row = rows[i]); i++) {
  19068. var cellsNum = 0;
  19069. for (var j = 0, cj; (cj = row.cells[j++]);) {
  19070. cellsNum += cj.colSpan || 1;
  19071. if (cj.rowSpan && cj.rowSpan > 1) {
  19072. for (var k = 1; k < cj.rowSpan; k++) {
  19073. if (!cellRows["row_" + (i + k)]) {
  19074. cellRows["row_" + (i + k)] = cj.colSpan || 1;
  19075. } else {
  19076. cellRows["row_" + (i + k)]++;
  19077. }
  19078. }
  19079. }
  19080. }
  19081. cellsNum += cellRows["row_" + i] || 0;
  19082. maxLen = Math.max(cellsNum, maxLen);
  19083. }
  19084. return maxLen;
  19085. },
  19086. getCellColIndex: function (cell) {
  19087. },
  19088. /**
  19089. * 获取当前cell旁边的单元格,
  19090. * @param cell
  19091. * @param right
  19092. */
  19093. getHSideCell: function (cell, right) {
  19094. try {
  19095. var cellInfo = this.getCellInfo(cell),
  19096. previewRowIndex,
  19097. previewColIndex;
  19098. var len = this.selectedTds.length,
  19099. range = this.cellsRange;
  19100. //首行或者首列没有前置单元格
  19101. if (
  19102. (!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
  19103. (right &&
  19104. (!len
  19105. ? cellInfo.colIndex == this.colsNum - 1
  19106. : range.endColIndex == this.colsNum - 1))
  19107. )
  19108. return null;
  19109. previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
  19110. previewColIndex = !right
  19111. ? !len
  19112. ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
  19113. : range.beginColIndex - 1
  19114. : !len ? cellInfo.colIndex + 1 : range.endColIndex + 1;
  19115. return this.getCell(
  19116. this.indexTable[previewRowIndex][previewColIndex].rowIndex,
  19117. this.indexTable[previewRowIndex][previewColIndex].cellIndex
  19118. );
  19119. } catch (e) {
  19120. showError(e);
  19121. }
  19122. },
  19123. getTabNextCell: function (cell, preRowIndex) {
  19124. var cellInfo = this.getCellInfo(cell),
  19125. rowIndex = preRowIndex || cellInfo.rowIndex,
  19126. colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
  19127. nextCell;
  19128. try {
  19129. nextCell = this.getCell(
  19130. this.indexTable[rowIndex][colIndex].rowIndex,
  19131. this.indexTable[rowIndex][colIndex].cellIndex
  19132. );
  19133. } catch (e) {
  19134. try {
  19135. rowIndex = rowIndex * 1 + 1;
  19136. colIndex = 0;
  19137. nextCell = this.getCell(
  19138. this.indexTable[rowIndex][colIndex].rowIndex,
  19139. this.indexTable[rowIndex][colIndex].cellIndex
  19140. );
  19141. } catch (e) {
  19142. }
  19143. }
  19144. return nextCell;
  19145. },
  19146. /**
  19147. * 获取视觉上的后置单元格
  19148. * @param cell
  19149. * @param bottom
  19150. */
  19151. getVSideCell: function (cell, bottom, ignoreRange) {
  19152. try {
  19153. var cellInfo = this.getCellInfo(cell),
  19154. nextRowIndex,
  19155. nextColIndex;
  19156. var len = this.selectedTds.length && !ignoreRange,
  19157. range = this.cellsRange;
  19158. //末行或者末列没有后置单元格
  19159. if (
  19160. (!bottom && cellInfo.rowIndex == 0) ||
  19161. (bottom &&
  19162. (!len
  19163. ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
  19164. : range.endRowIndex == this.rowsNum - 1))
  19165. )
  19166. return null;
  19167. nextRowIndex = !bottom
  19168. ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
  19169. : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
  19170. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  19171. return this.getCell(
  19172. this.indexTable[nextRowIndex][nextColIndex].rowIndex,
  19173. this.indexTable[nextRowIndex][nextColIndex].cellIndex
  19174. );
  19175. } catch (e) {
  19176. showError(e);
  19177. }
  19178. },
  19179. /**
  19180. * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
  19181. */
  19182. getSameEndPosCells: function (cell, xOrY) {
  19183. try {
  19184. var flag = xOrY.toLowerCase() === "x",
  19185. end =
  19186. domUtils.getXY(cell)[flag ? "x" : "y"] +
  19187. cell["offset" + (flag ? "Width" : "Height")],
  19188. rows = this.table.rows,
  19189. cells = null,
  19190. returns = [];
  19191. for (var i = 0; i < this.rowsNum; i++) {
  19192. cells = rows[i].cells;
  19193. for (var j = 0, tmpCell; (tmpCell = cells[j++]);) {
  19194. var tmpEnd =
  19195. domUtils.getXY(tmpCell)[flag ? "x" : "y"] +
  19196. tmpCell["offset" + (flag ? "Width" : "Height")];
  19197. //对应行的td已经被上面行rowSpan了
  19198. if (tmpEnd > end && flag) break;
  19199. if (cell == tmpCell || end == tmpEnd) {
  19200. //只获取单一的单元格
  19201. //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
  19202. if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
  19203. returns.push(tmpCell);
  19204. }
  19205. if (flag) break;
  19206. }
  19207. }
  19208. }
  19209. return returns;
  19210. } catch (e) {
  19211. showError(e);
  19212. }
  19213. },
  19214. setCellContent: function (cell, content) {
  19215. cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />");
  19216. },
  19217. cloneCell: UETable.cloneCell,
  19218. /**
  19219. * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
  19220. */
  19221. getSameStartPosXCells: function (cell) {
  19222. try {
  19223. var start = domUtils.getXY(cell).x + cell.offsetWidth,
  19224. rows = this.table.rows,
  19225. cells,
  19226. returns = [];
  19227. for (var i = 0; i < this.rowsNum; i++) {
  19228. cells = rows[i].cells;
  19229. for (var j = 0, tmpCell; (tmpCell = cells[j++]);) {
  19230. var tmpStart = domUtils.getXY(tmpCell).x;
  19231. if (tmpStart > start) break;
  19232. if (tmpStart == start && tmpCell.colSpan == 1) {
  19233. returns.push(tmpCell);
  19234. break;
  19235. }
  19236. }
  19237. }
  19238. return returns;
  19239. } catch (e) {
  19240. showError(e);
  19241. }
  19242. },
  19243. /**
  19244. * 更新table对应的索引表
  19245. */
  19246. update: function (table) {
  19247. this.table = table || this.table;
  19248. this.selectedTds = [];
  19249. this.cellsRange = {};
  19250. this.indexTable = [];
  19251. var rows = this.table.rows,
  19252. rowsNum = this.getMaxRows(),
  19253. dNum = rowsNum - rows.length,
  19254. colsNum = this.getMaxCols();
  19255. while (dNum--) {
  19256. this.table.insertRow(rows.length);
  19257. }
  19258. this.rowsNum = rowsNum;
  19259. this.colsNum = colsNum;
  19260. for (var i = 0, len = rows.length; i < len; i++) {
  19261. this.indexTable[i] = new Array(colsNum);
  19262. }
  19263. //填充索引表
  19264. for (var rowIndex = 0, row; (row = rows[rowIndex]); rowIndex++) {
  19265. for (
  19266. var cellIndex = 0, cell, cells = row.cells;
  19267. (cell = cells[cellIndex]);
  19268. cellIndex++
  19269. ) {
  19270. //修正整行被rowSpan时导致的行数计算错误
  19271. if (cell.rowSpan > rowsNum) {
  19272. cell.rowSpan = rowsNum;
  19273. }
  19274. var colIndex = cellIndex,
  19275. rowSpan = cell.rowSpan || 1,
  19276. colSpan = cell.colSpan || 1;
  19277. //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
  19278. while (this.indexTable[rowIndex][colIndex]) colIndex++;
  19279. for (var j = 0; j < rowSpan; j++) {
  19280. for (var k = 0; k < colSpan; k++) {
  19281. this.indexTable[rowIndex + j][colIndex + k] = {
  19282. rowIndex: rowIndex,
  19283. cellIndex: cellIndex,
  19284. colIndex: colIndex,
  19285. rowSpan: rowSpan,
  19286. colSpan: colSpan
  19287. };
  19288. }
  19289. }
  19290. }
  19291. }
  19292. //修复残缺td
  19293. for (j = 0; j < rowsNum; j++) {
  19294. for (k = 0; k < colsNum; k++) {
  19295. if (this.indexTable[j][k] === undefined) {
  19296. row = rows[j];
  19297. cell = row.cells[row.cells.length - 1];
  19298. cell = cell
  19299. ? cell.cloneNode(true)
  19300. : this.table.ownerDocument.createElement("td");
  19301. this.setCellContent(cell);
  19302. if (cell.colSpan !== 1) cell.colSpan = 1;
  19303. if (cell.rowSpan !== 1) cell.rowSpan = 1;
  19304. row.appendChild(cell);
  19305. this.indexTable[j][k] = {
  19306. rowIndex: j,
  19307. cellIndex: cell.cellIndex,
  19308. colIndex: k,
  19309. rowSpan: 1,
  19310. colSpan: 1
  19311. };
  19312. }
  19313. }
  19314. }
  19315. //当框选后删除行或者列后撤销,需要重建选区。
  19316. var tds = domUtils.getElementsByTagName(this.table, "td"),
  19317. selectTds = [];
  19318. utils.each(tds, function (td) {
  19319. if (domUtils.hasClass(td, "selectTdClass")) {
  19320. selectTds.push(td);
  19321. }
  19322. });
  19323. if (selectTds.length) {
  19324. var start = selectTds[0],
  19325. end = selectTds[selectTds.length - 1],
  19326. startInfo = this.getCellInfo(start),
  19327. endInfo = this.getCellInfo(end);
  19328. this.selectedTds = selectTds;
  19329. this.cellsRange = {
  19330. beginRowIndex: startInfo.rowIndex,
  19331. beginColIndex: startInfo.colIndex,
  19332. endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
  19333. endColIndex: endInfo.colIndex + endInfo.colSpan - 1
  19334. };
  19335. }
  19336. //给第一行设置firstRow的样式名称,在排序图标的样式上使用到
  19337. if (!domUtils.hasClass(this.table.rows[0], "firstRow")) {
  19338. domUtils.addClass(this.table.rows[0], "firstRow");
  19339. for (var i = 1; i < this.table.rows.length; i++) {
  19340. domUtils.removeClasses(this.table.rows[i], "firstRow");
  19341. }
  19342. }
  19343. },
  19344. /**
  19345. * 获取单元格的索引信息
  19346. */
  19347. getCellInfo: function (cell) {
  19348. if (!cell) return;
  19349. var cellIndex = cell.cellIndex,
  19350. rowIndex = cell.parentNode.rowIndex,
  19351. rowInfo = this.indexTable[rowIndex],
  19352. numCols = this.colsNum;
  19353. for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
  19354. var cellInfo = rowInfo[colIndex];
  19355. if (
  19356. cellInfo.rowIndex === rowIndex &&
  19357. cellInfo.cellIndex === cellIndex
  19358. ) {
  19359. return cellInfo;
  19360. }
  19361. }
  19362. },
  19363. /**
  19364. * 根据行列号获取单元格
  19365. */
  19366. getCell: function (rowIndex, cellIndex) {
  19367. return (
  19368. (rowIndex < this.rowsNum &&
  19369. this.table.rows[rowIndex].cells[cellIndex]) ||
  19370. null
  19371. );
  19372. },
  19373. /**
  19374. * 删除单元格
  19375. */
  19376. deleteCell: function (cell, rowIndex) {
  19377. rowIndex = typeof rowIndex == "number"
  19378. ? rowIndex
  19379. : cell.parentNode.rowIndex;
  19380. var row = this.table.rows[rowIndex];
  19381. row.deleteCell(cell.cellIndex);
  19382. },
  19383. /**
  19384. * 根据始末两个单元格获取被框选的所有单元格范围
  19385. */
  19386. getCellsRange: function (cellA, cellB) {
  19387. function checkRange(
  19388. beginRowIndex,
  19389. beginColIndex,
  19390. endRowIndex,
  19391. endColIndex
  19392. ) {
  19393. var tmpBeginRowIndex = beginRowIndex,
  19394. tmpBeginColIndex = beginColIndex,
  19395. tmpEndRowIndex = endRowIndex,
  19396. tmpEndColIndex = endColIndex,
  19397. cellInfo,
  19398. colIndex,
  19399. rowIndex;
  19400. // 通过indexTable检查是否存在超出TableRange上边界的情况
  19401. if (beginRowIndex > 0) {
  19402. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  19403. cellInfo = me.indexTable[beginRowIndex][colIndex];
  19404. rowIndex = cellInfo.rowIndex;
  19405. if (rowIndex < beginRowIndex) {
  19406. tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex);
  19407. }
  19408. }
  19409. }
  19410. // 通过indexTable检查是否存在超出TableRange右边界的情况
  19411. if (endColIndex < me.colsNum) {
  19412. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  19413. cellInfo = me.indexTable[rowIndex][endColIndex];
  19414. colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
  19415. if (colIndex > endColIndex) {
  19416. tmpEndColIndex = Math.max(colIndex, tmpEndColIndex);
  19417. }
  19418. }
  19419. }
  19420. // 检查是否有超出TableRange下边界的情况
  19421. if (endRowIndex < me.rowsNum) {
  19422. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  19423. cellInfo = me.indexTable[endRowIndex][colIndex];
  19424. rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
  19425. if (rowIndex > endRowIndex) {
  19426. tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex);
  19427. }
  19428. }
  19429. }
  19430. // 检查是否有超出TableRange左边界的情况
  19431. if (beginColIndex > 0) {
  19432. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  19433. cellInfo = me.indexTable[rowIndex][beginColIndex];
  19434. colIndex = cellInfo.colIndex;
  19435. if (colIndex < beginColIndex) {
  19436. tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex);
  19437. }
  19438. }
  19439. }
  19440. //递归调用直至所有完成所有框选单元格的扩展
  19441. if (
  19442. tmpBeginRowIndex != beginRowIndex ||
  19443. tmpBeginColIndex != beginColIndex ||
  19444. tmpEndRowIndex != endRowIndex ||
  19445. tmpEndColIndex != endColIndex
  19446. ) {
  19447. return checkRange(
  19448. tmpBeginRowIndex,
  19449. tmpBeginColIndex,
  19450. tmpEndRowIndex,
  19451. tmpEndColIndex
  19452. );
  19453. } else {
  19454. // 不需要扩展TableRange的情况
  19455. return {
  19456. beginRowIndex: beginRowIndex,
  19457. beginColIndex: beginColIndex,
  19458. endRowIndex: endRowIndex,
  19459. endColIndex: endColIndex
  19460. };
  19461. }
  19462. }
  19463. try {
  19464. var me = this,
  19465. cellAInfo = me.getCellInfo(cellA);
  19466. if (cellA === cellB) {
  19467. return {
  19468. beginRowIndex: cellAInfo.rowIndex,
  19469. beginColIndex: cellAInfo.colIndex,
  19470. endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  19471. endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
  19472. };
  19473. }
  19474. var cellBInfo = me.getCellInfo(cellB);
  19475. // 计算TableRange的四个边
  19476. var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
  19477. beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
  19478. endRowIndex = Math.max(
  19479. cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  19480. cellBInfo.rowIndex + cellBInfo.rowSpan - 1
  19481. ),
  19482. endColIndex = Math.max(
  19483. cellAInfo.colIndex + cellAInfo.colSpan - 1,
  19484. cellBInfo.colIndex + cellBInfo.colSpan - 1
  19485. );
  19486. return checkRange(
  19487. beginRowIndex,
  19488. beginColIndex,
  19489. endRowIndex,
  19490. endColIndex
  19491. );
  19492. } catch (e) {
  19493. //throw e;
  19494. }
  19495. },
  19496. /**
  19497. * 依据cellsRange获取对应的单元格集合
  19498. */
  19499. getCells: function (range) {
  19500. //每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
  19501. this.clearSelected();
  19502. var beginRowIndex = range.beginRowIndex,
  19503. beginColIndex = range.beginColIndex,
  19504. endRowIndex = range.endRowIndex,
  19505. endColIndex = range.endColIndex,
  19506. cellInfo,
  19507. rowIndex,
  19508. colIndex,
  19509. tdHash = {},
  19510. returnTds = [];
  19511. for (var i = beginRowIndex; i <= endRowIndex; i++) {
  19512. for (var j = beginColIndex; j <= endColIndex; j++) {
  19513. cellInfo = this.indexTable[i][j];
  19514. rowIndex = cellInfo.rowIndex;
  19515. colIndex = cellInfo.colIndex;
  19516. // 如果Cells里已经包含了此Cell则跳过
  19517. var key = rowIndex + "|" + colIndex;
  19518. if (tdHash[key]) continue;
  19519. tdHash[key] = 1;
  19520. if (
  19521. rowIndex < i ||
  19522. colIndex < j ||
  19523. rowIndex + cellInfo.rowSpan - 1 > endRowIndex ||
  19524. colIndex + cellInfo.colSpan - 1 > endColIndex
  19525. ) {
  19526. return null;
  19527. }
  19528. returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex));
  19529. }
  19530. }
  19531. return returnTds;
  19532. },
  19533. /**
  19534. * 清理已经选中的单元格
  19535. */
  19536. clearSelected: function () {
  19537. UETable.removeSelectedClass(this.selectedTds);
  19538. this.selectedTds = [];
  19539. this.cellsRange = {};
  19540. },
  19541. /**
  19542. * 根据range设置已经选中的单元格
  19543. */
  19544. setSelected: function (range) {
  19545. var cells = this.getCells(range);
  19546. UETable.addSelectedClass(cells);
  19547. this.selectedTds = cells;
  19548. this.cellsRange = range;
  19549. },
  19550. isFullRow: function () {
  19551. var range = this.cellsRange;
  19552. return range.endColIndex - range.beginColIndex + 1 == this.colsNum;
  19553. },
  19554. isFullCol: function () {
  19555. var range = this.cellsRange,
  19556. table = this.table,
  19557. ths = table.getElementsByTagName("th"),
  19558. rows = range.endRowIndex - range.beginRowIndex + 1;
  19559. return !ths.length
  19560. ? rows == this.rowsNum
  19561. : rows == this.rowsNum || rows == this.rowsNum - 1;
  19562. },
  19563. /**
  19564. * 获取视觉上的前置单元格,默认是左边,top传入时
  19565. * @param cell
  19566. * @param top
  19567. */
  19568. getNextCell: function (cell, bottom, ignoreRange) {
  19569. try {
  19570. var cellInfo = this.getCellInfo(cell),
  19571. nextRowIndex,
  19572. nextColIndex;
  19573. var len = this.selectedTds.length && !ignoreRange,
  19574. range = this.cellsRange;
  19575. //末行或者末列没有后置单元格
  19576. if (
  19577. (!bottom && cellInfo.rowIndex == 0) ||
  19578. (bottom &&
  19579. (!len
  19580. ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
  19581. : range.endRowIndex == this.rowsNum - 1))
  19582. )
  19583. return null;
  19584. nextRowIndex = !bottom
  19585. ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
  19586. : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
  19587. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  19588. return this.getCell(
  19589. this.indexTable[nextRowIndex][nextColIndex].rowIndex,
  19590. this.indexTable[nextRowIndex][nextColIndex].cellIndex
  19591. );
  19592. } catch (e) {
  19593. showError(e);
  19594. }
  19595. },
  19596. getPreviewCell: function (cell, top) {
  19597. try {
  19598. var cellInfo = this.getCellInfo(cell),
  19599. previewRowIndex,
  19600. previewColIndex;
  19601. var len = this.selectedTds.length,
  19602. range = this.cellsRange;
  19603. //首行或者首列没有前置单元格
  19604. if (
  19605. (!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
  19606. (top &&
  19607. (!len
  19608. ? cellInfo.rowIndex > this.colsNum - 1
  19609. : range.endColIndex == this.colsNum - 1))
  19610. )
  19611. return null;
  19612. previewRowIndex = !top
  19613. ? !len ? cellInfo.rowIndex : range.beginRowIndex
  19614. : !len
  19615. ? cellInfo.rowIndex < 1 ? 0 : cellInfo.rowIndex - 1
  19616. : range.beginRowIndex;
  19617. previewColIndex = !top
  19618. ? !len
  19619. ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
  19620. : range.beginColIndex - 1
  19621. : !len ? cellInfo.colIndex : range.endColIndex + 1;
  19622. return this.getCell(
  19623. this.indexTable[previewRowIndex][previewColIndex].rowIndex,
  19624. this.indexTable[previewRowIndex][previewColIndex].cellIndex
  19625. );
  19626. } catch (e) {
  19627. showError(e);
  19628. }
  19629. },
  19630. /**
  19631. * 移动单元格中的内容
  19632. */
  19633. moveContent: function (cellTo, cellFrom) {
  19634. if (UETable.isEmptyBlock(cellFrom)) return;
  19635. if (UETable.isEmptyBlock(cellTo)) {
  19636. cellTo.innerHTML = cellFrom.innerHTML;
  19637. return;
  19638. }
  19639. var child = cellTo.lastChild;
  19640. if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
  19641. cellTo.appendChild(cellTo.ownerDocument.createElement("br"));
  19642. }
  19643. while ((child = cellFrom.firstChild)) {
  19644. cellTo.appendChild(child);
  19645. }
  19646. },
  19647. /**
  19648. * 向右合并单元格
  19649. */
  19650. mergeRight: function (cell) {
  19651. var cellInfo = this.getCellInfo(cell),
  19652. rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
  19653. rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
  19654. rightCell = this.getCell(
  19655. rightCellInfo.rowIndex,
  19656. rightCellInfo.cellIndex
  19657. );
  19658. //合并
  19659. cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
  19660. //被合并的单元格不应存在宽度属性
  19661. cell.removeAttribute("width");
  19662. //移动内容
  19663. this.moveContent(cell, rightCell);
  19664. //删掉被合并的Cell
  19665. this.deleteCell(rightCell, rightCellInfo.rowIndex);
  19666. this.update();
  19667. },
  19668. /**
  19669. * 向下合并单元格
  19670. */
  19671. mergeDown: function (cell) {
  19672. var cellInfo = this.getCellInfo(cell),
  19673. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
  19674. downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
  19675. downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
  19676. cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
  19677. cell.removeAttribute("height");
  19678. this.moveContent(cell, downCell);
  19679. this.deleteCell(downCell, downCellInfo.rowIndex);
  19680. this.update();
  19681. },
  19682. /**
  19683. * 合并整个range中的内容
  19684. */
  19685. mergeRange: function () {
  19686. //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
  19687. var range = this.cellsRange,
  19688. leftTopCell = this.getCell(
  19689. range.beginRowIndex,
  19690. this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
  19691. );
  19692. // 这段关于行表头或者列表头的特殊处理会导致表头合并范围错误
  19693. // 为什么有这段代码的原因未明,暂且注释掉,希望原作者看到后出面说明下
  19694. // if (
  19695. // leftTopCell.tagName == "TH" &&
  19696. // range.endRowIndex !== range.beginRowIndex
  19697. // ) {
  19698. // var index = this.indexTable,
  19699. // info = this.getCellInfo(leftTopCell);
  19700. // leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
  19701. // range = this.getCellsRange(
  19702. // leftTopCell,
  19703. // this.getCell(
  19704. // index[this.rowsNum - 1][info.colIndex].rowIndex,
  19705. // index[this.rowsNum - 1][info.colIndex].cellIndex
  19706. // )
  19707. // );
  19708. // }
  19709. // 删除剩余的Cells
  19710. var cells = this.getCells(range);
  19711. for (var i = 0, ci; (ci = cells[i++]);) {
  19712. if (ci !== leftTopCell) {
  19713. this.moveContent(leftTopCell, ci);
  19714. this.deleteCell(ci);
  19715. }
  19716. }
  19717. // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
  19718. leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
  19719. leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
  19720. leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
  19721. leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
  19722. if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
  19723. leftTopCell.colSpan = 1;
  19724. }
  19725. if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
  19726. var rowIndex = leftTopCell.parentNode.rowIndex;
  19727. //解决IE下的表格操作问题
  19728. if (this.table.deleteRow) {
  19729. for (
  19730. var i = rowIndex + 1,
  19731. curIndex = rowIndex + 1,
  19732. len = leftTopCell.rowSpan;
  19733. i < len;
  19734. i++
  19735. ) {
  19736. this.table.deleteRow(curIndex);
  19737. }
  19738. } else {
  19739. for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
  19740. var row = this.table.rows[rowIndex + 1];
  19741. row.parentNode.removeChild(row);
  19742. }
  19743. }
  19744. leftTopCell.rowSpan = 1;
  19745. }
  19746. this.update();
  19747. },
  19748. /**
  19749. * 插入一行单元格
  19750. */
  19751. insertRow: function (rowIndex, sourceCell) {
  19752. var numCols = this.colsNum,
  19753. table = this.table,
  19754. row = table.insertRow(rowIndex),
  19755. cell,
  19756. thead = null,
  19757. isInsertTitle =
  19758. typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";
  19759. function replaceTdToTh(colIndex, cell, tableRow) {
  19760. if (colIndex == 0) {
  19761. var tr = tableRow.nextSibling || tableRow.previousSibling,
  19762. th = tr.cells[colIndex];
  19763. if (th.tagName == "TH") {
  19764. th = cell.ownerDocument.createElement("th");
  19765. th.appendChild(cell.firstChild);
  19766. tableRow.insertBefore(th, cell);
  19767. domUtils.remove(cell);
  19768. }
  19769. } else {
  19770. if (cell.tagName == "TH") {
  19771. var td = cell.ownerDocument.createElement("td");
  19772. td.appendChild(cell.firstChild);
  19773. tableRow.insertBefore(td, cell);
  19774. domUtils.remove(cell);
  19775. }
  19776. }
  19777. }
  19778. //首行直接插入,无需考虑部分单元格被rowspan的情况
  19779. if (rowIndex == 0 || rowIndex == this.rowsNum) {
  19780. for (var colIndex = 0; colIndex < numCols; colIndex++) {
  19781. cell = this.cloneCell(sourceCell, true);
  19782. this.setCellContent(cell);
  19783. cell.getAttribute("vAlign") &&
  19784. cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  19785. row.appendChild(cell);
  19786. if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
  19787. }
  19788. if (isInsertTitle) {
  19789. thead = table.createTHead();
  19790. thead.insertBefore(row, thead.firstChild);
  19791. }
  19792. } else {
  19793. var infoRow = this.indexTable[rowIndex],
  19794. cellIndex = 0;
  19795. for (colIndex = 0; colIndex < numCols; colIndex++) {
  19796. var cellInfo = infoRow[colIndex];
  19797. //如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
  19798. if (cellInfo.rowIndex < rowIndex) {
  19799. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19800. cell.rowSpan = cellInfo.rowSpan + 1;
  19801. } else {
  19802. cell = this.cloneCell(sourceCell, true);
  19803. this.setCellContent(cell);
  19804. row.appendChild(cell);
  19805. }
  19806. if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
  19807. }
  19808. }
  19809. //框选时插入不触发contentchange,需要手动更新索引。
  19810. this.update();
  19811. return row;
  19812. },
  19813. /**
  19814. * 删除一行单元格
  19815. * @param rowIndex
  19816. */
  19817. deleteRow: function (rowIndex) {
  19818. var row = this.table.rows[rowIndex],
  19819. infoRow = this.indexTable[rowIndex],
  19820. colsNum = this.colsNum,
  19821. count = 0; //处理计数
  19822. for (var colIndex = 0; colIndex < colsNum;) {
  19823. var cellInfo = infoRow[colIndex],
  19824. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19825. if (cell.rowSpan > 1) {
  19826. if (cellInfo.rowIndex == rowIndex) {
  19827. var clone = cell.cloneNode(true);
  19828. clone.rowSpan = cell.rowSpan - 1;
  19829. clone.innerHTML = "";
  19830. cell.rowSpan = 1;
  19831. var nextRowIndex = rowIndex + 1,
  19832. nextRow = this.table.rows[nextRowIndex],
  19833. insertCellIndex,
  19834. preMerged =
  19835. this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count;
  19836. if (preMerged < colIndex) {
  19837. insertCellIndex = colIndex - preMerged - 1;
  19838. //nextRow.insertCell(insertCellIndex);
  19839. domUtils.insertAfter(nextRow.cells[insertCellIndex], clone);
  19840. } else {
  19841. if (nextRow.cells.length)
  19842. nextRow.insertBefore(clone, nextRow.cells[0]);
  19843. }
  19844. count += 1;
  19845. //cell.parentNode.removeChild(cell);
  19846. }
  19847. }
  19848. colIndex += cell.colSpan || 1;
  19849. }
  19850. var deleteTds = [],
  19851. cacheMap = {};
  19852. for (colIndex = 0; colIndex < colsNum; colIndex++) {
  19853. var tmpRowIndex = infoRow[colIndex].rowIndex,
  19854. tmpCellIndex = infoRow[colIndex].cellIndex,
  19855. key = tmpRowIndex + "_" + tmpCellIndex;
  19856. if (cacheMap[key]) continue;
  19857. cacheMap[key] = 1;
  19858. cell = this.getCell(tmpRowIndex, tmpCellIndex);
  19859. deleteTds.push(cell);
  19860. }
  19861. var mergeTds = [];
  19862. utils.each(deleteTds, function (td) {
  19863. if (td.rowSpan == 1) {
  19864. td.parentNode.removeChild(td);
  19865. } else {
  19866. mergeTds.push(td);
  19867. }
  19868. });
  19869. utils.each(mergeTds, function (td) {
  19870. td.rowSpan--;
  19871. });
  19872. row.parentNode.removeChild(row);
  19873. //浏览器方法本身存在bug,采用自定义方法删除
  19874. //this.table.deleteRow(rowIndex);
  19875. this.update();
  19876. },
  19877. insertCol: function (colIndex, sourceCell, defaultValue) {
  19878. var rowsNum = this.rowsNum,
  19879. rowIndex = 0,
  19880. tableRow,
  19881. cell,
  19882. backWidth = parseInt(
  19883. (this.table.offsetWidth -
  19884. (this.colsNum + 1) * 20 -
  19885. (this.colsNum + 1)) /
  19886. (this.colsNum + 1),
  19887. 10
  19888. ),
  19889. isInsertTitleCol =
  19890. typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";
  19891. function replaceTdToTh(rowIndex, cell, tableRow) {
  19892. if (rowIndex == 0) {
  19893. var th = cell.nextSibling || cell.previousSibling;
  19894. if (th.tagName == "TH") {
  19895. th = cell.ownerDocument.createElement("th");
  19896. th.appendChild(cell.firstChild);
  19897. tableRow.insertBefore(th, cell);
  19898. domUtils.remove(cell);
  19899. }
  19900. } else {
  19901. if (cell.tagName == "TH") {
  19902. var td = cell.ownerDocument.createElement("td");
  19903. td.appendChild(cell.firstChild);
  19904. tableRow.insertBefore(td, cell);
  19905. domUtils.remove(cell);
  19906. }
  19907. }
  19908. }
  19909. var preCell;
  19910. if (colIndex == 0 || colIndex == this.colsNum) {
  19911. for (; rowIndex < rowsNum; rowIndex++) {
  19912. tableRow = this.table.rows[rowIndex];
  19913. preCell =
  19914. tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
  19915. cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
  19916. this.setCellContent(cell);
  19917. cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  19918. preCell && cell.setAttribute("width", preCell.getAttribute("width"));
  19919. if (!colIndex) {
  19920. tableRow.insertBefore(cell, tableRow.cells[0]);
  19921. } else {
  19922. domUtils.insertAfter(
  19923. tableRow.cells[tableRow.cells.length - 1],
  19924. cell
  19925. );
  19926. }
  19927. if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
  19928. }
  19929. } else {
  19930. for (; rowIndex < rowsNum; rowIndex++) {
  19931. var cellInfo = this.indexTable[rowIndex][colIndex];
  19932. if (cellInfo.colIndex < colIndex) {
  19933. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19934. cell.colSpan = cellInfo.colSpan + 1;
  19935. } else {
  19936. tableRow = this.table.rows[rowIndex];
  19937. preCell = tableRow.cells[cellInfo.cellIndex];
  19938. cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(cellInfo.cellIndex);
  19939. this.setCellContent(cell);
  19940. cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  19941. preCell &&
  19942. cell.setAttribute("width", preCell.getAttribute("width"));
  19943. //防止IE下报错
  19944. preCell
  19945. ? tableRow.insertBefore(cell, preCell)
  19946. : tableRow.appendChild(cell);
  19947. }
  19948. if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
  19949. }
  19950. }
  19951. //框选时插入不触发contentchange,需要手动更新索引
  19952. this.update();
  19953. this.updateWidth(
  19954. backWidth,
  19955. defaultValue || {tdPadding: 10, tdBorder: 1}
  19956. );
  19957. },
  19958. updateWidth: function (width, defaultValue) {
  19959. var table = this.table,
  19960. tmpWidth =
  19961. UETable.getWidth(table) -
  19962. defaultValue.tdPadding * 2 -
  19963. defaultValue.tdBorder +
  19964. width;
  19965. if (tmpWidth < table.ownerDocument.body.offsetWidth) {
  19966. table.setAttribute("width", tmpWidth);
  19967. return;
  19968. }
  19969. var tds = domUtils.getElementsByTagName(this.table, "td th");
  19970. utils.each(tds, function (td) {
  19971. td.setAttribute("width", width);
  19972. });
  19973. },
  19974. deleteCol: function (colIndex) {
  19975. var indexTable = this.indexTable,
  19976. tableRows = this.table.rows,
  19977. backTableWidth = this.table.getAttribute("width"),
  19978. backTdWidth = 0,
  19979. rowsNum = this.rowsNum,
  19980. cacheMap = {};
  19981. for (var rowIndex = 0; rowIndex < rowsNum;) {
  19982. var infoRow = indexTable[rowIndex],
  19983. cellInfo = infoRow[colIndex],
  19984. key = cellInfo.rowIndex + "_" + cellInfo.colIndex;
  19985. // 跳过已经处理过的Cell
  19986. if (cacheMap[key]) continue;
  19987. cacheMap[key] = 1;
  19988. var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19989. if (!backTdWidth)
  19990. backTdWidth =
  19991. cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0);
  19992. // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
  19993. if (cell.colSpan > 1) {
  19994. cell.colSpan--;
  19995. } else {
  19996. tableRows[rowIndex].deleteCell(cellInfo.cellIndex);
  19997. }
  19998. rowIndex += cellInfo.rowSpan || 1;
  19999. }
  20000. this.table.setAttribute("width", backTableWidth - backTdWidth);
  20001. this.update();
  20002. },
  20003. splitToCells: function (cell) {
  20004. var me = this,
  20005. cells = this.splitToRows(cell);
  20006. utils.each(cells, function (cell) {
  20007. me.splitToCols(cell);
  20008. });
  20009. },
  20010. splitToRows: function (cell) {
  20011. var cellInfo = this.getCellInfo(cell),
  20012. rowIndex = cellInfo.rowIndex,
  20013. colIndex = cellInfo.colIndex,
  20014. results = [];
  20015. // 修改Cell的rowSpan
  20016. cell.rowSpan = 1;
  20017. results.push(cell);
  20018. // 补齐单元格
  20019. for (
  20020. var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan;
  20021. i < endRow;
  20022. i++
  20023. ) {
  20024. if (i == rowIndex) continue;
  20025. var tableRow = this.table.rows[i],
  20026. tmpCell = tableRow.insertCell(
  20027. colIndex - this.getPreviewMergedCellsNum(i, colIndex)
  20028. );
  20029. tmpCell.colSpan = cellInfo.colSpan;
  20030. this.setCellContent(tmpCell);
  20031. tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  20032. tmpCell.setAttribute("align", cell.getAttribute("align"));
  20033. if (cell.style.cssText) {
  20034. tmpCell.style.cssText = cell.style.cssText;
  20035. }
  20036. results.push(tmpCell);
  20037. }
  20038. this.update();
  20039. return results;
  20040. },
  20041. getPreviewMergedCellsNum: function (rowIndex, colIndex) {
  20042. var indexRow = this.indexTable[rowIndex],
  20043. num = 0;
  20044. for (var i = 0; i < colIndex;) {
  20045. var colSpan = indexRow[i].colSpan,
  20046. tmpRowIndex = indexRow[i].rowIndex;
  20047. num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0);
  20048. i += colSpan;
  20049. }
  20050. return num;
  20051. },
  20052. splitToCols: function (cell) {
  20053. var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
  20054. cellInfo = this.getCellInfo(cell),
  20055. rowIndex = cellInfo.rowIndex,
  20056. colIndex = cellInfo.colIndex,
  20057. results = [];
  20058. // 修改Cell的rowSpan
  20059. cell.colSpan = 1;
  20060. cell.setAttribute("width", backWidth);
  20061. results.push(cell);
  20062. // 补齐单元格
  20063. for (
  20064. var j = colIndex, endCol = colIndex + cellInfo.colSpan;
  20065. j < endCol;
  20066. j++
  20067. ) {
  20068. if (j == colIndex) continue;
  20069. var tableRow = this.table.rows[rowIndex],
  20070. tmpCell = tableRow.insertCell(
  20071. this.indexTable[rowIndex][j].cellIndex + 1
  20072. );
  20073. tmpCell.rowSpan = cellInfo.rowSpan;
  20074. this.setCellContent(tmpCell);
  20075. tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  20076. tmpCell.setAttribute("align", cell.getAttribute("align"));
  20077. tmpCell.setAttribute("width", backWidth);
  20078. if (cell.style.cssText) {
  20079. tmpCell.style.cssText = cell.style.cssText;
  20080. }
  20081. //处理th的情况
  20082. if (cell.tagName == "TH") {
  20083. var th = cell.ownerDocument.createElement("th");
  20084. th.appendChild(tmpCell.firstChild);
  20085. th.setAttribute("vAlign", cell.getAttribute("vAlign"));
  20086. th.rowSpan = tmpCell.rowSpan;
  20087. tableRow.insertBefore(th, tmpCell);
  20088. domUtils.remove(tmpCell);
  20089. }
  20090. results.push(tmpCell);
  20091. }
  20092. this.update();
  20093. return results;
  20094. },
  20095. isLastCell: function (cell, rowsNum, colsNum) {
  20096. rowsNum = rowsNum || this.rowsNum;
  20097. colsNum = colsNum || this.colsNum;
  20098. var cellInfo = this.getCellInfo(cell);
  20099. return (
  20100. cellInfo.rowIndex + cellInfo.rowSpan == rowsNum &&
  20101. cellInfo.colIndex + cellInfo.colSpan == colsNum
  20102. );
  20103. },
  20104. getLastCell: function (cells) {
  20105. cells = cells || this.table.getElementsByTagName("td");
  20106. var firstInfo = this.getCellInfo(cells[0]);
  20107. var me = this,
  20108. last = cells[0],
  20109. tr = last.parentNode,
  20110. cellsNum = 0,
  20111. cols = 0,
  20112. rows;
  20113. utils.each(cells, function (cell) {
  20114. if (cell.parentNode == tr) cols += cell.colSpan || 1;
  20115. cellsNum += cell.rowSpan * cell.colSpan || 1;
  20116. });
  20117. rows = cellsNum / cols;
  20118. utils.each(cells, function (cell) {
  20119. if (me.isLastCell(cell, rows, cols)) {
  20120. last = cell;
  20121. return false;
  20122. }
  20123. });
  20124. return last;
  20125. },
  20126. selectRow: function (rowIndex) {
  20127. var indexRow = this.indexTable[rowIndex],
  20128. start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
  20129. end = this.getCell(
  20130. indexRow[this.colsNum - 1].rowIndex,
  20131. indexRow[this.colsNum - 1].cellIndex
  20132. ),
  20133. range = this.getCellsRange(start, end);
  20134. this.setSelected(range);
  20135. },
  20136. selectTable: function () {
  20137. var tds = this.table.getElementsByTagName("td"),
  20138. range = this.getCellsRange(tds[0], tds[tds.length - 1]);
  20139. this.setSelected(range);
  20140. },
  20141. setBackground: function (cells, value) {
  20142. if (typeof value === "string") {
  20143. utils.each(cells, function (cell) {
  20144. cell.style.backgroundColor = value;
  20145. });
  20146. } else if (typeof value === "object") {
  20147. value = utils.extend(
  20148. {
  20149. repeat: true,
  20150. colorList: ["#ddd", "#fff"]
  20151. },
  20152. value
  20153. );
  20154. var rowIndex = this.getCellInfo(cells[0]).rowIndex,
  20155. count = 0,
  20156. colors = value.colorList,
  20157. getColor = function (list, index, repeat) {
  20158. return list[index]
  20159. ? list[index]
  20160. : repeat ? list[index % list.length] : "";
  20161. };
  20162. for (var i = 0, cell; (cell = cells[i++]);) {
  20163. var cellInfo = this.getCellInfo(cell);
  20164. cell.style.backgroundColor = getColor(
  20165. colors,
  20166. rowIndex + count == cellInfo.rowIndex ? count : ++count,
  20167. value.repeat
  20168. );
  20169. }
  20170. }
  20171. },
  20172. removeBackground: function (cells) {
  20173. utils.each(cells, function (cell) {
  20174. cell.style.backgroundColor = "";
  20175. });
  20176. }
  20177. };
  20178. function showError(e) {
  20179. }
  20180. })();
  20181. // plugins/table.cmds.js
  20182. /**
  20183. * Created with JetBrains PhpStorm.
  20184. * User: taoqili
  20185. * Date: 13-2-20
  20186. * Time: 下午6:25
  20187. * To change this template use File | Settings | File Templates.
  20188. */
  20189. ;(function () {
  20190. var UT = UE.UETable,
  20191. getTableItemsByRange = function (editor) {
  20192. return UT.getTableItemsByRange(editor);
  20193. },
  20194. getUETableBySelected = function (editor) {
  20195. return UT.getUETableBySelected(editor);
  20196. },
  20197. getDefaultValue = function (editor, table) {
  20198. return UT.getDefaultValue(editor, table);
  20199. },
  20200. getUETable = function (tdOrTable) {
  20201. return UT.getUETable(tdOrTable);
  20202. };
  20203. UE.commands["inserttable"] = {
  20204. queryCommandState: function () {
  20205. return getTableItemsByRange(this).table ? -1 : 0;
  20206. },
  20207. execCommand: function (cmd, opt) {
  20208. function createTable(opt, tdWidth) {
  20209. var html = [],
  20210. rowsNum = opt.numRows,
  20211. colsNum = opt.numCols;
  20212. for (var r = 0; r < rowsNum; r++) {
  20213. html.push("<tr" + (r == 0 ? ' class="firstRow"' : "") + ">");
  20214. for (var c = 0; c < colsNum; c++) {
  20215. html.push(
  20216. '<td style="border:1px solid windowtext;" width="' +
  20217. tdWidth +
  20218. '" vAlign="' +
  20219. opt.tdvalign +
  20220. '" >' +
  20221. (browser.ie && browser.version < 11
  20222. ? domUtils.fillChar
  20223. : "<br/>") +
  20224. "</td>"
  20225. );
  20226. }
  20227. html.push("</tr>");
  20228. }
  20229. //禁止指定table-width
  20230. return "<table style=\"border-collapse:collapse;\" ><tbody>" + html.join("") + "</tbody></table>";
  20231. }
  20232. if (!opt) {
  20233. opt = utils.extend(
  20234. {},
  20235. {
  20236. numCols: this.options.defaultCols,
  20237. numRows: this.options.defaultRows,
  20238. tdvalign: this.options.tdvalign
  20239. }
  20240. );
  20241. }
  20242. var me = this;
  20243. var range = this.selection.getRange(),
  20244. start = range.startContainer,
  20245. firstParentBlock =
  20246. domUtils.findParent(
  20247. start,
  20248. function (node) {
  20249. return domUtils.isBlockElm(node);
  20250. },
  20251. true
  20252. ) || me.body;
  20253. var defaultValue = getDefaultValue(me),
  20254. tableWidth = firstParentBlock.offsetWidth,
  20255. tdWidth = Math.floor(
  20256. tableWidth / opt.numCols -
  20257. defaultValue.tdPadding * 2 -
  20258. defaultValue.tdBorder
  20259. );
  20260. //todo其他属性
  20261. !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
  20262. me.execCommand("inserthtml", createTable(opt, tdWidth));
  20263. }
  20264. };
  20265. UE.commands["insertparagraphbeforetable"] = {
  20266. queryCommandState: function () {
  20267. return getTableItemsByRange(this).cell ? 0 : -1;
  20268. },
  20269. execCommand: function () {
  20270. var table = getTableItemsByRange(this).table;
  20271. if (table) {
  20272. var p = this.document.createElement("p");
  20273. p.innerHTML = browser.ie ? "&nbsp;" : "<br />";
  20274. table.parentNode.insertBefore(p, table);
  20275. this.selection.getRange().setStart(p, 0).setCursor();
  20276. }
  20277. }
  20278. };
  20279. UE.commands["deletetable"] = {
  20280. queryCommandState: function () {
  20281. var rng = this.selection.getRange();
  20282. return domUtils.findParentByTagName(rng.startContainer, "table", true)
  20283. ? 0
  20284. : -1;
  20285. },
  20286. execCommand: function (cmd, table) {
  20287. var rng = this.selection.getRange();
  20288. table =
  20289. table ||
  20290. domUtils.findParentByTagName(rng.startContainer, "table", true);
  20291. if (table) {
  20292. var next = table.nextSibling;
  20293. if (!next) {
  20294. next = domUtils.createElement(this.document, "p", {
  20295. innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
  20296. });
  20297. table.parentNode.insertBefore(next, table);
  20298. }
  20299. domUtils.remove(table);
  20300. rng = this.selection.getRange();
  20301. if (next.nodeType == 3) {
  20302. rng.setStartBefore(next);
  20303. } else {
  20304. rng.setStart(next, 0);
  20305. }
  20306. rng.setCursor(false, true);
  20307. this.fireEvent("tablehasdeleted");
  20308. }
  20309. }
  20310. };
  20311. UE.commands["cellalign"] = {
  20312. queryCommandState: function () {
  20313. return getSelectedArr(this).length ? 0 : -1;
  20314. },
  20315. execCommand: function (cmd, align) {
  20316. var selectedTds = getSelectedArr(this);
  20317. if (selectedTds.length) {
  20318. for (var i = 0, ci; (ci = selectedTds[i++]);) {
  20319. ci.setAttribute("align", align);
  20320. }
  20321. }
  20322. }
  20323. };
  20324. UE.commands["cellvalign"] = {
  20325. queryCommandState: function () {
  20326. return getSelectedArr(this).length ? 0 : -1;
  20327. },
  20328. execCommand: function (cmd, valign) {
  20329. var selectedTds = getSelectedArr(this);
  20330. if (selectedTds.length) {
  20331. for (var i = 0, ci; (ci = selectedTds[i++]);) {
  20332. ci.setAttribute("vAlign", valign);
  20333. }
  20334. }
  20335. }
  20336. };
  20337. UE.commands["insertcaption"] = {
  20338. queryCommandState: function () {
  20339. var table = getTableItemsByRange(this).table;
  20340. if (table) {
  20341. return table.getElementsByTagName("caption").length == 0 ? 1 : -1;
  20342. }
  20343. return -1;
  20344. },
  20345. execCommand: function () {
  20346. var table = getTableItemsByRange(this).table;
  20347. if (table) {
  20348. var caption = this.document.createElement("caption");
  20349. caption.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
  20350. table.insertBefore(caption, table.firstChild);
  20351. var range = this.selection.getRange();
  20352. range.setStart(caption, 0).setCursor();
  20353. }
  20354. }
  20355. };
  20356. UE.commands["deletecaption"] = {
  20357. queryCommandState: function () {
  20358. var rng = this.selection.getRange(),
  20359. table = domUtils.findParentByTagName(rng.startContainer, "table");
  20360. if (table) {
  20361. return table.getElementsByTagName("caption").length == 0 ? -1 : 1;
  20362. }
  20363. return -1;
  20364. },
  20365. execCommand: function () {
  20366. var rng = this.selection.getRange(),
  20367. table = domUtils.findParentByTagName(rng.startContainer, "table");
  20368. if (table) {
  20369. domUtils.remove(table.getElementsByTagName("caption")[0]);
  20370. var range = this.selection.getRange();
  20371. range.setStart(table.rows[0].cells[0], 0).setCursor();
  20372. }
  20373. }
  20374. };
  20375. UE.commands["inserttitle"] = {
  20376. queryCommandState: function () {
  20377. var table = getTableItemsByRange(this).table;
  20378. if (table) {
  20379. var firstRow = table.rows[0];
  20380. return firstRow.cells[
  20381. firstRow.cells.length - 1
  20382. ].tagName.toLowerCase() != "th"
  20383. ? 0
  20384. : -1;
  20385. }
  20386. return -1;
  20387. },
  20388. execCommand: function () {
  20389. var table = getTableItemsByRange(this).table;
  20390. if (table) {
  20391. getUETable(table).insertRow(0, "th");
  20392. }
  20393. var th = table.getElementsByTagName("th")[0];
  20394. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  20395. }
  20396. };
  20397. UE.commands["deletetitle"] = {
  20398. queryCommandState: function () {
  20399. var table = getTableItemsByRange(this).table;
  20400. if (table) {
  20401. var firstRow = table.rows[0];
  20402. return firstRow.cells[
  20403. firstRow.cells.length - 1
  20404. ].tagName.toLowerCase() == "th"
  20405. ? 0
  20406. : -1;
  20407. }
  20408. return -1;
  20409. },
  20410. execCommand: function () {
  20411. var table = getTableItemsByRange(this).table;
  20412. if (table) {
  20413. domUtils.remove(table.rows[0]);
  20414. }
  20415. var td = table.getElementsByTagName("td")[0];
  20416. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  20417. }
  20418. };
  20419. UE.commands["inserttitlecol"] = {
  20420. queryCommandState: function () {
  20421. var table = getTableItemsByRange(this).table;
  20422. if (table) {
  20423. var lastRow = table.rows[table.rows.length - 1];
  20424. return lastRow.getElementsByTagName("th").length ? -1 : 0;
  20425. }
  20426. return -1;
  20427. },
  20428. execCommand: function (cmd) {
  20429. var table = getTableItemsByRange(this).table;
  20430. if (table) {
  20431. getUETable(table).insertCol(0, "th");
  20432. }
  20433. resetTdWidth(table, this);
  20434. var th = table.getElementsByTagName("th")[0];
  20435. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  20436. }
  20437. };
  20438. UE.commands["deletetitlecol"] = {
  20439. queryCommandState: function () {
  20440. var table = getTableItemsByRange(this).table;
  20441. if (table) {
  20442. var lastRow = table.rows[table.rows.length - 1];
  20443. return lastRow.getElementsByTagName("th").length ? 0 : -1;
  20444. }
  20445. return -1;
  20446. },
  20447. execCommand: function () {
  20448. var table = getTableItemsByRange(this).table;
  20449. if (table) {
  20450. for (var i = 0; i < table.rows.length; i++) {
  20451. domUtils.remove(table.rows[i].children[0]);
  20452. }
  20453. }
  20454. resetTdWidth(table, this);
  20455. var td = table.getElementsByTagName("td")[0];
  20456. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  20457. }
  20458. };
  20459. UE.commands["mergeright"] = {
  20460. queryCommandState: function (cmd) {
  20461. var tableItems = getTableItemsByRange(this),
  20462. table = tableItems.table,
  20463. cell = tableItems.cell;
  20464. if (!table || !cell) return -1;
  20465. var ut = getUETable(table);
  20466. if (ut.selectedTds.length) return -1;
  20467. var cellInfo = ut.getCellInfo(cell),
  20468. rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
  20469. if (rightColIndex >= ut.colsNum) return -1; // 如果处于最右边则不能向右合并
  20470. var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
  20471. rightCell =
  20472. table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex];
  20473. if (!rightCell || cell.tagName != rightCell.tagName) return -1; // TH和TD不能相互合并
  20474. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  20475. return rightCellInfo.rowIndex == cellInfo.rowIndex &&
  20476. rightCellInfo.rowSpan == cellInfo.rowSpan
  20477. ? 0
  20478. : -1;
  20479. },
  20480. execCommand: function (cmd) {
  20481. var rng = this.selection.getRange(),
  20482. bk = rng.createBookmark(true);
  20483. var cell = getTableItemsByRange(this).cell,
  20484. ut = getUETable(cell);
  20485. ut.mergeRight(cell);
  20486. rng.moveToBookmark(bk).select();
  20487. }
  20488. };
  20489. UE.commands["mergedown"] = {
  20490. queryCommandState: function (cmd) {
  20491. var tableItems = getTableItemsByRange(this),
  20492. table = tableItems.table,
  20493. cell = tableItems.cell;
  20494. if (!table || !cell) return -1;
  20495. var ut = getUETable(table);
  20496. if (ut.selectedTds.length) return -1;
  20497. var cellInfo = ut.getCellInfo(cell),
  20498. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
  20499. if (downRowIndex >= ut.rowsNum) return -1; // 如果处于最下边则不能向下合并
  20500. var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
  20501. downCell =
  20502. table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex];
  20503. if (!downCell || cell.tagName != downCell.tagName) return -1; // TH和TD不能相互合并
  20504. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  20505. return downCellInfo.colIndex == cellInfo.colIndex &&
  20506. downCellInfo.colSpan == cellInfo.colSpan
  20507. ? 0
  20508. : -1;
  20509. },
  20510. execCommand: function () {
  20511. var rng = this.selection.getRange(),
  20512. bk = rng.createBookmark(true);
  20513. var cell = getTableItemsByRange(this).cell,
  20514. ut = getUETable(cell);
  20515. ut.mergeDown(cell);
  20516. rng.moveToBookmark(bk).select();
  20517. }
  20518. };
  20519. UE.commands["mergecells"] = {
  20520. queryCommandState: function () {
  20521. return getUETableBySelected(this) ? 0 : -1;
  20522. },
  20523. execCommand: function () {
  20524. var ut = getUETableBySelected(this);
  20525. if (ut && ut.selectedTds.length) {
  20526. var cell = ut.selectedTds[0];
  20527. ut.mergeRange();
  20528. var rng = this.selection.getRange();
  20529. if (domUtils.isEmptyBlock(cell)) {
  20530. rng.setStart(cell, 0).collapse(true);
  20531. } else {
  20532. rng.selectNodeContents(cell);
  20533. }
  20534. rng.select();
  20535. }
  20536. }
  20537. };
  20538. UE.commands["insertrow"] = {
  20539. queryCommandState: function () {
  20540. var tableItems = getTableItemsByRange(this),
  20541. cell = tableItems.cell;
  20542. return cell &&
  20543. (cell.tagName == "TD" ||
  20544. (cell.tagName == "TH" &&
  20545. tableItems.tr !== tableItems.table.rows[0])) &&
  20546. getUETable(tableItems.table).rowsNum < this.options.maxRowNum
  20547. ? 0
  20548. : -1;
  20549. },
  20550. execCommand: function () {
  20551. var rng = this.selection.getRange(),
  20552. bk = rng.createBookmark(true);
  20553. var tableItems = getTableItemsByRange(this),
  20554. cell = tableItems.cell,
  20555. table = tableItems.table,
  20556. ut = getUETable(table),
  20557. cellInfo = ut.getCellInfo(cell);
  20558. //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
  20559. if (!ut.selectedTds.length) {
  20560. ut.insertRow(cellInfo.rowIndex, cell);
  20561. } else {
  20562. var range = ut.cellsRange;
  20563. for (
  20564. var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
  20565. i < len;
  20566. i++
  20567. ) {
  20568. ut.insertRow(range.beginRowIndex, cell);
  20569. }
  20570. }
  20571. rng.moveToBookmark(bk).select();
  20572. if (table.getAttribute("interlaced") === "enabled")
  20573. this.fireEvent("interlacetable", table);
  20574. }
  20575. };
  20576. //后插入行
  20577. UE.commands["insertrownext"] = {
  20578. queryCommandState: function () {
  20579. var tableItems = getTableItemsByRange(this),
  20580. cell = tableItems.cell;
  20581. return cell &&
  20582. cell.tagName == "TD" &&
  20583. getUETable(tableItems.table).rowsNum < this.options.maxRowNum
  20584. ? 0
  20585. : -1;
  20586. },
  20587. execCommand: function () {
  20588. var rng = this.selection.getRange(),
  20589. bk = rng.createBookmark(true);
  20590. var tableItems = getTableItemsByRange(this),
  20591. cell = tableItems.cell,
  20592. table = tableItems.table,
  20593. ut = getUETable(table),
  20594. cellInfo = ut.getCellInfo(cell);
  20595. //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
  20596. if (!ut.selectedTds.length) {
  20597. ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell);
  20598. } else {
  20599. var range = ut.cellsRange;
  20600. for (
  20601. var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
  20602. i < len;
  20603. i++
  20604. ) {
  20605. ut.insertRow(range.endRowIndex + 1, cell);
  20606. }
  20607. }
  20608. rng.moveToBookmark(bk).select();
  20609. if (table.getAttribute("interlaced") === "enabled")
  20610. this.fireEvent("interlacetable", table);
  20611. }
  20612. };
  20613. UE.commands["deleterow"] = {
  20614. queryCommandState: function () {
  20615. var tableItems = getTableItemsByRange(this);
  20616. return tableItems.cell ? 0 : -1;
  20617. },
  20618. execCommand: function () {
  20619. var cell = getTableItemsByRange(this).cell,
  20620. ut = getUETable(cell),
  20621. cellsRange = ut.cellsRange,
  20622. cellInfo = ut.getCellInfo(cell),
  20623. preCell = ut.getVSideCell(cell),
  20624. nextCell = ut.getVSideCell(cell, true),
  20625. rng = this.selection.getRange();
  20626. if (utils.isEmptyObject(cellsRange)) {
  20627. ut.deleteRow(cellInfo.rowIndex);
  20628. } else {
  20629. for (
  20630. var i = cellsRange.beginRowIndex;
  20631. i < cellsRange.endRowIndex + 1;
  20632. i++
  20633. ) {
  20634. ut.deleteRow(cellsRange.beginRowIndex);
  20635. }
  20636. }
  20637. var table = ut.table;
  20638. if (!table.getElementsByTagName("td").length) {
  20639. var nextSibling = table.nextSibling;
  20640. domUtils.remove(table);
  20641. if (nextSibling) {
  20642. rng.setStart(nextSibling, 0).setCursor(false, true);
  20643. }
  20644. } else {
  20645. if (
  20646. cellInfo.rowSpan == 1 ||
  20647. cellInfo.rowSpan ==
  20648. cellsRange.endRowIndex - cellsRange.beginRowIndex + 1
  20649. ) {
  20650. if (nextCell || preCell)
  20651. rng.selectNodeContents(nextCell || preCell).setCursor(false, true);
  20652. } else {
  20653. var newCell = ut.getCell(
  20654. cellInfo.rowIndex,
  20655. ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex
  20656. );
  20657. if (newCell) rng.selectNodeContents(newCell).setCursor(false, true);
  20658. }
  20659. }
  20660. if (table.getAttribute("interlaced") === "enabled")
  20661. this.fireEvent("interlacetable", table);
  20662. }
  20663. };
  20664. UE.commands["insertcol"] = {
  20665. queryCommandState: function (cmd) {
  20666. var tableItems = getTableItemsByRange(this),
  20667. cell = tableItems.cell;
  20668. return cell &&
  20669. (cell.tagName == "TD" ||
  20670. (cell.tagName == "TH" && cell !== tableItems.tr.cells[0])) &&
  20671. getUETable(tableItems.table).colsNum < this.options.maxColNum
  20672. ? 0
  20673. : -1;
  20674. },
  20675. execCommand: function (cmd) {
  20676. var rng = this.selection.getRange(),
  20677. bk = rng.createBookmark(true);
  20678. if (this.queryCommandState(cmd) == -1) return;
  20679. var cell = getTableItemsByRange(this).cell,
  20680. ut = getUETable(cell),
  20681. cellInfo = ut.getCellInfo(cell);
  20682. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
  20683. if (!ut.selectedTds.length) {
  20684. ut.insertCol(cellInfo.colIndex, cell);
  20685. } else {
  20686. var range = ut.cellsRange;
  20687. for (
  20688. var i = 0, len = range.endColIndex - range.beginColIndex + 1;
  20689. i < len;
  20690. i++
  20691. ) {
  20692. ut.insertCol(range.beginColIndex, cell);
  20693. }
  20694. }
  20695. rng.moveToBookmark(bk).select(true);
  20696. }
  20697. };
  20698. UE.commands["insertcolnext"] = {
  20699. queryCommandState: function () {
  20700. var tableItems = getTableItemsByRange(this),
  20701. cell = tableItems.cell;
  20702. return cell &&
  20703. getUETable(tableItems.table).colsNum < this.options.maxColNum
  20704. ? 0
  20705. : -1;
  20706. },
  20707. execCommand: function () {
  20708. var rng = this.selection.getRange(),
  20709. bk = rng.createBookmark(true);
  20710. var cell = getTableItemsByRange(this).cell,
  20711. ut = getUETable(cell),
  20712. cellInfo = ut.getCellInfo(cell);
  20713. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
  20714. if (!ut.selectedTds.length) {
  20715. ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell);
  20716. } else {
  20717. var range = ut.cellsRange;
  20718. for (
  20719. var i = 0, len = range.endColIndex - range.beginColIndex + 1;
  20720. i < len;
  20721. i++
  20722. ) {
  20723. ut.insertCol(range.endColIndex + 1, cell);
  20724. }
  20725. }
  20726. rng.moveToBookmark(bk).select();
  20727. }
  20728. };
  20729. UE.commands["deletecol"] = {
  20730. queryCommandState: function () {
  20731. var tableItems = getTableItemsByRange(this);
  20732. return tableItems.cell ? 0 : -1;
  20733. },
  20734. execCommand: function () {
  20735. var cell = getTableItemsByRange(this).cell,
  20736. ut = getUETable(cell),
  20737. range = ut.cellsRange,
  20738. cellInfo = ut.getCellInfo(cell),
  20739. preCell = ut.getHSideCell(cell),
  20740. nextCell = ut.getHSideCell(cell, true);
  20741. if (utils.isEmptyObject(range)) {
  20742. ut.deleteCol(cellInfo.colIndex);
  20743. } else {
  20744. for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
  20745. ut.deleteCol(range.beginColIndex);
  20746. }
  20747. }
  20748. var table = ut.table,
  20749. rng = this.selection.getRange();
  20750. if (!table.getElementsByTagName("td").length) {
  20751. var nextSibling = table.nextSibling;
  20752. domUtils.remove(table);
  20753. if (nextSibling) {
  20754. rng.setStart(nextSibling, 0).setCursor(false, true);
  20755. }
  20756. } else {
  20757. if (domUtils.inDoc(cell, this.document)) {
  20758. rng.setStart(cell, 0).setCursor(false, true);
  20759. } else {
  20760. if (nextCell && domUtils.inDoc(nextCell, this.document)) {
  20761. rng.selectNodeContents(nextCell).setCursor(false, true);
  20762. } else {
  20763. if (preCell && domUtils.inDoc(preCell, this.document)) {
  20764. rng.selectNodeContents(preCell).setCursor(true, true);
  20765. }
  20766. }
  20767. }
  20768. }
  20769. }
  20770. };
  20771. UE.commands["splittocells"] = {
  20772. queryCommandState: function () {
  20773. var tableItems = getTableItemsByRange(this),
  20774. cell = tableItems.cell;
  20775. if (!cell) return -1;
  20776. var ut = getUETable(tableItems.table);
  20777. if (ut.selectedTds.length > 0) return -1;
  20778. return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1;
  20779. },
  20780. execCommand: function () {
  20781. var rng = this.selection.getRange(),
  20782. bk = rng.createBookmark(true);
  20783. var cell = getTableItemsByRange(this).cell,
  20784. ut = getUETable(cell);
  20785. ut.splitToCells(cell);
  20786. rng.moveToBookmark(bk).select();
  20787. }
  20788. };
  20789. UE.commands["splittorows"] = {
  20790. queryCommandState: function () {
  20791. var tableItems = getTableItemsByRange(this),
  20792. cell = tableItems.cell;
  20793. if (!cell) return -1;
  20794. var ut = getUETable(tableItems.table);
  20795. if (ut.selectedTds.length > 0) return -1;
  20796. return cell && cell.rowSpan > 1 ? 0 : -1;
  20797. },
  20798. execCommand: function () {
  20799. var rng = this.selection.getRange(),
  20800. bk = rng.createBookmark(true);
  20801. var cell = getTableItemsByRange(this).cell,
  20802. ut = getUETable(cell);
  20803. ut.splitToRows(cell);
  20804. rng.moveToBookmark(bk).select();
  20805. }
  20806. };
  20807. UE.commands["splittocols"] = {
  20808. queryCommandState: function () {
  20809. var tableItems = getTableItemsByRange(this),
  20810. cell = tableItems.cell;
  20811. if (!cell) return -1;
  20812. var ut = getUETable(tableItems.table);
  20813. if (ut.selectedTds.length > 0) return -1;
  20814. return cell && cell.colSpan > 1 ? 0 : -1;
  20815. },
  20816. execCommand: function () {
  20817. var rng = this.selection.getRange(),
  20818. bk = rng.createBookmark(true);
  20819. var cell = getTableItemsByRange(this).cell,
  20820. ut = getUETable(cell);
  20821. ut.splitToCols(cell);
  20822. rng.moveToBookmark(bk).select();
  20823. }
  20824. };
  20825. UE.commands["adaptbytext"] = UE.commands["adaptbywindow"] = {
  20826. queryCommandState: function () {
  20827. return getTableItemsByRange(this).table ? 0 : -1;
  20828. },
  20829. execCommand: function (cmd) {
  20830. var tableItems = getTableItemsByRange(this),
  20831. table = tableItems.table;
  20832. if (table) {
  20833. if (cmd == "adaptbywindow") {
  20834. resetTdWidth(table, this);
  20835. } else {
  20836. var cells = domUtils.getElementsByTagName(table, "td th");
  20837. utils.each(cells, function (cell) {
  20838. cell.removeAttribute("width");
  20839. });
  20840. table.removeAttribute("width");
  20841. }
  20842. }
  20843. }
  20844. };
  20845. //平均分配各列
  20846. UE.commands["averagedistributecol"] = {
  20847. queryCommandState: function () {
  20848. var ut = getUETableBySelected(this);
  20849. if (!ut) return -1;
  20850. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  20851. },
  20852. execCommand: function (cmd) {
  20853. var me = this,
  20854. ut = getUETableBySelected(me);
  20855. function getAverageWidth() {
  20856. var tb = ut.table,
  20857. averageWidth,
  20858. sumWidth = 0,
  20859. colsNum = 0,
  20860. tbAttr = getDefaultValue(me, tb);
  20861. if (ut.isFullRow()) {
  20862. sumWidth = tb.offsetWidth;
  20863. colsNum = ut.colsNum;
  20864. } else {
  20865. var begin = ut.cellsRange.beginColIndex,
  20866. end = ut.cellsRange.endColIndex,
  20867. node;
  20868. for (var i = begin; i <= end;) {
  20869. node = ut.selectedTds[i];
  20870. sumWidth += node.offsetWidth;
  20871. i += node.colSpan;
  20872. colsNum += 1;
  20873. }
  20874. }
  20875. averageWidth =
  20876. Math.ceil(sumWidth / colsNum) -
  20877. tbAttr.tdBorder * 2 -
  20878. tbAttr.tdPadding * 2;
  20879. return averageWidth;
  20880. }
  20881. function setAverageWidth(averageWidth) {
  20882. utils.each(domUtils.getElementsByTagName(ut.table, "th"), function (
  20883. node
  20884. ) {
  20885. node.setAttribute("width", "");
  20886. });
  20887. var cells = ut.isFullRow()
  20888. ? domUtils.getElementsByTagName(ut.table, "td")
  20889. : ut.selectedTds;
  20890. utils.each(cells, function (node) {
  20891. if (node.colSpan == 1) {
  20892. node.setAttribute("width", averageWidth);
  20893. }
  20894. });
  20895. }
  20896. if (ut && ut.selectedTds.length) {
  20897. setAverageWidth(getAverageWidth());
  20898. }
  20899. }
  20900. };
  20901. //平均分配各行
  20902. UE.commands["averagedistributerow"] = {
  20903. queryCommandState: function () {
  20904. var ut = getUETableBySelected(this);
  20905. if (!ut) return -1;
  20906. if (ut.selectedTds && /th/gi.test(ut.selectedTds[0].tagName)) return -1;
  20907. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  20908. },
  20909. execCommand: function (cmd) {
  20910. var me = this,
  20911. ut = getUETableBySelected(me);
  20912. function getAverageHeight() {
  20913. var averageHeight,
  20914. rowNum,
  20915. sumHeight = 0,
  20916. tb = ut.table,
  20917. tbAttr = getDefaultValue(me, tb),
  20918. tdpadding = parseInt(
  20919. domUtils.getComputedStyle(
  20920. tb.getElementsByTagName("td")[0],
  20921. "padding-top"
  20922. )
  20923. );
  20924. if (ut.isFullCol()) {
  20925. var captionArr = domUtils.getElementsByTagName(tb, "caption"),
  20926. thArr = domUtils.getElementsByTagName(tb, "th"),
  20927. captionHeight,
  20928. thHeight;
  20929. if (captionArr.length > 0) {
  20930. captionHeight = captionArr[0].offsetHeight;
  20931. }
  20932. if (thArr.length > 0) {
  20933. thHeight = thArr[0].offsetHeight;
  20934. }
  20935. sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0);
  20936. rowNum = thArr.length == 0 ? ut.rowsNum : ut.rowsNum - 1;
  20937. } else {
  20938. var begin = ut.cellsRange.beginRowIndex,
  20939. end = ut.cellsRange.endRowIndex,
  20940. count = 0,
  20941. trs = domUtils.getElementsByTagName(tb, "tr");
  20942. for (var i = begin; i <= end; i++) {
  20943. sumHeight += trs[i].offsetHeight;
  20944. count += 1;
  20945. }
  20946. rowNum = count;
  20947. }
  20948. //ie8下是混杂模式
  20949. if (browser.ie && browser.version < 9) {
  20950. averageHeight = Math.ceil(sumHeight / rowNum);
  20951. } else {
  20952. averageHeight =
  20953. Math.ceil(sumHeight / rowNum) - tbAttr.tdBorder * 2 - tdpadding * 2;
  20954. }
  20955. return averageHeight;
  20956. }
  20957. function setAverageHeight(averageHeight) {
  20958. var cells = ut.isFullCol()
  20959. ? domUtils.getElementsByTagName(ut.table, "td")
  20960. : ut.selectedTds;
  20961. utils.each(cells, function (node) {
  20962. if (node.rowSpan == 1) {
  20963. node.setAttribute("height", averageHeight);
  20964. }
  20965. });
  20966. }
  20967. if (ut && ut.selectedTds.length) {
  20968. setAverageHeight(getAverageHeight());
  20969. }
  20970. }
  20971. };
  20972. //单元格对齐方式
  20973. UE.commands["cellalignment"] = {
  20974. queryCommandState: function () {
  20975. return getTableItemsByRange(this).table ? 0 : -1;
  20976. },
  20977. execCommand: function (cmd, data) {
  20978. var me = this,
  20979. ut = getUETableBySelected(me);
  20980. if (!ut) {
  20981. var start = me.selection.getStart(),
  20982. cell =
  20983. start &&
  20984. domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  20985. if (!/caption/gi.test(cell.tagName)) {
  20986. domUtils.setAttributes(cell, data);
  20987. } else {
  20988. cell.style.textAlign = data.align;
  20989. cell.style.verticalAlign = data.vAlign;
  20990. }
  20991. me.selection.getRange().setCursor(true);
  20992. } else {
  20993. utils.each(ut.selectedTds, function (cell) {
  20994. domUtils.setAttributes(cell, data);
  20995. });
  20996. }
  20997. },
  20998. /**
  20999. * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
  21000. * @see UE.UETable.getTableCellAlignState
  21001. */
  21002. queryCommandValue: function (cmd) {
  21003. var activeMenuCell = getTableItemsByRange(this).cell;
  21004. if (!activeMenuCell) {
  21005. activeMenuCell = getSelectedArr(this)[0];
  21006. }
  21007. if (!activeMenuCell) {
  21008. return null;
  21009. } else {
  21010. //获取同时选中的其他单元格
  21011. var cells = UE.UETable.getUETable(activeMenuCell).selectedTds;
  21012. !cells.length && (cells = activeMenuCell);
  21013. return UE.UETable.getTableCellAlignState(cells);
  21014. }
  21015. }
  21016. };
  21017. //表格对齐方式
  21018. UE.commands["tablealignment"] = {
  21019. queryCommandState: function () {
  21020. if (browser.ie && browser.version < 8) {
  21021. return -1;
  21022. }
  21023. return getTableItemsByRange(this).table ? 0 : -1;
  21024. },
  21025. execCommand: function (cmd, value) {
  21026. var me = this,
  21027. start = me.selection.getStart(),
  21028. table = start && domUtils.findParentByTagName(start, ["table"], true);
  21029. if (table) {
  21030. table.setAttribute("align", value);
  21031. }
  21032. }
  21033. };
  21034. //表格属性
  21035. UE.commands["edittable"] = {
  21036. queryCommandState: function () {
  21037. return getTableItemsByRange(this).table ? 0 : -1;
  21038. },
  21039. execCommand: function (cmd, color) {
  21040. var rng = this.selection.getRange(),
  21041. table = domUtils.findParentByTagName(rng.startContainer, "table");
  21042. if (table) {
  21043. var arr = domUtils
  21044. .getElementsByTagName(table, "td")
  21045. .concat(
  21046. domUtils.getElementsByTagName(table, "th"),
  21047. domUtils.getElementsByTagName(table, "caption")
  21048. );
  21049. utils.each(arr, function (node) {
  21050. node.style.borderColor = color;
  21051. });
  21052. }
  21053. }
  21054. };
  21055. //单元格属性
  21056. UE.commands["edittd"] = {
  21057. queryCommandState: function () {
  21058. return getTableItemsByRange(this).table ? 0 : -1;
  21059. },
  21060. execCommand: function (cmd, bkColor) {
  21061. var me = this,
  21062. ut = getUETableBySelected(me);
  21063. if (!ut) {
  21064. var start = me.selection.getStart(),
  21065. cell =
  21066. start &&
  21067. domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  21068. if (cell) {
  21069. cell.style.backgroundColor = bkColor;
  21070. }
  21071. } else {
  21072. utils.each(ut.selectedTds, function (cell) {
  21073. cell.style.backgroundColor = bkColor;
  21074. });
  21075. }
  21076. }
  21077. };
  21078. UE.commands["settablebackground"] = {
  21079. queryCommandState: function () {
  21080. return getSelectedArr(this).length > 1 ? 0 : -1;
  21081. },
  21082. execCommand: function (cmd, value) {
  21083. var cells, ut;
  21084. cells = getSelectedArr(this);
  21085. ut = getUETable(cells[0]);
  21086. ut.setBackground(cells, value);
  21087. }
  21088. };
  21089. UE.commands["cleartablebackground"] = {
  21090. queryCommandState: function () {
  21091. var cells = getSelectedArr(this);
  21092. if (!cells.length) return -1;
  21093. for (var i = 0, cell; (cell = cells[i++]);) {
  21094. if (cell.style.backgroundColor !== "") return 0;
  21095. }
  21096. return -1;
  21097. },
  21098. execCommand: function () {
  21099. var cells = getSelectedArr(this),
  21100. ut = getUETable(cells[0]);
  21101. ut.removeBackground(cells);
  21102. }
  21103. };
  21104. UE.commands["interlacetable"] = UE.commands["uninterlacetable"] = {
  21105. queryCommandState: function (cmd) {
  21106. var table = getTableItemsByRange(this).table;
  21107. if (!table) return -1;
  21108. var interlaced = table.getAttribute("interlaced");
  21109. if (cmd == "interlacetable") {
  21110. //TODO 待定
  21111. //是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
  21112. return interlaced === "enabled" ? -1 : 0;
  21113. } else {
  21114. return !interlaced || interlaced === "disabled" ? -1 : 0;
  21115. }
  21116. },
  21117. execCommand: function (cmd, classList) {
  21118. var table = getTableItemsByRange(this).table;
  21119. if (cmd == "interlacetable") {
  21120. table.setAttribute("interlaced", "enabled");
  21121. this.fireEvent("interlacetable", table, classList);
  21122. } else {
  21123. table.setAttribute("interlaced", "disabled");
  21124. this.fireEvent("uninterlacetable", table);
  21125. }
  21126. }
  21127. };
  21128. UE.commands["setbordervisible"] = {
  21129. queryCommandState: function (cmd) {
  21130. var table = getTableItemsByRange(this).table;
  21131. if (!table) return -1;
  21132. return 0;
  21133. },
  21134. execCommand: function () {
  21135. var table = getTableItemsByRange(this).table;
  21136. utils.each(domUtils.getElementsByTagName(table, "td"), function (td) {
  21137. td.style.borderWidth = "1px";
  21138. td.style.borderStyle = "solid";
  21139. td.style.borderColor = 'windowtext';
  21140. });
  21141. utils.each(domUtils.getElementsByTagName(table, "th"), function (th) {
  21142. th.style.borderWidth = "1px";
  21143. th.style.borderStyle = "solid";
  21144. th.style.borderColor = 'windowtext';
  21145. });
  21146. }
  21147. };
  21148. function resetTdWidth(table, editor) {
  21149. var tds = domUtils.getElementsByTagName(table, "td th");
  21150. utils.each(tds, function (td) {
  21151. td.removeAttribute("width");
  21152. });
  21153. table.setAttribute(
  21154. "width",
  21155. getTableWidth(editor, true, getDefaultValue(editor, table))
  21156. );
  21157. var tdsWidths = [];
  21158. setTimeout(function () {
  21159. utils.each(tds, function (td) {
  21160. td.colSpan == 1 && tdsWidths.push(td.offsetWidth);
  21161. });
  21162. utils.each(tds, function (td, i) {
  21163. td.colSpan == 1 && td.setAttribute("width", tdsWidths[i] + "");
  21164. });
  21165. }, 0);
  21166. }
  21167. function getTableWidth(editor, needIEHack, defaultValue) {
  21168. var body = editor.body;
  21169. return (
  21170. body.offsetWidth -
  21171. (needIEHack
  21172. ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
  21173. : 0) -
  21174. defaultValue.tableBorder * 2 -
  21175. (editor.options.offsetWidth || 0)
  21176. );
  21177. }
  21178. function getSelectedArr(editor) {
  21179. var cell = getTableItemsByRange(editor).cell;
  21180. if (cell) {
  21181. var ut = getUETable(cell);
  21182. return ut.selectedTds.length ? ut.selectedTds : [cell];
  21183. } else {
  21184. return [];
  21185. }
  21186. }
  21187. })();
  21188. // plugins/table.action.js
  21189. /**
  21190. * Created with JetBrains PhpStorm.
  21191. * User: taoqili
  21192. * Date: 12-10-12
  21193. * Time: 上午10:05
  21194. * To change this template use File | Settings | File Templates.
  21195. */
  21196. UE.plugins["table"] = function () {
  21197. var me = this,
  21198. tabTimer = null,
  21199. //拖动计时器
  21200. tableDragTimer = null,
  21201. //双击计时器
  21202. tableResizeTimer = null,
  21203. //单元格最小宽度
  21204. cellMinWidth = 5,
  21205. isInResizeBuffer = false,
  21206. //单元格边框大小
  21207. cellBorderWidth = 5,
  21208. //鼠标偏移距离
  21209. offsetOfTableCell = 10,
  21210. //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
  21211. singleClickState = 0,
  21212. userActionStatus = null,
  21213. //双击允许的时间范围
  21214. dblclickTime = 360,
  21215. UT = UE.UETable,
  21216. getUETable = function (tdOrTable) {
  21217. return UT.getUETable(tdOrTable);
  21218. },
  21219. getUETableBySelected = function (editor) {
  21220. return UT.getUETableBySelected(editor);
  21221. },
  21222. getDefaultValue = function (editor, table) {
  21223. return UT.getDefaultValue(editor, table);
  21224. },
  21225. removeSelectedClass = function (cells) {
  21226. return UT.removeSelectedClass(cells);
  21227. };
  21228. function showError(e) {
  21229. // throw e;
  21230. }
  21231. me.ready(function () {
  21232. var me = this;
  21233. var orgGetText = me.selection.getText;
  21234. me.selection.getText = function () {
  21235. var table = getUETableBySelected(me);
  21236. if (table) {
  21237. var str = "";
  21238. utils.each(table.selectedTds, function (td) {
  21239. str += td[browser.ie ? "innerText" : "textContent"];
  21240. });
  21241. return str;
  21242. } else {
  21243. return orgGetText.call(me.selection);
  21244. }
  21245. };
  21246. });
  21247. //处理拖动及框选相关方法
  21248. var startTd = null, //鼠标按下时的锚点td
  21249. currentTd = null, //当前鼠标经过时的td
  21250. onDrag = "", //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
  21251. onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
  21252. dragButton = null,
  21253. dragOver = false,
  21254. dragLine = null, //模拟的拖动线
  21255. dragTd = null; //发生拖动的目标td
  21256. var mousedown = false,
  21257. //todo 判断混乱模式
  21258. needIEHack = true;
  21259. me.setOpt({
  21260. maxColNum: 20,
  21261. maxRowNum: 100,
  21262. defaultCols: 5,
  21263. defaultRows: 5,
  21264. tdvalign: "top",
  21265. cursorpath: me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
  21266. tableDragable: false,
  21267. classList: [
  21268. "ue-table-interlace-color-single",
  21269. "ue-table-interlace-color-double"
  21270. ]
  21271. });
  21272. me.getUETable = getUETable;
  21273. var commands = {
  21274. deletetable: 1,
  21275. inserttable: 1,
  21276. cellvalign: 1,
  21277. insertcaption: 1,
  21278. deletecaption: 1,
  21279. inserttitle: 1,
  21280. deletetitle: 1,
  21281. mergeright: 1,
  21282. mergedown: 1,
  21283. mergecells: 1,
  21284. insertrow: 1,
  21285. insertrownext: 1,
  21286. deleterow: 1,
  21287. insertcol: 1,
  21288. insertcolnext: 1,
  21289. deletecol: 1,
  21290. splittocells: 1,
  21291. splittorows: 1,
  21292. splittocols: 1,
  21293. adaptbytext: 1,
  21294. adaptbywindow: 1,
  21295. adaptbycustomer: 1,
  21296. insertparagraph: 1,
  21297. insertparagraphbeforetable: 1,
  21298. averagedistributecol: 1,
  21299. averagedistributerow: 1
  21300. };
  21301. me.ready(function () {
  21302. utils.cssRule(
  21303. "table",
  21304. //选中的td上的样式
  21305. ".selectTdClass{background-color:#edf5fa !important}" +
  21306. "table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}" +
  21307. //插入的表格的默认样式
  21308. "table{margin-bottom:10px;border-collapse:collapse;display:table;}" +
  21309. "td,th{padding: 5px 10px;border: 1px dashed #DDD;}" +
  21310. "caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}" +
  21311. "th{border-top:1px dashed #BBB;background-color:#F7F7F7;}" +
  21312. "table tr.firstRow th{border-top-width:2px;}" +
  21313. ".ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }" +
  21314. "td p{margin:0;padding:0;}",
  21315. me.document
  21316. );
  21317. var tableCopyList, isFullCol, isFullRow;
  21318. //注册del/backspace事件
  21319. me.addListener("keydown", function (cmd, evt) {
  21320. var me = this;
  21321. var keyCode = evt.keyCode || evt.which;
  21322. if (keyCode == 8) {
  21323. var ut = getUETableBySelected(me);
  21324. if (ut && ut.selectedTds.length) {
  21325. if (ut.isFullCol()) {
  21326. me.execCommand("deletecol");
  21327. } else if (ut.isFullRow()) {
  21328. me.execCommand("deleterow");
  21329. } else {
  21330. me.fireEvent("delcells");
  21331. }
  21332. domUtils.preventDefault(evt);
  21333. }
  21334. var caption = domUtils.findParentByTagName(
  21335. me.selection.getStart(),
  21336. "caption",
  21337. true
  21338. ),
  21339. range = me.selection.getRange();
  21340. if (range.collapsed && caption && isEmptyBlock(caption)) {
  21341. me.fireEvent("saveScene");
  21342. var table = caption.parentNode;
  21343. domUtils.remove(caption);
  21344. if (table) {
  21345. range.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  21346. }
  21347. me.fireEvent("saveScene");
  21348. }
  21349. }
  21350. if (keyCode == 46) {
  21351. ut = getUETableBySelected(me);
  21352. if (ut) {
  21353. me.fireEvent("saveScene");
  21354. for (var i = 0, ci; (ci = ut.selectedTds[i++]);) {
  21355. domUtils.fillNode(me.document, ci);
  21356. }
  21357. me.fireEvent("saveScene");
  21358. domUtils.preventDefault(evt);
  21359. }
  21360. }
  21361. if (keyCode == 13) {
  21362. var rng = me.selection.getRange(),
  21363. caption = domUtils.findParentByTagName(
  21364. rng.startContainer,
  21365. "caption",
  21366. true
  21367. );
  21368. if (caption) {
  21369. var table = domUtils.findParentByTagName(caption, "table");
  21370. if (!rng.collapsed) {
  21371. rng.deleteContents();
  21372. me.fireEvent("saveScene");
  21373. } else {
  21374. if (caption) {
  21375. rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  21376. }
  21377. }
  21378. domUtils.preventDefault(evt);
  21379. return;
  21380. }
  21381. if (rng.collapsed) {
  21382. var table = domUtils.findParentByTagName(rng.startContainer, "table");
  21383. if (table) {
  21384. var cell = table.rows[0].cells[0],
  21385. start = domUtils.findParentByTagName(
  21386. me.selection.getStart(),
  21387. ["td", "th"],
  21388. true
  21389. ),
  21390. preNode = table.previousSibling;
  21391. if (
  21392. cell === start &&
  21393. (!preNode ||
  21394. (preNode.nodeType == 1 && preNode.tagName == "TABLE")) &&
  21395. domUtils.isStartInblock(rng)
  21396. ) {
  21397. var first = domUtils.findParent(
  21398. me.selection.getStart(),
  21399. function (n) {
  21400. return domUtils.isBlockElm(n);
  21401. },
  21402. true
  21403. );
  21404. if (
  21405. first &&
  21406. (/t(h|d)/i.test(first.tagName) || first === start.firstChild)
  21407. ) {
  21408. me.execCommand("insertparagraphbeforetable");
  21409. domUtils.preventDefault(evt);
  21410. }
  21411. }
  21412. }
  21413. }
  21414. }
  21415. if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == "67") {
  21416. tableCopyList = null;
  21417. var ut = getUETableBySelected(me);
  21418. if (ut) {
  21419. var tds = ut.selectedTds;
  21420. isFullCol = ut.isFullCol();
  21421. isFullRow = ut.isFullRow();
  21422. tableCopyList = [[ut.cloneCell(tds[0], null, true)]];
  21423. for (var i = 1, ci; (ci = tds[i]); i++) {
  21424. if (ci.parentNode !== tds[i - 1].parentNode) {
  21425. tableCopyList.push([ut.cloneCell(ci, null, true)]);
  21426. } else {
  21427. tableCopyList[tableCopyList.length - 1].push(
  21428. ut.cloneCell(ci, null, true)
  21429. );
  21430. }
  21431. }
  21432. }
  21433. }
  21434. });
  21435. me.addListener("tablehasdeleted", function () {
  21436. toggleDraggableState(this, false, "", null);
  21437. if (dragButton) domUtils.remove(dragButton);
  21438. });
  21439. me.addListener("beforepaste", function (cmd, html) {
  21440. var me = this;
  21441. var rng = me.selection.getRange();
  21442. if (domUtils.findParentByTagName(rng.startContainer, "caption", true)) {
  21443. var div = me.document.createElement("div");
  21444. div.innerHTML = html.html;
  21445. //trace:3729
  21446. html.html = div[browser.ie9below ? "innerText" : "textContent"];
  21447. return;
  21448. }
  21449. var table = getUETableBySelected(me);
  21450. if (tableCopyList) {
  21451. me.fireEvent("saveScene");
  21452. var rng = me.selection.getRange();
  21453. var td = domUtils.findParentByTagName(
  21454. rng.startContainer,
  21455. ["td", "th"],
  21456. true
  21457. ),
  21458. tmpNode,
  21459. preNode;
  21460. if (td) {
  21461. var ut = getUETable(td);
  21462. if (isFullRow) {
  21463. var rowIndex = ut.getCellInfo(td).rowIndex;
  21464. if (td.tagName == "TH") {
  21465. rowIndex++;
  21466. }
  21467. for (var i = 0, ci; (ci = tableCopyList[i++]);) {
  21468. var tr = ut.insertRow(rowIndex++, "td");
  21469. for (var j = 0, cj; (cj = ci[j]); j++) {
  21470. var cell = tr.cells[j];
  21471. if (!cell) {
  21472. cell = tr.insertCell(j);
  21473. }
  21474. cell.innerHTML = cj.innerHTML;
  21475. cj.getAttribute("width") &&
  21476. cell.setAttribute("width", cj.getAttribute("width"));
  21477. cj.getAttribute("vAlign") &&
  21478. cell.setAttribute("vAlign", cj.getAttribute("vAlign"));
  21479. cj.getAttribute("align") &&
  21480. cell.setAttribute("align", cj.getAttribute("align"));
  21481. cj.style.cssText && (cell.style.cssText = cj.style.cssText);
  21482. }
  21483. for (var j = 0, cj; (cj = tr.cells[j]); j++) {
  21484. if (!ci[j]) break;
  21485. cj.innerHTML = ci[j].innerHTML;
  21486. ci[j].getAttribute("width") &&
  21487. cj.setAttribute("width", ci[j].getAttribute("width"));
  21488. ci[j].getAttribute("vAlign") &&
  21489. cj.setAttribute("vAlign", ci[j].getAttribute("vAlign"));
  21490. ci[j].getAttribute("align") &&
  21491. cj.setAttribute("align", ci[j].getAttribute("align"));
  21492. ci[j].style.cssText && (cj.style.cssText = ci[j].style.cssText);
  21493. }
  21494. }
  21495. } else {
  21496. if (isFullCol) {
  21497. cellInfo = ut.getCellInfo(td);
  21498. var maxColNum = 0;
  21499. for (var j = 0, ci = tableCopyList[0], cj; (cj = ci[j++]);) {
  21500. maxColNum += cj.colSpan || 1;
  21501. }
  21502. me.__hasEnterExecCommand = true;
  21503. for (i = 0; i < maxColNum; i++) {
  21504. me.execCommand("insertcol");
  21505. }
  21506. me.__hasEnterExecCommand = false;
  21507. td = ut.table.rows[0].cells[cellInfo.cellIndex];
  21508. if (td.tagName == "TH") {
  21509. td = ut.table.rows[1].cells[cellInfo.cellIndex];
  21510. }
  21511. }
  21512. for (var i = 0, ci; (ci = tableCopyList[i++]);) {
  21513. tmpNode = td;
  21514. for (var j = 0, cj; (cj = ci[j++]);) {
  21515. if (td) {
  21516. td.innerHTML = cj.innerHTML;
  21517. //todo 定制处理
  21518. cj.getAttribute("width") &&
  21519. td.setAttribute("width", cj.getAttribute("width"));
  21520. cj.getAttribute("vAlign") &&
  21521. td.setAttribute("vAlign", cj.getAttribute("vAlign"));
  21522. cj.getAttribute("align") &&
  21523. td.setAttribute("align", cj.getAttribute("align"));
  21524. cj.style.cssText && (td.style.cssText = cj.style.cssText);
  21525. preNode = td;
  21526. td = td.nextSibling;
  21527. } else {
  21528. var cloneTd = cj.cloneNode(true);
  21529. domUtils.removeAttributes(cloneTd, [
  21530. "class",
  21531. "rowSpan",
  21532. "colSpan"
  21533. ]);
  21534. preNode.parentNode.appendChild(cloneTd);
  21535. }
  21536. }
  21537. td = ut.getNextCell(tmpNode, true, true);
  21538. if (!tableCopyList[i]) break;
  21539. if (!td) {
  21540. var cellInfo = ut.getCellInfo(tmpNode);
  21541. ut.table.insertRow(ut.table.rows.length);
  21542. ut.update();
  21543. td = ut.getVSideCell(tmpNode, true);
  21544. }
  21545. }
  21546. }
  21547. ut.update();
  21548. } else {
  21549. table = me.document.createElement("table");
  21550. for (var i = 0, ci; (ci = tableCopyList[i++]);) {
  21551. var tr = table.insertRow(table.rows.length);
  21552. for (var j = 0, cj; (cj = ci[j++]);) {
  21553. cloneTd = UT.cloneCell(cj, null, true);
  21554. domUtils.removeAttributes(cloneTd, ["class"]);
  21555. tr.appendChild(cloneTd);
  21556. }
  21557. if (j == 2 && cloneTd.rowSpan > 1) {
  21558. cloneTd.rowSpan = 1;
  21559. }
  21560. }
  21561. var defaultValue = getDefaultValue(me),
  21562. width =
  21563. me.body.offsetWidth -
  21564. (needIEHack
  21565. ? parseInt(
  21566. domUtils.getComputedStyle(me.body, "margin-left"),
  21567. 10
  21568. ) * 2
  21569. : 0) -
  21570. defaultValue.tableBorder * 2 -
  21571. (me.options.offsetWidth || 0);
  21572. me.execCommand(
  21573. "insertHTML",
  21574. "<table " +
  21575. (isFullCol && isFullRow ? 'width="' + width + '"' : "") +
  21576. ">" +
  21577. table.innerHTML
  21578. .replace(/>\s*</g, "><")
  21579. .replace(/\bth\b/gi, "td") +
  21580. "</table>"
  21581. );
  21582. }
  21583. me.fireEvent("contentchange");
  21584. me.fireEvent("saveScene");
  21585. html.html = "";
  21586. return true;
  21587. } else {
  21588. var div = me.document.createElement("div"),
  21589. tables;
  21590. div.innerHTML = html.html;
  21591. tables = div.getElementsByTagName("table");
  21592. if (domUtils.findParentByTagName(me.selection.getStart(), "table")) {
  21593. utils.each(tables, function (t) {
  21594. domUtils.remove(t);
  21595. });
  21596. if (
  21597. domUtils.findParentByTagName(
  21598. me.selection.getStart(),
  21599. "caption",
  21600. true
  21601. )
  21602. ) {
  21603. div.innerHTML = div[browser.ie ? "innerText" : "textContent"];
  21604. }
  21605. } else {
  21606. utils.each(tables, function (table) {
  21607. removeStyleSize(table, true);
  21608. domUtils.removeAttributes(table, ["style"]);
  21609. utils.each(domUtils.getElementsByTagName(table, "td"), function (
  21610. td
  21611. ) {
  21612. if (isEmptyBlock(td)) {
  21613. domUtils.fillNode(me.document, td);
  21614. }
  21615. removeStyleSize(td, true);
  21616. // domUtils.removeAttributes(td, ['style'])
  21617. });
  21618. });
  21619. }
  21620. html.html = div.innerHTML;
  21621. }
  21622. });
  21623. me.addListener("afterpaste", function () {
  21624. utils.each(domUtils.getElementsByTagName(me.body, "table"), function (
  21625. table
  21626. ) {
  21627. if (table.offsetWidth > me.body.offsetWidth) {
  21628. var defaultValue = getDefaultValue(me, table);
  21629. table.style.width =
  21630. me.body.offsetWidth -
  21631. (needIEHack
  21632. ? parseInt(
  21633. domUtils.getComputedStyle(me.body, "margin-left"),
  21634. 10
  21635. ) * 2
  21636. : 0) -
  21637. defaultValue.tableBorder * 2 -
  21638. (me.options.offsetWidth || 0) +
  21639. "px";
  21640. }
  21641. });
  21642. });
  21643. me.addListener("blur", function () {
  21644. tableCopyList = null;
  21645. });
  21646. var timer;
  21647. me.addListener("keydown", function () {
  21648. clearTimeout(timer);
  21649. timer = setTimeout(function () {
  21650. var rng = me.selection.getRange(),
  21651. cell = domUtils.findParentByTagName(
  21652. rng.startContainer,
  21653. ["th", "td"],
  21654. true
  21655. );
  21656. if (cell) {
  21657. var table = cell.parentNode.parentNode.parentNode;
  21658. if (table.offsetWidth > table.getAttribute("width")) {
  21659. cell.style.wordBreak = "break-all";
  21660. }
  21661. }
  21662. }, 100);
  21663. });
  21664. me.addListener("selectionchange", function () {
  21665. toggleDraggableState(me, false, "", null);
  21666. });
  21667. //内容变化时触发索引更新
  21668. //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
  21669. me.addListener("contentchange", function () {
  21670. var me = this;
  21671. //尽可能排除一些不需要更新的状况
  21672. hideDragLine(me);
  21673. if (getUETableBySelected(me)) return;
  21674. var rng = me.selection.getRange();
  21675. var start = rng.startContainer;
  21676. start = domUtils.findParentByTagName(start, ["td", "th"], true);
  21677. utils.each(domUtils.getElementsByTagName(me.document, "table"), function (
  21678. table
  21679. ) {
  21680. if (me.fireEvent("excludetable", table) === true) return;
  21681. table.ueTable = new UT(table);
  21682. //trace:3742
  21683. // utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
  21684. //
  21685. // if (domUtils.isEmptyBlock(td) && td !== start) {
  21686. // domUtils.fillNode(me.document, td);
  21687. // if (browser.ie && browser.version == 6) {
  21688. // td.innerHTML = '&nbsp;'
  21689. // }
  21690. // }
  21691. // });
  21692. // utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
  21693. // if (domUtils.isEmptyBlock(th) && th !== start) {
  21694. // domUtils.fillNode(me.document, th);
  21695. // if (browser.ie && browser.version == 6) {
  21696. // th.innerHTML = '&nbsp;'
  21697. // }
  21698. // }
  21699. // });
  21700. table.onmouseover = function () {
  21701. me.fireEvent("tablemouseover", table);
  21702. };
  21703. table.onmousemove = function () {
  21704. me.fireEvent("tablemousemove", table);
  21705. me.options.tableDragable && toggleDragButton(true, this, me);
  21706. utils.defer(function () {
  21707. me.fireEvent("contentchange", 50);
  21708. }, true);
  21709. };
  21710. table.onmouseout = function () {
  21711. me.fireEvent("tablemouseout", table);
  21712. toggleDraggableState(me, false, "", null);
  21713. hideDragLine(me);
  21714. };
  21715. table.onclick = function (evt) {
  21716. evt = me.window.event || evt;
  21717. var target = getParentTdOrTh(evt.target || evt.srcElement);
  21718. if (!target) return;
  21719. var ut = getUETable(target),
  21720. table = ut.table,
  21721. cellInfo = ut.getCellInfo(target),
  21722. cellsRange,
  21723. rng = me.selection.getRange();
  21724. // if ("topLeft" == inPosition(table, mouseCoords(evt))) {
  21725. // cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
  21726. // ut.setSelected(cellsRange);
  21727. // return;
  21728. // }
  21729. // if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
  21730. //
  21731. // return;
  21732. // }
  21733. if (inTableSide(table, target, evt, true)) {
  21734. var endTdCol = ut.getCell(
  21735. ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex,
  21736. ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex
  21737. );
  21738. if (evt.shiftKey && ut.selectedTds.length) {
  21739. if (ut.selectedTds[0] !== endTdCol) {
  21740. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol);
  21741. ut.setSelected(cellsRange);
  21742. } else {
  21743. rng && rng.selectNodeContents(endTdCol).select();
  21744. }
  21745. } else {
  21746. if (target !== endTdCol) {
  21747. cellsRange = ut.getCellsRange(target, endTdCol);
  21748. ut.setSelected(cellsRange);
  21749. } else {
  21750. rng && rng.selectNodeContents(endTdCol).select();
  21751. }
  21752. }
  21753. return;
  21754. }
  21755. if (inTableSide(table, target, evt)) {
  21756. var endTdRow = ut.getCell(
  21757. ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex,
  21758. ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex
  21759. );
  21760. if (evt.shiftKey && ut.selectedTds.length) {
  21761. if (ut.selectedTds[0] !== endTdRow) {
  21762. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow);
  21763. ut.setSelected(cellsRange);
  21764. } else {
  21765. rng && rng.selectNodeContents(endTdRow).select();
  21766. }
  21767. } else {
  21768. if (target !== endTdRow) {
  21769. cellsRange = ut.getCellsRange(target, endTdRow);
  21770. ut.setSelected(cellsRange);
  21771. } else {
  21772. rng && rng.selectNodeContents(endTdRow).select();
  21773. }
  21774. }
  21775. }
  21776. };
  21777. });
  21778. switchBorderColor(me, true);
  21779. });
  21780. domUtils.on(me.document, "mousemove", mouseMoveEvent);
  21781. domUtils.on(me.document, "mouseout", function (evt) {
  21782. var target = evt.target || evt.srcElement;
  21783. if (target.tagName == "TABLE") {
  21784. toggleDraggableState(me, false, "", null);
  21785. }
  21786. });
  21787. /**
  21788. * 表格隔行变色
  21789. */
  21790. me.addListener("interlacetable", function (type, table, classList) {
  21791. if (!table) return;
  21792. var me = this,
  21793. rows = table.rows,
  21794. len = rows.length,
  21795. getClass = function (list, index, repeat) {
  21796. return list[index]
  21797. ? list[index]
  21798. : repeat ? list[index % list.length] : "";
  21799. };
  21800. for (var i = 0; i < len; i++) {
  21801. rows[i].className = getClass(
  21802. classList || me.options.classList,
  21803. i,
  21804. true
  21805. );
  21806. }
  21807. });
  21808. me.addListener("uninterlacetable", function (type, table) {
  21809. if (!table) return;
  21810. var me = this,
  21811. rows = table.rows,
  21812. classList = me.options.classList,
  21813. len = rows.length;
  21814. for (var i = 0; i < len; i++) {
  21815. domUtils.removeClasses(rows[i], classList);
  21816. }
  21817. });
  21818. me.addListener("mousedown", mouseDownEvent);
  21819. me.addListener("mouseup", mouseUpEvent);
  21820. //拖动的时候触发mouseup
  21821. domUtils.on(me.body, "dragstart", function (evt) {
  21822. mouseUpEvent.call(me, "dragstart", evt);
  21823. });
  21824. me.addOutputRule(function (root) {
  21825. utils.each(root.getNodesByTagName("div"), function (n) {
  21826. if (n.getAttr("id") == "ue_tableDragLine") {
  21827. n.parentNode.removeChild(n);
  21828. }
  21829. });
  21830. });
  21831. var currentRowIndex = 0;
  21832. me.addListener("mousedown", function () {
  21833. currentRowIndex = 0;
  21834. });
  21835. me.addListener("tabkeydown", function () {
  21836. var range = this.selection.getRange(),
  21837. common = range.getCommonAncestor(true, true),
  21838. table = domUtils.findParentByTagName(common, "table");
  21839. if (table) {
  21840. if (domUtils.findParentByTagName(common, "caption", true)) {
  21841. var cell = domUtils.getElementsByTagName(table, "th td");
  21842. if (cell && cell.length) {
  21843. range.setStart(cell[0], 0).setCursor(false, true);
  21844. }
  21845. } else {
  21846. var cell = domUtils.findParentByTagName(common, ["td", "th"], true),
  21847. ua = getUETable(cell);
  21848. currentRowIndex = cell.rowSpan > 1
  21849. ? currentRowIndex
  21850. : ua.getCellInfo(cell).rowIndex;
  21851. var nextCell = ua.getTabNextCell(cell, currentRowIndex);
  21852. if (nextCell) {
  21853. if (isEmptyBlock(nextCell)) {
  21854. range.setStart(nextCell, 0).setCursor(false, true);
  21855. } else {
  21856. range.selectNodeContents(nextCell).select();
  21857. }
  21858. } else {
  21859. me.fireEvent("saveScene");
  21860. me.__hasEnterExecCommand = true;
  21861. this.execCommand("insertrownext");
  21862. me.__hasEnterExecCommand = false;
  21863. range = this.selection.getRange();
  21864. range
  21865. .setStart(table.rows[table.rows.length - 1].cells[0], 0)
  21866. .setCursor();
  21867. me.fireEvent("saveScene");
  21868. }
  21869. }
  21870. return true;
  21871. }
  21872. });
  21873. browser.ie &&
  21874. me.addListener("selectionchange", function () {
  21875. toggleDraggableState(this, false, "", null);
  21876. });
  21877. me.addListener("keydown", function (type, evt) {
  21878. var me = this;
  21879. //处理在表格的最后一个输入tab产生新的表格
  21880. var keyCode = evt.keyCode || evt.which;
  21881. if (keyCode == 8 || keyCode == 46) {
  21882. return;
  21883. }
  21884. var notCtrlKey =
  21885. !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey;
  21886. notCtrlKey &&
  21887. removeSelectedClass(domUtils.getElementsByTagName(me.body, "td"));
  21888. var ut = getUETableBySelected(me);
  21889. if (!ut) return;
  21890. notCtrlKey && ut.clearSelected();
  21891. });
  21892. me.addListener("beforegetcontent", function () {
  21893. switchBorderColor(this, false);
  21894. browser.ie &&
  21895. utils.each(this.document.getElementsByTagName("caption"), function (ci) {
  21896. if (domUtils.isEmptyNode(ci)) {
  21897. ci.innerHTML = "&nbsp;";
  21898. }
  21899. });
  21900. });
  21901. me.addListener("aftergetcontent", function () {
  21902. switchBorderColor(this, true);
  21903. });
  21904. me.addListener("getAllHtml", function () {
  21905. removeSelectedClass(me.document.getElementsByTagName("td"));
  21906. });
  21907. //修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
  21908. me.addListener("fullscreenchanged", function (type, fullscreen) {
  21909. if (!fullscreen) {
  21910. var ratio = this.body.offsetWidth / document.body.offsetWidth,
  21911. tables = domUtils.getElementsByTagName(this.body, "table");
  21912. utils.each(tables, function (table) {
  21913. if (table.offsetWidth < me.body.offsetWidth) return false;
  21914. var tds = domUtils.getElementsByTagName(table, "td"),
  21915. backWidths = [];
  21916. utils.each(tds, function (td) {
  21917. backWidths.push(td.offsetWidth);
  21918. });
  21919. for (var i = 0, td; (td = tds[i]); i++) {
  21920. td.setAttribute("width", Math.floor(backWidths[i] * ratio));
  21921. }
  21922. table.setAttribute(
  21923. "width",
  21924. Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me)))
  21925. );
  21926. });
  21927. }
  21928. });
  21929. //重写execCommand命令,用于处理框选时的处理
  21930. var oldExecCommand = me.execCommand;
  21931. me.execCommand = function (cmd, datatat) {
  21932. var me = this,
  21933. args = arguments;
  21934. cmd = cmd.toLowerCase();
  21935. var ut = getUETableBySelected(me),
  21936. tds,
  21937. range = new dom.Range(me.document),
  21938. cmdFun = me.commands[cmd] || UE.commands[cmd],
  21939. result;
  21940. if (!cmdFun) return;
  21941. if (
  21942. ut &&
  21943. !commands[cmd] &&
  21944. !cmdFun.notNeedUndo &&
  21945. !me.__hasEnterExecCommand
  21946. ) {
  21947. me.__hasEnterExecCommand = true;
  21948. me.fireEvent("beforeexeccommand", cmd);
  21949. tds = ut.selectedTds;
  21950. var lastState = -2,
  21951. lastValue = -2,
  21952. value,
  21953. state;
  21954. for (var i = 0, td; (td = tds[i]); i++) {
  21955. if (isEmptyBlock(td)) {
  21956. range.setStart(td, 0).setCursor(false, true);
  21957. } else {
  21958. range.selectNode(td).select(true);
  21959. }
  21960. state = me.queryCommandState(cmd);
  21961. value = me.queryCommandValue(cmd);
  21962. if (state != -1) {
  21963. if (lastState !== state || lastValue !== value) {
  21964. me._ignoreContentChange = true;
  21965. result = oldExecCommand.apply(me, arguments);
  21966. me._ignoreContentChange = false;
  21967. }
  21968. lastState = me.queryCommandState(cmd);
  21969. lastValue = me.queryCommandValue(cmd);
  21970. if (domUtils.isEmptyBlock(td)) {
  21971. domUtils.fillNode(me.document, td);
  21972. }
  21973. }
  21974. }
  21975. range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true);
  21976. me.fireEvent("contentchange");
  21977. me.fireEvent("afterexeccommand", cmd);
  21978. me.__hasEnterExecCommand = false;
  21979. me._selectionChange();
  21980. } else {
  21981. result = oldExecCommand.apply(me, arguments);
  21982. }
  21983. return result;
  21984. };
  21985. });
  21986. /**
  21987. * 删除obj的宽高style,改成属性宽高
  21988. * @param obj
  21989. * @param replaceToProperty
  21990. */
  21991. function removeStyleSize(obj, replaceToProperty) {
  21992. removeStyle(obj, "width", true);
  21993. removeStyle(obj, "height", true);
  21994. }
  21995. function removeStyle(obj, styleName, replaceToProperty) {
  21996. if (obj.style[styleName]) {
  21997. replaceToProperty &&
  21998. obj.setAttribute(styleName, parseInt(obj.style[styleName], 10));
  21999. obj.style[styleName] = "";
  22000. }
  22001. }
  22002. function getParentTdOrTh(ele) {
  22003. if (ele.tagName == "TD" || ele.tagName == "TH") return ele;
  22004. var td;
  22005. if (
  22006. (td =
  22007. domUtils.findParentByTagName(ele, "td", true) ||
  22008. domUtils.findParentByTagName(ele, "th", true))
  22009. )
  22010. return td;
  22011. return null;
  22012. }
  22013. function isEmptyBlock(node) {
  22014. var reg = new RegExp(domUtils.fillChar, "g");
  22015. if (
  22016. node[browser.ie ? "innerText" : "textContent"]
  22017. .replace(/^\s*$/, "")
  22018. .replace(reg, "").length > 0
  22019. ) {
  22020. return 0;
  22021. }
  22022. for (var n in dtd.$isNotEmpty) {
  22023. if (node.getElementsByTagName(n).length) {
  22024. return 0;
  22025. }
  22026. }
  22027. return 1;
  22028. }
  22029. function mouseCoords(evt) {
  22030. if (evt.pageX || evt.pageY) {
  22031. return {x: evt.pageX, y: evt.pageY};
  22032. }
  22033. return {
  22034. x:
  22035. evt.clientX + me.document.body.scrollLeft - me.document.body.clientLeft,
  22036. y: evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
  22037. };
  22038. }
  22039. function mouseMoveEvent(evt) {
  22040. if (isEditorDisabled()) {
  22041. return;
  22042. }
  22043. try {
  22044. //普通状态下鼠标移动
  22045. var target = getParentTdOrTh(evt.target || evt.srcElement),
  22046. pos;
  22047. //区分用户的行为是拖动还是双击
  22048. if (isInResizeBuffer) {
  22049. me.body.style.webkitUserSelect = "none";
  22050. if (
  22051. Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell ||
  22052. Math.abs(userActionStatus.y - evt.clientY) > offsetOfTableCell
  22053. ) {
  22054. clearTableDragTimer();
  22055. isInResizeBuffer = false;
  22056. singleClickState = 0;
  22057. //drag action
  22058. tableBorderDrag(evt);
  22059. }
  22060. }
  22061. //修改单元格大小时的鼠标移动
  22062. if (onDrag && dragTd) {
  22063. singleClickState = 0;
  22064. me.body.style.webkitUserSelect = "none";
  22065. me.selection.getNative()[
  22066. browser.ie9below ? "empty" : "removeAllRanges"
  22067. ]();
  22068. pos = mouseCoords(evt);
  22069. toggleDraggableState(me, true, onDrag, pos, target);
  22070. if (onDrag == "h") {
  22071. dragLine.style.left = getPermissionX(dragTd, evt) + "px";
  22072. } else if (onDrag == "v") {
  22073. dragLine.style.top = getPermissionY(dragTd, evt) + "px";
  22074. }
  22075. return;
  22076. }
  22077. //当鼠标处于table上时,修改移动过程中的光标状态
  22078. if (target) {
  22079. //针对使用table作为容器的组件不触发拖拽效果
  22080. if (me.fireEvent("excludetable", target) === true) return;
  22081. pos = mouseCoords(evt);
  22082. var state = getRelation(target, pos),
  22083. table = domUtils.findParentByTagName(target, "table", true);
  22084. if (inTableSide(table, target, evt, true)) {
  22085. if (me.fireEvent("excludetable", table) === true) return;
  22086. me.body.style.cursor =
  22087. "url(" + me.options.cursorpath + "h.png),pointer";
  22088. } else if (inTableSide(table, target, evt)) {
  22089. if (me.fireEvent("excludetable", table) === true) return;
  22090. me.body.style.cursor =
  22091. "url(" + me.options.cursorpath + "v.png),pointer";
  22092. } else {
  22093. me.body.style.cursor = "text";
  22094. var curCell = target;
  22095. if (/\d/.test(state)) {
  22096. state = state.replace(/\d/, "");
  22097. target = getUETable(target).getPreviewCell(target, state == "v");
  22098. }
  22099. //位于第一行的顶部或者第一列的左边时不可拖动
  22100. toggleDraggableState(
  22101. me,
  22102. target ? !!state : false,
  22103. target ? state : "",
  22104. pos,
  22105. target
  22106. );
  22107. }
  22108. } else {
  22109. toggleDragButton(false, table, me);
  22110. }
  22111. } catch (e) {
  22112. showError(e);
  22113. }
  22114. }
  22115. var dragButtonTimer;
  22116. function toggleDragButton(show, table, editor) {
  22117. if (!show) {
  22118. if (dragOver) return;
  22119. dragButtonTimer = setTimeout(function () {
  22120. !dragOver &&
  22121. dragButton &&
  22122. dragButton.parentNode &&
  22123. dragButton.parentNode.removeChild(dragButton);
  22124. }, 2000);
  22125. } else {
  22126. createDragButton(table, editor);
  22127. }
  22128. }
  22129. function createDragButton(table, editor) {
  22130. var pos = domUtils.getXY(table),
  22131. doc = table.ownerDocument;
  22132. if (dragButton && dragButton.parentNode) return dragButton;
  22133. dragButton = doc.createElement("div");
  22134. dragButton.contentEditable = false;
  22135. dragButton.innerHTML = "";
  22136. dragButton.style.cssText =
  22137. "width:15px;height:15px;background-image:url(" +
  22138. editor.options.UEDITOR_HOME_URL +
  22139. "dialogs/table/dragicon.png);position: absolute;cursor:move;top:" +
  22140. (pos.y - 15) +
  22141. "px;left:" +
  22142. pos.x +
  22143. "px;";
  22144. domUtils.unSelectable(dragButton);
  22145. dragButton.onmouseover = function (evt) {
  22146. dragOver = true;
  22147. };
  22148. dragButton.onmouseout = function (evt) {
  22149. dragOver = false;
  22150. };
  22151. domUtils.on(dragButton, "click", function (type, evt) {
  22152. doClick(evt, this);
  22153. });
  22154. domUtils.on(dragButton, "dblclick", function (type, evt) {
  22155. doDblClick(evt);
  22156. });
  22157. domUtils.on(dragButton, "dragstart", function (type, evt) {
  22158. domUtils.preventDefault(evt);
  22159. });
  22160. var timer;
  22161. function doClick(evt, button) {
  22162. // 部分浏览器下需要清理
  22163. clearTimeout(timer);
  22164. timer = setTimeout(function () {
  22165. editor.fireEvent("tableClicked", table, button);
  22166. }, 300);
  22167. }
  22168. function doDblClick(evt) {
  22169. clearTimeout(timer);
  22170. var ut = getUETable(table),
  22171. start = table.rows[0].cells[0],
  22172. end = ut.getLastCell(),
  22173. range = ut.getCellsRange(start, end);
  22174. editor.selection.getRange().setStart(start, 0).setCursor(false, true);
  22175. ut.setSelected(range);
  22176. }
  22177. doc.body.appendChild(dragButton);
  22178. }
  22179. // function inPosition(table, pos) {
  22180. // var tablePos = domUtils.getXY(table),
  22181. // width = table.offsetWidth,
  22182. // height = table.offsetHeight;
  22183. // if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
  22184. // return "topLeft";
  22185. // } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
  22186. // return "bottomRight";
  22187. // }
  22188. // }
  22189. function inTableSide(table, cell, evt, top) {
  22190. var pos = mouseCoords(evt),
  22191. state = getRelation(cell, pos);
  22192. if (top) {
  22193. var caption = table.getElementsByTagName("caption")[0],
  22194. capHeight = caption ? caption.offsetHeight : 0;
  22195. return state == "v1" && pos.y - domUtils.getXY(table).y - capHeight < 8;
  22196. } else {
  22197. return state == "h1" && pos.x - domUtils.getXY(table).x < 8;
  22198. }
  22199. }
  22200. /**
  22201. * 获取拖动时允许的X轴坐标
  22202. * @param dragTd
  22203. * @param evt
  22204. */
  22205. function getPermissionX(dragTd, evt) {
  22206. var ut = getUETable(dragTd);
  22207. if (ut) {
  22208. var preTd = ut.getSameEndPosCells(dragTd, "x")[0],
  22209. nextTd = ut.getSameStartPosXCells(dragTd)[0],
  22210. mouseX = mouseCoords(evt).x,
  22211. left =
  22212. (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20,
  22213. right = nextTd
  22214. ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20
  22215. : me.body.offsetWidth + 5 ||
  22216. parseInt(domUtils.getComputedStyle(me.body, "width"), 10);
  22217. left += cellMinWidth;
  22218. right -= cellMinWidth;
  22219. return mouseX < left ? left : mouseX > right ? right : mouseX;
  22220. }
  22221. }
  22222. /**
  22223. * 获取拖动时允许的Y轴坐标
  22224. */
  22225. function getPermissionY(dragTd, evt) {
  22226. try {
  22227. var top = domUtils.getXY(dragTd).y,
  22228. mousePosY = mouseCoords(evt).y;
  22229. return mousePosY < top ? top : mousePosY;
  22230. } catch (e) {
  22231. showError(e);
  22232. }
  22233. }
  22234. /**
  22235. * 移动状态切换
  22236. */
  22237. function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
  22238. try {
  22239. editor.body.style.cursor = dir == "h"
  22240. ? "col-resize"
  22241. : dir == "v" ? "row-resize" : "text";
  22242. if (browser.ie) {
  22243. if (dir && !mousedown && !getUETableBySelected(editor)) {
  22244. getDragLine(editor, editor.document);
  22245. showDragLineAt(dir, cell);
  22246. } else {
  22247. hideDragLine(editor);
  22248. }
  22249. }
  22250. onBorder = draggable;
  22251. } catch (e) {
  22252. showError(e);
  22253. }
  22254. }
  22255. /**
  22256. * 获取与UETable相关的resize line
  22257. * @param uetable UETable对象
  22258. */
  22259. function getResizeLineByUETable() {
  22260. var lineId = "_UETableResizeLine",
  22261. line = this.document.getElementById(lineId);
  22262. if (!line) {
  22263. line = this.document.createElement("div");
  22264. line.id = lineId;
  22265. line.contnetEditable = false;
  22266. line.setAttribute("unselectable", "on");
  22267. var styles = {
  22268. width: 2 * cellBorderWidth + 1 + "px",
  22269. position: "absolute",
  22270. "z-index": 100000,
  22271. cursor: "col-resize",
  22272. background: "red",
  22273. display: "none"
  22274. };
  22275. //切换状态
  22276. line.onmouseout = function () {
  22277. this.style.display = "none";
  22278. };
  22279. utils.extend(line.style, styles);
  22280. this.document.body.appendChild(line);
  22281. }
  22282. return line;
  22283. }
  22284. /**
  22285. * 更新resize-line
  22286. */
  22287. function updateResizeLine(cell, uetable) {
  22288. var line = getResizeLineByUETable.call(this),
  22289. table = uetable.table,
  22290. styles = {
  22291. top: domUtils.getXY(table).y + "px",
  22292. left:
  22293. domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + "px",
  22294. display: "block",
  22295. height: table.offsetHeight + "px"
  22296. };
  22297. utils.extend(line.style, styles);
  22298. }
  22299. /**
  22300. * 显示resize-line
  22301. */
  22302. function showResizeLine(cell) {
  22303. var uetable = getUETable(cell);
  22304. updateResizeLine.call(this, cell, uetable);
  22305. }
  22306. /**
  22307. * 获取鼠标与当前单元格的相对位置
  22308. * @param ele
  22309. * @param mousePos
  22310. */
  22311. function getRelation(ele, mousePos) {
  22312. var elePos = domUtils.getXY(ele);
  22313. if (!elePos) {
  22314. return "";
  22315. }
  22316. if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
  22317. return "h";
  22318. }
  22319. if (mousePos.x - elePos.x < cellBorderWidth) {
  22320. return "h1";
  22321. }
  22322. if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
  22323. return "v";
  22324. }
  22325. if (mousePos.y - elePos.y < cellBorderWidth) {
  22326. return "v1";
  22327. }
  22328. return "";
  22329. }
  22330. function mouseDownEvent(type, evt) {
  22331. if (isEditorDisabled()) {
  22332. return;
  22333. }
  22334. userActionStatus = {
  22335. x: evt.clientX,
  22336. y: evt.clientY
  22337. };
  22338. //右键菜单单独处理
  22339. if (evt.button == 2) {
  22340. var ut = getUETableBySelected(me),
  22341. flag = false;
  22342. if (ut) {
  22343. var td = getTargetTd(me, evt);
  22344. utils.each(ut.selectedTds, function (ti) {
  22345. if (ti === td) {
  22346. flag = true;
  22347. }
  22348. });
  22349. if (!flag) {
  22350. removeSelectedClass(domUtils.getElementsByTagName(me.body, "th td"));
  22351. ut.clearSelected();
  22352. } else {
  22353. td = ut.selectedTds[0];
  22354. setTimeout(function () {
  22355. me.selection.getRange().setStart(td, 0).setCursor(false, true);
  22356. }, 0);
  22357. }
  22358. }
  22359. } else {
  22360. tableClickHander(evt);
  22361. }
  22362. }
  22363. //清除表格的计时器
  22364. function clearTableTimer() {
  22365. tabTimer && clearTimeout(tabTimer);
  22366. tabTimer = null;
  22367. }
  22368. //双击收缩
  22369. function tableDbclickHandler(evt) {
  22370. singleClickState = 0;
  22371. evt = evt || me.window.event;
  22372. var target = getParentTdOrTh(evt.target || evt.srcElement);
  22373. if (target) {
  22374. var h;
  22375. if ((h = getRelation(target, mouseCoords(evt)))) {
  22376. hideDragLine(me);
  22377. if (h == "h1") {
  22378. h = "h";
  22379. if (
  22380. inTableSide(
  22381. domUtils.findParentByTagName(target, "table"),
  22382. target,
  22383. evt
  22384. )
  22385. ) {
  22386. me.execCommand("adaptbywindow");
  22387. } else {
  22388. target = getUETable(target).getPreviewCell(target);
  22389. if (target) {
  22390. var rng = me.selection.getRange();
  22391. rng.selectNodeContents(target).setCursor(true, true);
  22392. }
  22393. }
  22394. }
  22395. if (h == "h") {
  22396. var ut = getUETable(target),
  22397. table = ut.table,
  22398. cells = getCellsByMoveBorder(target, table, true);
  22399. cells = extractArray(cells, "left");
  22400. ut.width = ut.offsetWidth;
  22401. var oldWidth = [],
  22402. newWidth = [];
  22403. utils.each(cells, function (cell) {
  22404. oldWidth.push(cell.offsetWidth);
  22405. });
  22406. utils.each(cells, function (cell) {
  22407. cell.removeAttribute("width");
  22408. });
  22409. window.setTimeout(function () {
  22410. //是否允许改变
  22411. var changeable = true;
  22412. utils.each(cells, function (cell, index) {
  22413. var width = cell.offsetWidth;
  22414. if (width > oldWidth[index]) {
  22415. changeable = false;
  22416. return false;
  22417. }
  22418. newWidth.push(width);
  22419. });
  22420. var change = changeable ? newWidth : oldWidth;
  22421. utils.each(cells, function (cell, index) {
  22422. cell.width = change[index] - getTabcellSpace();
  22423. });
  22424. }, 0);
  22425. // minWidth -= cellMinWidth;
  22426. //
  22427. // table.removeAttribute("width");
  22428. // utils.each(cells, function (cell) {
  22429. // cell.style.width = "";
  22430. // cell.width -= minWidth;
  22431. // });
  22432. }
  22433. }
  22434. }
  22435. }
  22436. function tableClickHander(evt) {
  22437. removeSelectedClass(domUtils.getElementsByTagName(me.body, "td th"));
  22438. //trace:3113
  22439. //选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
  22440. utils.each(me.document.getElementsByTagName("table"), function (t) {
  22441. t.ueTable = null;
  22442. });
  22443. startTd = getTargetTd(me, evt);
  22444. if (!startTd) return;
  22445. var table = domUtils.findParentByTagName(startTd, "table", true);
  22446. ut = getUETable(table);
  22447. ut && ut.clearSelected();
  22448. //判断当前鼠标状态
  22449. if (!onBorder) {
  22450. me.document.body.style.webkitUserSelect = "";
  22451. mousedown = true;
  22452. me.addListener("mouseover", mouseOverEvent);
  22453. } else {
  22454. //边框上的动作处理
  22455. borderActionHandler(evt);
  22456. }
  22457. }
  22458. //处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
  22459. function borderActionHandler(evt) {
  22460. if (browser.ie) {
  22461. evt = reconstruct(evt);
  22462. }
  22463. clearTableDragTimer();
  22464. //是否正在等待resize的缓冲中
  22465. isInResizeBuffer = true;
  22466. tableDragTimer = setTimeout(function () {
  22467. tableBorderDrag(evt);
  22468. }, dblclickTime);
  22469. }
  22470. function extractArray(originArr, key) {
  22471. var result = [],
  22472. tmp = null;
  22473. for (var i = 0, len = originArr.length; i < len; i++) {
  22474. tmp = originArr[i][key];
  22475. if (tmp) {
  22476. result.push(tmp);
  22477. }
  22478. }
  22479. return result;
  22480. }
  22481. function clearTableDragTimer() {
  22482. tableDragTimer && clearTimeout(tableDragTimer);
  22483. tableDragTimer = null;
  22484. }
  22485. function reconstruct(obj) {
  22486. var attrs = [
  22487. "pageX",
  22488. "pageY",
  22489. "clientX",
  22490. "clientY",
  22491. "srcElement",
  22492. "target"
  22493. ],
  22494. newObj = {};
  22495. if (obj) {
  22496. for (var i = 0, key, val; (key = attrs[i]); i++) {
  22497. val = obj[key];
  22498. val && (newObj[key] = val);
  22499. }
  22500. }
  22501. return newObj;
  22502. }
  22503. //边框拖动
  22504. function tableBorderDrag(evt) {
  22505. isInResizeBuffer = false;
  22506. startTd = evt.target || evt.srcElement;
  22507. if (!startTd) return;
  22508. var state = getRelation(startTd, mouseCoords(evt));
  22509. if (/\d/.test(state)) {
  22510. state = state.replace(/\d/, "");
  22511. startTd = getUETable(startTd).getPreviewCell(startTd, state == "v");
  22512. }
  22513. hideDragLine(me);
  22514. getDragLine(me, me.document);
  22515. me.fireEvent("saveScene");
  22516. showDragLineAt(state, startTd);
  22517. mousedown = true;
  22518. //拖动开始
  22519. onDrag = state;
  22520. dragTd = startTd;
  22521. }
  22522. function mouseUpEvent(type, evt) {
  22523. if (isEditorDisabled()) {
  22524. return;
  22525. }
  22526. clearTableDragTimer();
  22527. isInResizeBuffer = false;
  22528. if (onBorder) {
  22529. singleClickState = ++singleClickState % 3;
  22530. userActionStatus = {
  22531. x: evt.clientX,
  22532. y: evt.clientY
  22533. };
  22534. tableResizeTimer = setTimeout(function () {
  22535. singleClickState > 0 && singleClickState--;
  22536. }, dblclickTime);
  22537. if (singleClickState === 2) {
  22538. singleClickState = 0;
  22539. tableDbclickHandler(evt);
  22540. return;
  22541. }
  22542. }
  22543. if (evt.button == 2) return;
  22544. var me = this;
  22545. //清除表格上原生跨选问题
  22546. var range = me.selection.getRange(),
  22547. start = domUtils.findParentByTagName(range.startContainer, "table", true),
  22548. end = domUtils.findParentByTagName(range.endContainer, "table", true);
  22549. if (start || end) {
  22550. if (start === end) {
  22551. start = domUtils.findParentByTagName(
  22552. range.startContainer,
  22553. ["td", "th", "caption"],
  22554. true
  22555. );
  22556. end = domUtils.findParentByTagName(
  22557. range.endContainer,
  22558. ["td", "th", "caption"],
  22559. true
  22560. );
  22561. if (start !== end) {
  22562. me.selection.clearRange();
  22563. }
  22564. } else {
  22565. me.selection.clearRange();
  22566. }
  22567. }
  22568. mousedown = false;
  22569. me.document.body.style.webkitUserSelect = "";
  22570. //拖拽状态下的mouseUP
  22571. if (onDrag && dragTd) {
  22572. me.selection.getNative()[
  22573. browser.ie9below ? "empty" : "removeAllRanges"
  22574. ]();
  22575. singleClickState = 0;
  22576. dragLine = me.document.getElementById("ue_tableDragLine");
  22577. // trace 3973
  22578. if (dragLine) {
  22579. var dragTdPos = domUtils.getXY(dragTd),
  22580. dragLinePos = domUtils.getXY(dragLine);
  22581. switch (onDrag) {
  22582. case "h":
  22583. changeColWidth(dragTd, dragLinePos.x - dragTdPos.x);
  22584. break;
  22585. case "v":
  22586. changeRowHeight(
  22587. dragTd,
  22588. dragLinePos.y - dragTdPos.y - dragTd.offsetHeight
  22589. );
  22590. break;
  22591. default:
  22592. }
  22593. onDrag = "";
  22594. dragTd = null;
  22595. hideDragLine(me);
  22596. me.fireEvent("saveScene");
  22597. return;
  22598. }
  22599. }
  22600. //正常状态下的mouseup
  22601. if (!startTd) {
  22602. var target = domUtils.findParentByTagName(
  22603. evt.target || evt.srcElement,
  22604. "td",
  22605. true
  22606. );
  22607. if (!target)
  22608. target = domUtils.findParentByTagName(
  22609. evt.target || evt.srcElement,
  22610. "th",
  22611. true
  22612. );
  22613. if (target && (target.tagName == "TD" || target.tagName == "TH")) {
  22614. if (me.fireEvent("excludetable", target) === true) return;
  22615. range = new dom.Range(me.document);
  22616. range.setStart(target, 0).setCursor(false, true);
  22617. }
  22618. } else {
  22619. var ut = getUETable(startTd),
  22620. cell = ut ? ut.selectedTds[0] : null;
  22621. if (cell) {
  22622. range = new dom.Range(me.document);
  22623. if (domUtils.isEmptyBlock(cell)) {
  22624. range.setStart(cell, 0).setCursor(false, true);
  22625. } else {
  22626. range
  22627. .selectNodeContents(cell)
  22628. .shrinkBoundary()
  22629. .setCursor(false, true);
  22630. }
  22631. } else {
  22632. range = me.selection.getRange().shrinkBoundary();
  22633. if (!range.collapsed) {
  22634. var start = domUtils.findParentByTagName(
  22635. range.startContainer,
  22636. ["td", "th"],
  22637. true
  22638. ),
  22639. end = domUtils.findParentByTagName(
  22640. range.endContainer,
  22641. ["td", "th"],
  22642. true
  22643. );
  22644. //在table里边的不能清除
  22645. if (
  22646. (start && !end) ||
  22647. (!start && end) ||
  22648. (start && end && start !== end)
  22649. ) {
  22650. range.setCursor(false, true);
  22651. }
  22652. }
  22653. }
  22654. startTd = null;
  22655. me.removeListener("mouseover", mouseOverEvent);
  22656. }
  22657. me._selectionChange(250, evt);
  22658. }
  22659. function mouseOverEvent(type, evt) {
  22660. if (isEditorDisabled()) {
  22661. return;
  22662. }
  22663. var me = this,
  22664. tar = evt.target || evt.srcElement;
  22665. currentTd =
  22666. domUtils.findParentByTagName(tar, "td", true) ||
  22667. domUtils.findParentByTagName(tar, "th", true);
  22668. //需要判断两个TD是否位于同一个表格内
  22669. if (
  22670. startTd &&
  22671. currentTd &&
  22672. ((startTd.tagName == "TD" && currentTd.tagName == "TD") ||
  22673. (startTd.tagName == "TH" && currentTd.tagName == "TH")) &&
  22674. domUtils.findParentByTagName(startTd, "table") ==
  22675. domUtils.findParentByTagName(currentTd, "table")
  22676. ) {
  22677. var ut = getUETable(currentTd);
  22678. if (startTd != currentTd) {
  22679. me.document.body.style.webkitUserSelect = "none";
  22680. me.selection.getNative()[
  22681. browser.ie9below ? "empty" : "removeAllRanges"
  22682. ]();
  22683. var range = ut.getCellsRange(startTd, currentTd);
  22684. ut.setSelected(range);
  22685. } else {
  22686. me.document.body.style.webkitUserSelect = "";
  22687. ut.clearSelected();
  22688. }
  22689. }
  22690. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  22691. }
  22692. function setCellHeight(cell, height, backHeight) {
  22693. var lineHight = parseInt(
  22694. domUtils.getComputedStyle(cell, "line-height"),
  22695. 10
  22696. ),
  22697. tmpHeight = backHeight + height;
  22698. height = tmpHeight < lineHight ? lineHight : tmpHeight;
  22699. if (cell.style.height) cell.style.height = "";
  22700. cell.rowSpan == 1
  22701. ? cell.setAttribute("height", height)
  22702. : cell.removeAttribute && cell.removeAttribute("height");
  22703. }
  22704. function getWidth(cell) {
  22705. if (!cell) return 0;
  22706. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  22707. }
  22708. function changeColWidth(cell, changeValue) {
  22709. var ut = getUETable(cell);
  22710. if (ut) {
  22711. //根据当前移动的边框获取相关的单元格
  22712. var table = ut.table,
  22713. cells = getCellsByMoveBorder(cell, table);
  22714. table.style.width = "";
  22715. table.removeAttribute("width");
  22716. //修正改变量
  22717. changeValue = correctChangeValue(changeValue, cell, cells);
  22718. if (cell.nextSibling) {
  22719. var i = 0;
  22720. utils.each(cells, function (cellGroup) {
  22721. cellGroup.left.width = +cellGroup.left.width + changeValue;
  22722. cellGroup.right &&
  22723. (cellGroup.right.width = +cellGroup.right.width - changeValue);
  22724. });
  22725. } else {
  22726. utils.each(cells, function (cellGroup) {
  22727. cellGroup.left.width -= -changeValue;
  22728. });
  22729. }
  22730. }
  22731. }
  22732. function isEditorDisabled() {
  22733. return me.body.contentEditable === "false";
  22734. }
  22735. function changeRowHeight(td, changeValue) {
  22736. if (Math.abs(changeValue) < 10) return;
  22737. var ut = getUETable(td);
  22738. if (ut) {
  22739. var cells = ut.getSameEndPosCells(td, "y"),
  22740. //备份需要连带变化的td的原始高度,否则后期无法获取正确的值
  22741. backHeight = cells[0] ? cells[0].offsetHeight : 0;
  22742. for (var i = 0, cell; (cell = cells[i++]);) {
  22743. setCellHeight(cell, changeValue, backHeight);
  22744. }
  22745. }
  22746. }
  22747. /**
  22748. * 获取调整单元格大小的相关单元格
  22749. * @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
  22750. */
  22751. function getCellsByMoveBorder(cell, table, isContainMergeCell) {
  22752. if (!table) {
  22753. table = domUtils.findParentByTagName(cell, "table");
  22754. }
  22755. if (!table) {
  22756. return null;
  22757. }
  22758. //获取到该单元格所在行的序列号
  22759. var index = domUtils.getNodeIndex(cell),
  22760. temp = cell,
  22761. rows = table.rows,
  22762. colIndex = 0;
  22763. while (temp) {
  22764. //获取到当前单元格在未发生单元格合并时的序列
  22765. if (temp.nodeType === 1) {
  22766. colIndex += temp.colSpan || 1;
  22767. }
  22768. temp = temp.previousSibling;
  22769. }
  22770. temp = null;
  22771. //记录想关的单元格
  22772. var borderCells = [];
  22773. utils.each(rows, function (tabRow) {
  22774. var cells = tabRow.cells,
  22775. currIndex = 0;
  22776. utils.each(cells, function (tabCell) {
  22777. currIndex += tabCell.colSpan || 1;
  22778. if (currIndex === colIndex) {
  22779. borderCells.push({
  22780. left: tabCell,
  22781. right: tabCell.nextSibling || null
  22782. });
  22783. return false;
  22784. } else if (currIndex > colIndex) {
  22785. if (isContainMergeCell) {
  22786. borderCells.push({
  22787. left: tabCell
  22788. });
  22789. }
  22790. return false;
  22791. }
  22792. });
  22793. });
  22794. return borderCells;
  22795. }
  22796. /**
  22797. * 通过给定的单元格集合获取最小的单元格width
  22798. */
  22799. function getMinWidthByTableCells(cells) {
  22800. var minWidth = Number.MAX_VALUE;
  22801. for (var i = 0, curCell; (curCell = cells[i]); i++) {
  22802. minWidth = Math.min(
  22803. minWidth,
  22804. curCell.width || getTableCellWidth(curCell)
  22805. );
  22806. }
  22807. return minWidth;
  22808. }
  22809. function correctChangeValue(changeValue, relatedCell, cells) {
  22810. //为单元格的paading预留空间
  22811. changeValue -= getTabcellSpace();
  22812. if (changeValue < 0) {
  22813. return 0;
  22814. }
  22815. changeValue -= getTableCellWidth(relatedCell);
  22816. //确定方向
  22817. var direction = changeValue < 0 ? "left" : "right";
  22818. changeValue = Math.abs(changeValue);
  22819. //只关心非最后一个单元格就可以
  22820. utils.each(cells, function (cellGroup) {
  22821. var curCell = cellGroup[direction];
  22822. //为单元格保留最小空间
  22823. if (curCell) {
  22824. changeValue = Math.min(
  22825. changeValue,
  22826. getTableCellWidth(curCell) - cellMinWidth
  22827. );
  22828. }
  22829. });
  22830. //修正越界
  22831. changeValue = changeValue < 0 ? 0 : changeValue;
  22832. return direction === "left" ? -changeValue : changeValue;
  22833. }
  22834. function getTableCellWidth(cell) {
  22835. var width = 0,
  22836. //偏移纠正量
  22837. offset = 0,
  22838. width = cell.offsetWidth - getTabcellSpace();
  22839. //最后一个节点纠正一下
  22840. if (!cell.nextSibling) {
  22841. width -= getTableCellOffset(cell);
  22842. }
  22843. width = width < 0 ? 0 : width;
  22844. try {
  22845. cell.width = width;
  22846. } catch (e) {
  22847. }
  22848. return width;
  22849. }
  22850. /**
  22851. * 获取单元格所在表格的最末单元格的偏移量
  22852. */
  22853. function getTableCellOffset(cell) {
  22854. tab = domUtils.findParentByTagName(cell, "table", false);
  22855. if (tab.offsetVal === undefined) {
  22856. var prev = cell.previousSibling;
  22857. if (prev) {
  22858. //最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
  22859. tab.offsetVal = cell.offsetWidth - prev.offsetWidth === UT.borderWidth
  22860. ? UT.borderWidth
  22861. : 0;
  22862. } else {
  22863. tab.offsetVal = 0;
  22864. }
  22865. }
  22866. return tab.offsetVal;
  22867. }
  22868. function getTabcellSpace() {
  22869. if (UT.tabcellSpace === undefined) {
  22870. var cell = null,
  22871. tab = me.document.createElement("table"),
  22872. tbody = me.document.createElement("tbody"),
  22873. trow = me.document.createElement("tr"),
  22874. tabcell = me.document.createElement("td"),
  22875. mirror = null;
  22876. tabcell.style.cssText = "border: 0;";
  22877. tabcell.width = 1;
  22878. trow.appendChild(tabcell);
  22879. trow.appendChild((mirror = tabcell.cloneNode(false)));
  22880. tbody.appendChild(trow);
  22881. tab.appendChild(tbody);
  22882. tab.style.cssText = "visibility: hidden;";
  22883. me.body.appendChild(tab);
  22884. UT.paddingSpace = tabcell.offsetWidth - 1;
  22885. var tmpTabWidth = tab.offsetWidth;
  22886. tabcell.style.cssText = "";
  22887. mirror.style.cssText = "";
  22888. UT.borderWidth = (tab.offsetWidth - tmpTabWidth) / 3;
  22889. UT.tabcellSpace = UT.paddingSpace + UT.borderWidth;
  22890. me.body.removeChild(tab);
  22891. }
  22892. getTabcellSpace = function () {
  22893. return UT.tabcellSpace;
  22894. };
  22895. return UT.tabcellSpace;
  22896. }
  22897. function getDragLine(editor, doc) {
  22898. if (mousedown) return;
  22899. dragLine = editor.document.createElement("div");
  22900. domUtils.setAttributes(dragLine, {
  22901. id: "ue_tableDragLine",
  22902. unselectable: "on",
  22903. contenteditable: false,
  22904. onresizestart: "return false",
  22905. ondragstart: "return false",
  22906. onselectstart: "return false",
  22907. style:
  22908. "background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)"
  22909. });
  22910. editor.body.appendChild(dragLine);
  22911. }
  22912. function hideDragLine(editor) {
  22913. if (mousedown) return;
  22914. var line;
  22915. while ((line = editor.document.getElementById("ue_tableDragLine"))) {
  22916. domUtils.remove(line);
  22917. }
  22918. }
  22919. /**
  22920. * 依据state(v|h)在cell位置显示横线
  22921. * @param state
  22922. * @param cell
  22923. */
  22924. function showDragLineAt(state, cell) {
  22925. if (!cell) return;
  22926. var table = domUtils.findParentByTagName(cell, "table"),
  22927. caption = table.getElementsByTagName("caption"),
  22928. width = table.offsetWidth,
  22929. height =
  22930. table.offsetHeight - (caption.length > 0 ? caption[0].offsetHeight : 0),
  22931. tablePos = domUtils.getXY(table),
  22932. cellPos = domUtils.getXY(cell),
  22933. css;
  22934. switch (state) {
  22935. case "h":
  22936. css =
  22937. "height:" +
  22938. height +
  22939. "px;top:" +
  22940. (tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) +
  22941. "px;left:" +
  22942. (cellPos.x + cell.offsetWidth);
  22943. dragLine.style.cssText =
  22944. css +
  22945. "px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)";
  22946. break;
  22947. case "v":
  22948. css =
  22949. "width:" +
  22950. width +
  22951. "px;left:" +
  22952. tablePos.x +
  22953. "px;top:" +
  22954. (cellPos.y + cell.offsetHeight);
  22955. //必须加上border:0和color:blue,否则低版ie不支持背景色显示
  22956. dragLine.style.cssText =
  22957. css +
  22958. "px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)";
  22959. break;
  22960. default:
  22961. }
  22962. }
  22963. /**
  22964. * 当表格边框颜色为白色时设置为虚线,true为添加虚线
  22965. * @param editor
  22966. * @param flag
  22967. */
  22968. function switchBorderColor(editor, flag) {
  22969. var tableArr = domUtils.getElementsByTagName(editor.body, "table"),
  22970. color;
  22971. for (var i = 0, node; (node = tableArr[i++]);) {
  22972. var td = domUtils.getElementsByTagName(node, "td");
  22973. if (td[0]) {
  22974. if (flag) {
  22975. color = td[0].style.borderColor.replace(/\s/g, "");
  22976. if (/(#ffffff)|(rgb\(255,255,255\))/gi.test(color))
  22977. domUtils.addClass(node, "noBorderTable");
  22978. } else {
  22979. domUtils.removeClasses(node, "noBorderTable");
  22980. }
  22981. }
  22982. }
  22983. }
  22984. function getTableWidth(editor, needIEHack, defaultValue) {
  22985. var body = editor.body;
  22986. return (
  22987. body.offsetWidth -
  22988. (needIEHack
  22989. ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
  22990. : 0) -
  22991. defaultValue.tableBorder * 2 -
  22992. (editor.options.offsetWidth || 0)
  22993. );
  22994. }
  22995. /**
  22996. * 获取当前拖动的单元格
  22997. */
  22998. function getTargetTd(editor, evt) {
  22999. var target = domUtils.findParentByTagName(
  23000. evt.target || evt.srcElement,
  23001. ["td", "th"],
  23002. true
  23003. ),
  23004. dir = null;
  23005. if (!target) {
  23006. return null;
  23007. }
  23008. dir = getRelation(target, mouseCoords(evt));
  23009. //如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td
  23010. if (!target) {
  23011. return null;
  23012. }
  23013. if (dir === "h1" && target.previousSibling) {
  23014. var position = domUtils.getXY(target),
  23015. cellWidth = target.offsetWidth;
  23016. if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
  23017. target = target.previousSibling;
  23018. }
  23019. } else if (dir === "v1" && target.parentNode.previousSibling) {
  23020. var position = domUtils.getXY(target),
  23021. cellHeight = target.offsetHeight;
  23022. if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
  23023. target = target.parentNode.previousSibling.firstChild;
  23024. }
  23025. }
  23026. //排除了非td内部以及用于代码高亮部分的td
  23027. return target && !(editor.fireEvent("excludetable", target) === true)
  23028. ? target
  23029. : null;
  23030. }
  23031. };
  23032. // plugins/table.sort.js
  23033. /**
  23034. * Created with JetBrains PhpStorm.
  23035. * User: Jinqn
  23036. * Date: 13-10-12
  23037. * Time: 上午10:20
  23038. * To change this template use File | Settings | File Templates.
  23039. */
  23040. UE.UETable.prototype.sortTable = function (sortByCellIndex, compareFn) {
  23041. var table = this.table,
  23042. rows = table.rows,
  23043. trArray = [],
  23044. flag = rows[0].cells[0].tagName === "TH",
  23045. lastRowIndex = 0;
  23046. if (this.selectedTds.length) {
  23047. var range = this.cellsRange,
  23048. len = range.endRowIndex + 1;
  23049. for (var i = range.beginRowIndex; i < len; i++) {
  23050. trArray[i] = rows[i];
  23051. }
  23052. trArray.splice(0, range.beginRowIndex);
  23053. lastRowIndex = range.endRowIndex + 1 === this.rowsNum
  23054. ? 0
  23055. : range.endRowIndex + 1;
  23056. } else {
  23057. for (var i = 0, len = rows.length; i < len; i++) {
  23058. trArray[i] = rows[i];
  23059. }
  23060. }
  23061. var Fn = {
  23062. reversecurrent: function (td1, td2) {
  23063. return 1;
  23064. },
  23065. orderbyasc: function (td1, td2) {
  23066. var value1 = td1.innerText || td1.textContent,
  23067. value2 = td2.innerText || td2.textContent;
  23068. return value1.localeCompare(value2);
  23069. },
  23070. reversebyasc: function (td1, td2) {
  23071. var value1 = td1.innerHTML,
  23072. value2 = td2.innerHTML;
  23073. return value2.localeCompare(value1);
  23074. },
  23075. orderbynum: function (td1, td2) {
  23076. var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
  23077. value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
  23078. if (value1) value1 = +value1[0];
  23079. if (value2) value2 = +value2[0];
  23080. return (value1 || 0) - (value2 || 0);
  23081. },
  23082. reversebynum: function (td1, td2) {
  23083. var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
  23084. value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
  23085. if (value1) value1 = +value1[0];
  23086. if (value2) value2 = +value2[0];
  23087. return (value2 || 0) - (value1 || 0);
  23088. }
  23089. };
  23090. //对表格设置排序的标记data-sort-type
  23091. table.setAttribute(
  23092. "data-sort-type",
  23093. compareFn && typeof compareFn === "string" && Fn[compareFn] ? compareFn : ""
  23094. );
  23095. //th不参与排序
  23096. flag && trArray.splice(0, 1);
  23097. trArray = utils.sort(trArray, function (tr1, tr2) {
  23098. var result;
  23099. if (compareFn && typeof compareFn === "function") {
  23100. result = compareFn.call(
  23101. this,
  23102. tr1.cells[sortByCellIndex],
  23103. tr2.cells[sortByCellIndex]
  23104. );
  23105. } else if (compareFn && typeof compareFn === "number") {
  23106. result = 1;
  23107. } else if (compareFn && typeof compareFn === "string" && Fn[compareFn]) {
  23108. result = Fn[compareFn].call(
  23109. this,
  23110. tr1.cells[sortByCellIndex],
  23111. tr2.cells[sortByCellIndex]
  23112. );
  23113. } else {
  23114. result = Fn["orderbyasc"].call(
  23115. this,
  23116. tr1.cells[sortByCellIndex],
  23117. tr2.cells[sortByCellIndex]
  23118. );
  23119. }
  23120. return result;
  23121. });
  23122. var fragment = table.ownerDocument.createDocumentFragment();
  23123. for (var j = 0, len = trArray.length; j < len; j++) {
  23124. fragment.appendChild(trArray[j]);
  23125. }
  23126. var tbody = table.getElementsByTagName("tbody")[0];
  23127. if (!lastRowIndex) {
  23128. tbody.appendChild(fragment);
  23129. } else {
  23130. tbody.insertBefore(
  23131. fragment,
  23132. rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1]
  23133. );
  23134. }
  23135. };
  23136. UE.plugins["tablesort"] = function () {
  23137. var me = this,
  23138. UT = UE.UETable,
  23139. getUETable = function (tdOrTable) {
  23140. return UT.getUETable(tdOrTable);
  23141. },
  23142. getTableItemsByRange = function (editor) {
  23143. return UT.getTableItemsByRange(editor);
  23144. };
  23145. me.ready(function () {
  23146. //添加表格可排序的样式
  23147. utils.cssRule(
  23148. "tablesort",
  23149. "table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;" +
  23150. " background-image:url(" +
  23151. me.options.themePath +
  23152. me.options.theme +
  23153. "/images/sortable.png);}",
  23154. me.document
  23155. );
  23156. //做单元格合并操作时,清除可排序标识
  23157. me.addListener("afterexeccommand", function (type, cmd) {
  23158. if (cmd == "mergeright" || cmd == "mergedown" || cmd == "mergecells") {
  23159. this.execCommand("disablesort");
  23160. }
  23161. });
  23162. });
  23163. //表格排序
  23164. UE.commands["sorttable"] = {
  23165. queryCommandState: function () {
  23166. var me = this,
  23167. tableItems = getTableItemsByRange(me);
  23168. if (!tableItems.cell) return -1;
  23169. var table = tableItems.table,
  23170. cells = table.getElementsByTagName("td");
  23171. for (var i = 0, cell; (cell = cells[i++]);) {
  23172. if (cell.rowSpan != 1 || cell.colSpan != 1) return -1;
  23173. }
  23174. return 0;
  23175. },
  23176. execCommand: function (cmd, fn) {
  23177. var me = this,
  23178. range = me.selection.getRange(),
  23179. bk = range.createBookmark(true),
  23180. tableItems = getTableItemsByRange(me),
  23181. cell = tableItems.cell,
  23182. ut = getUETable(tableItems.table),
  23183. cellInfo = ut.getCellInfo(cell);
  23184. ut.sortTable(cellInfo.cellIndex, fn);
  23185. range.moveToBookmark(bk);
  23186. try {
  23187. range.select();
  23188. } catch (e) {
  23189. }
  23190. }
  23191. };
  23192. //设置表格可排序,清除表格可排序
  23193. UE.commands["enablesort"] = UE.commands["disablesort"] = {
  23194. queryCommandState: function (cmd) {
  23195. var table = getTableItemsByRange(this).table;
  23196. if (table && cmd == "enablesort") {
  23197. var cells = domUtils.getElementsByTagName(table, "th td");
  23198. for (var i = 0; i < cells.length; i++) {
  23199. if (
  23200. cells[i].getAttribute("colspan") > 1 ||
  23201. cells[i].getAttribute("rowspan") > 1
  23202. )
  23203. return -1;
  23204. }
  23205. }
  23206. return !table
  23207. ? -1
  23208. : (cmd == "enablesort") ^
  23209. (table.getAttribute("data-sort") != "sortEnabled")
  23210. ? -1
  23211. : 0;
  23212. },
  23213. execCommand: function (cmd) {
  23214. var table = getTableItemsByRange(this).table;
  23215. table.setAttribute(
  23216. "data-sort",
  23217. cmd == "enablesort" ? "sortEnabled" : "sortDisabled"
  23218. );
  23219. table.setAttribute("style", "border-collapse:collapse;");
  23220. cmd == "enablesort"
  23221. ? domUtils.addClass(table, "sortEnabled")
  23222. : domUtils.removeClasses(table, "sortEnabled");
  23223. }
  23224. };
  23225. };
  23226. // plugins/contextmenu.js
  23227. ///import core
  23228. ///commands 右键菜单
  23229. ///commandsName ContextMenu
  23230. ///commandsTitle 右键菜单
  23231. /**
  23232. * 右键菜单
  23233. * @function
  23234. * @name baidu.editor.plugins.contextmenu
  23235. * @author zhanyi
  23236. */
  23237. UE.plugins["contextmenu"] = function () {
  23238. var me = this;
  23239. me.setOpt("enableContextMenu", me.getOpt("enableContextMenu") || true);
  23240. if (me.getOpt("enableContextMenu") === false) {
  23241. return;
  23242. }
  23243. var lang = me.getLang("contextMenu"),
  23244. menu,
  23245. items = me.options.contextMenu || [
  23246. {label: lang["selectall"], cmdName: "selectall"},
  23247. {
  23248. label: lang.cleardoc,
  23249. cmdName: "cleardoc",
  23250. exec: function () {
  23251. if (confirm(lang.confirmclear)) {
  23252. this.execCommand("cleardoc");
  23253. }
  23254. }
  23255. },
  23256. "-",
  23257. {
  23258. label: lang.unlink,
  23259. cmdName: "unlink"
  23260. },
  23261. "-",
  23262. {
  23263. group: lang.paragraph,
  23264. icon: "justifyjustify",
  23265. subMenu: [
  23266. {
  23267. label: lang.justifyleft,
  23268. cmdName: "justify",
  23269. value: "left"
  23270. },
  23271. {
  23272. label: lang.justifyright,
  23273. cmdName: "justify",
  23274. value: "right"
  23275. },
  23276. {
  23277. label: lang.justifycenter,
  23278. cmdName: "justify",
  23279. value: "center"
  23280. },
  23281. {
  23282. label: lang.justifyjustify,
  23283. cmdName: "justify",
  23284. value: "justify"
  23285. }
  23286. ]
  23287. },
  23288. "-",
  23289. {
  23290. group: lang.table,
  23291. icon: "table",
  23292. subMenu: [
  23293. {
  23294. label: lang.inserttable,
  23295. cmdName: "inserttable"
  23296. },
  23297. {
  23298. label: lang.deletetable,
  23299. cmdName: "deletetable"
  23300. },
  23301. "-",
  23302. {
  23303. label: lang.deleterow,
  23304. cmdName: "deleterow"
  23305. },
  23306. {
  23307. label: lang.deletecol,
  23308. cmdName: "deletecol"
  23309. },
  23310. {
  23311. label: lang.insertcol,
  23312. cmdName: "insertcol"
  23313. },
  23314. {
  23315. label: lang.insertcolnext,
  23316. cmdName: "insertcolnext"
  23317. },
  23318. {
  23319. label: lang.insertrow,
  23320. cmdName: "insertrow"
  23321. },
  23322. {
  23323. label: lang.insertrownext,
  23324. cmdName: "insertrownext"
  23325. },
  23326. "-",
  23327. {
  23328. label: lang.insertcaption,
  23329. cmdName: "insertcaption"
  23330. },
  23331. {
  23332. label: lang.deletecaption,
  23333. cmdName: "deletecaption"
  23334. },
  23335. {
  23336. label: lang.inserttitle,
  23337. cmdName: "inserttitle"
  23338. },
  23339. {
  23340. label: lang.deletetitle,
  23341. cmdName: "deletetitle"
  23342. },
  23343. {
  23344. label: lang.inserttitlecol,
  23345. cmdName: "inserttitlecol"
  23346. },
  23347. {
  23348. label: lang.deletetitlecol,
  23349. cmdName: "deletetitlecol"
  23350. },
  23351. "-",
  23352. {
  23353. label: lang.mergecells,
  23354. cmdName: "mergecells"
  23355. },
  23356. {
  23357. label: lang.mergeright,
  23358. cmdName: "mergeright"
  23359. },
  23360. {
  23361. label: lang.mergedown,
  23362. cmdName: "mergedown"
  23363. },
  23364. "-",
  23365. {
  23366. label: lang.splittorows,
  23367. cmdName: "splittorows"
  23368. },
  23369. {
  23370. label: lang.splittocols,
  23371. cmdName: "splittocols"
  23372. },
  23373. {
  23374. label: lang.splittocells,
  23375. cmdName: "splittocells"
  23376. },
  23377. "-",
  23378. {
  23379. label: lang.averageDiseRow,
  23380. cmdName: "averagedistributerow"
  23381. },
  23382. {
  23383. label: lang.averageDisCol,
  23384. cmdName: "averagedistributecol"
  23385. },
  23386. "-",
  23387. {
  23388. label: lang.edittd,
  23389. cmdName: "edittd",
  23390. exec: function () {
  23391. if (UE.ui["edittd"]) {
  23392. new UE.ui["edittd"](this);
  23393. }
  23394. this.getDialog("edittd").open();
  23395. }
  23396. },
  23397. {
  23398. label: lang.edittable,
  23399. cmdName: "edittable",
  23400. exec: function () {
  23401. if (UE.ui["edittable"]) {
  23402. new UE.ui["edittable"](this);
  23403. }
  23404. this.getDialog("edittable").open();
  23405. }
  23406. },
  23407. {
  23408. label: lang.setbordervisible,
  23409. cmdName: "setbordervisible"
  23410. }
  23411. ]
  23412. },
  23413. {
  23414. group: lang.tablesort,
  23415. icon: "tablesort",
  23416. subMenu: [
  23417. {
  23418. label: lang.enablesort,
  23419. cmdName: "enablesort"
  23420. },
  23421. {
  23422. label: lang.disablesort,
  23423. cmdName: "disablesort"
  23424. },
  23425. "-",
  23426. {
  23427. label: lang.reversecurrent,
  23428. cmdName: "sorttable",
  23429. value: "reversecurrent"
  23430. },
  23431. {
  23432. label: lang.orderbyasc,
  23433. cmdName: "sorttable",
  23434. value: "orderbyasc"
  23435. },
  23436. {
  23437. label: lang.reversebyasc,
  23438. cmdName: "sorttable",
  23439. value: "reversebyasc"
  23440. },
  23441. {
  23442. label: lang.orderbynum,
  23443. cmdName: "sorttable",
  23444. value: "orderbynum"
  23445. },
  23446. {
  23447. label: lang.reversebynum,
  23448. cmdName: "sorttable",
  23449. value: "reversebynum"
  23450. }
  23451. ]
  23452. },
  23453. {
  23454. group: lang.borderbk,
  23455. icon: "borderBack",
  23456. subMenu: [
  23457. {
  23458. label: lang.setcolor,
  23459. cmdName: "interlacetable",
  23460. exec: function () {
  23461. this.execCommand("interlacetable");
  23462. }
  23463. },
  23464. {
  23465. label: lang.unsetcolor,
  23466. cmdName: "uninterlacetable",
  23467. exec: function () {
  23468. this.execCommand("uninterlacetable");
  23469. }
  23470. },
  23471. {
  23472. label: lang.setbackground,
  23473. cmdName: "settablebackground",
  23474. exec: function () {
  23475. this.execCommand("settablebackground", {
  23476. repeat: true,
  23477. colorList: ["#bbb", "#ccc"]
  23478. });
  23479. }
  23480. },
  23481. {
  23482. label: lang.unsetbackground,
  23483. cmdName: "cleartablebackground",
  23484. exec: function () {
  23485. this.execCommand("cleartablebackground");
  23486. }
  23487. },
  23488. {
  23489. label: lang.redandblue,
  23490. cmdName: "settablebackground",
  23491. exec: function () {
  23492. this.execCommand("settablebackground", {
  23493. repeat: true,
  23494. colorList: ["red", "blue"]
  23495. });
  23496. }
  23497. },
  23498. {
  23499. label: lang.threecolorgradient,
  23500. cmdName: "settablebackground",
  23501. exec: function () {
  23502. this.execCommand("settablebackground", {
  23503. repeat: true,
  23504. colorList: ["#aaa", "#bbb", "#ccc"]
  23505. });
  23506. }
  23507. }
  23508. ]
  23509. },
  23510. {
  23511. group: lang.aligntd,
  23512. icon: "aligntd",
  23513. subMenu: [
  23514. {
  23515. cmdName: "cellalignment",
  23516. value: {align: "left", vAlign: "top"}
  23517. },
  23518. {
  23519. cmdName: "cellalignment",
  23520. value: {align: "center", vAlign: "top"}
  23521. },
  23522. {
  23523. cmdName: "cellalignment",
  23524. value: {align: "right", vAlign: "top"}
  23525. },
  23526. {
  23527. cmdName: "cellalignment",
  23528. value: {align: "left", vAlign: "middle"}
  23529. },
  23530. {
  23531. cmdName: "cellalignment",
  23532. value: {align: "center", vAlign: "middle"}
  23533. },
  23534. {
  23535. cmdName: "cellalignment",
  23536. value: {align: "right", vAlign: "middle"}
  23537. },
  23538. {
  23539. cmdName: "cellalignment",
  23540. value: {align: "left", vAlign: "bottom"}
  23541. },
  23542. {
  23543. cmdName: "cellalignment",
  23544. value: {align: "center", vAlign: "bottom"}
  23545. },
  23546. {
  23547. cmdName: "cellalignment",
  23548. value: {align: "right", vAlign: "bottom"}
  23549. }
  23550. ]
  23551. },
  23552. {
  23553. group: lang.aligntable,
  23554. icon: "aligntable",
  23555. subMenu: [
  23556. {
  23557. cmdName: "tablealignment",
  23558. className: "left",
  23559. label: lang.tableleft,
  23560. value: "left"
  23561. },
  23562. {
  23563. cmdName: "tablealignment",
  23564. className: "center",
  23565. label: lang.tablecenter,
  23566. value: "center"
  23567. },
  23568. {
  23569. cmdName: "tablealignment",
  23570. className: "right",
  23571. label: lang.tableright,
  23572. value: "right"
  23573. }
  23574. ]
  23575. },
  23576. "-",
  23577. {
  23578. label: lang.insertparagraphbefore,
  23579. cmdName: "insertparagraph",
  23580. value: true
  23581. },
  23582. {
  23583. label: lang.insertparagraphafter,
  23584. cmdName: "insertparagraph"
  23585. },
  23586. {
  23587. label: lang["copy"],
  23588. cmdName: "copy"
  23589. },
  23590. {
  23591. label: lang["paste"],
  23592. cmdName: "paste"
  23593. }
  23594. ];
  23595. if (!items.length) {
  23596. return;
  23597. }
  23598. var uiUtils = UE.ui.uiUtils;
  23599. me.addListener("contextmenu", function (type, evt) {
  23600. var offset = uiUtils.getViewportOffsetByEvent(evt);
  23601. me.fireEvent("beforeselectionchange");
  23602. if (menu) {
  23603. menu.destroy();
  23604. }
  23605. for (var i = 0, ti, contextItems = []; (ti = items[i]); i++) {
  23606. var last;
  23607. (function (item) {
  23608. if (item == "-") {
  23609. if ((last = contextItems[contextItems.length - 1]) && last !== "-") {
  23610. contextItems.push("-");
  23611. }
  23612. } else if (item.hasOwnProperty("group")) {
  23613. for (var j = 0, cj, subMenu = []; (cj = item.subMenu[j]); j++) {
  23614. (function (subItem) {
  23615. if (subItem == "-") {
  23616. if ((last = subMenu[subMenu.length - 1]) && last !== "-") {
  23617. subMenu.push("-");
  23618. } else {
  23619. subMenu.splice(subMenu.length - 1);
  23620. }
  23621. } else {
  23622. if (
  23623. (me.commands[subItem.cmdName] ||
  23624. UE.commands[subItem.cmdName] ||
  23625. subItem.query) &&
  23626. (subItem.query
  23627. ? subItem.query()
  23628. : me.queryCommandState(subItem.cmdName)) > -1
  23629. ) {
  23630. subMenu.push({
  23631. label:
  23632. subItem.label ||
  23633. me.getLang(
  23634. "contextMenu." +
  23635. subItem.cmdName +
  23636. (subItem.value || "")
  23637. ) ||
  23638. "",
  23639. className:
  23640. "edui-for-" +
  23641. subItem.cmdName +
  23642. (subItem.className
  23643. ? " edui-for-" +
  23644. subItem.cmdName +
  23645. "-" +
  23646. subItem.className
  23647. : ""),
  23648. onclick: subItem.exec
  23649. ? function () {
  23650. subItem.exec.call(me);
  23651. }
  23652. : function () {
  23653. me.execCommand(subItem.cmdName, subItem.value);
  23654. }
  23655. });
  23656. }
  23657. }
  23658. })(cj);
  23659. }
  23660. if (subMenu.length) {
  23661. function getLabel() {
  23662. switch (item.icon) {
  23663. case "table":
  23664. return me.getLang("contextMenu.table");
  23665. case "justifyjustify":
  23666. return me.getLang("contextMenu.paragraph");
  23667. case "aligntd":
  23668. return me.getLang("contextMenu.aligntd");
  23669. case "aligntable":
  23670. return me.getLang("contextMenu.aligntable");
  23671. case "tablesort":
  23672. return lang.tablesort;
  23673. case "borderBack":
  23674. return lang.borderbk;
  23675. default:
  23676. return "";
  23677. }
  23678. }
  23679. contextItems.push({
  23680. //todo 修正成自动获取方式
  23681. label: getLabel(),
  23682. className: "edui-for-" + item.icon,
  23683. subMenu: {
  23684. items: subMenu,
  23685. editor: me
  23686. }
  23687. });
  23688. }
  23689. } else {
  23690. //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
  23691. if (
  23692. (me.commands[item.cmdName] ||
  23693. UE.commands[item.cmdName] ||
  23694. item.query) &&
  23695. (item.query
  23696. ? item.query.call(me)
  23697. : me.queryCommandState(item.cmdName)) > -1
  23698. ) {
  23699. contextItems.push({
  23700. label: item.label || me.getLang("contextMenu." + item.cmdName),
  23701. className:
  23702. "edui-for-" +
  23703. (item.icon ? item.icon : item.cmdName + (item.value || "")),
  23704. onclick: item.exec
  23705. ? function () {
  23706. item.exec.call(me);
  23707. }
  23708. : function () {
  23709. me.execCommand(item.cmdName, item.value);
  23710. }
  23711. });
  23712. }
  23713. }
  23714. })(ti);
  23715. }
  23716. if (contextItems[contextItems.length - 1] == "-") {
  23717. contextItems.pop();
  23718. }
  23719. menu = new UE.ui.Menu({
  23720. items: contextItems,
  23721. className: "edui-contextmenu",
  23722. editor: me
  23723. });
  23724. menu.render();
  23725. menu.showAt(offset);
  23726. me.fireEvent("aftershowcontextmenu", menu);
  23727. domUtils.preventDefault(evt);
  23728. if (browser.ie) {
  23729. var ieRange;
  23730. try {
  23731. ieRange = me.selection.getNative().createRange();
  23732. } catch (e) {
  23733. return;
  23734. }
  23735. if (ieRange.item) {
  23736. var range = new dom.Range(me.document);
  23737. range.selectNode(ieRange.item(0)).select(true, true);
  23738. }
  23739. }
  23740. });
  23741. // 添加复制的flash按钮
  23742. me.addListener("aftershowcontextmenu", function (type, menu) {
  23743. if (me.zeroclipboard) {
  23744. var items = menu.items;
  23745. for (var key in items) {
  23746. if (items[key].className == "edui-for-copy") {
  23747. me.zeroclipboard.clip(items[key].getDom());
  23748. }
  23749. }
  23750. }
  23751. });
  23752. };
  23753. // plugins/shortcutmenu.js
  23754. ///import core
  23755. ///commands 弹出菜单
  23756. // commandsName popupmenu
  23757. ///commandsTitle 弹出菜单
  23758. /**
  23759. * 弹出菜单
  23760. * @function
  23761. * @name baidu.editor.plugins.popupmenu
  23762. * @author xuheng
  23763. */
  23764. UE.plugins["shortcutmenu"] = function () {
  23765. var me = this,
  23766. menu,
  23767. items = me.options.shortcutMenu || [];
  23768. if (!items.length) {
  23769. return;
  23770. }
  23771. me.addListener("contextmenu mouseup", function (type, e) {
  23772. var me = this,
  23773. customEvt = {
  23774. type: type,
  23775. target: e.target || e.srcElement,
  23776. screenX: e.screenX,
  23777. screenY: e.screenY,
  23778. clientX: e.clientX,
  23779. clientY: e.clientY
  23780. };
  23781. setTimeout(function () {
  23782. var rng = me.selection.getRange();
  23783. if (rng.collapsed === false || type == "contextmenu") {
  23784. if (!menu) {
  23785. menu = new baidu.editor.ui.ShortCutMenu({
  23786. editor: me,
  23787. items: items,
  23788. theme: me.options.theme,
  23789. className: "edui-shortcutmenu"
  23790. });
  23791. menu.render();
  23792. me.fireEvent("afterrendershortcutmenu", menu);
  23793. }
  23794. menu.show(customEvt, !!UE.plugins["contextmenu"]);
  23795. }
  23796. });
  23797. if (type == "contextmenu") {
  23798. domUtils.preventDefault(e);
  23799. if (browser.ie9below) {
  23800. var ieRange;
  23801. try {
  23802. ieRange = me.selection.getNative().createRange();
  23803. } catch (e) {
  23804. return;
  23805. }
  23806. if (ieRange.item) {
  23807. var range = new dom.Range(me.document);
  23808. range.selectNode(ieRange.item(0)).select(true, true);
  23809. }
  23810. }
  23811. }
  23812. });
  23813. me.addListener("keydown", function (type) {
  23814. if (type == "keydown") {
  23815. menu && !menu.isHidden && menu.hide();
  23816. }
  23817. });
  23818. };
  23819. // plugins/basestyle.js
  23820. /**
  23821. * B、I、sub、super命令支持
  23822. * @file
  23823. * @since 1.2.6.1
  23824. */
  23825. UE.plugins["basestyle"] = function () {
  23826. /**
  23827. * 字体加粗
  23828. * @command bold
  23829. * @param { String } cmd 命令字符串
  23830. * @remind 对已加粗的文本内容执行该命令, 将取消加粗
  23831. * @method execCommand
  23832. * @example
  23833. * ```javascript
  23834. * //editor是编辑器实例
  23835. * //对当前选中的文本内容执行加粗操作
  23836. * //第一次执行, 文本内容加粗
  23837. * editor.execCommand( 'bold' );
  23838. *
  23839. * //第二次执行, 文本内容取消加粗
  23840. * editor.execCommand( 'bold' );
  23841. * ```
  23842. */
  23843. /**
  23844. * 字体倾斜
  23845. * @command italic
  23846. * @method execCommand
  23847. * @param { String } cmd 命令字符串
  23848. * @remind 对已倾斜的文本内容执行该命令, 将取消倾斜
  23849. * @example
  23850. * ```javascript
  23851. * //editor是编辑器实例
  23852. * //对当前选中的文本内容执行斜体操作
  23853. * //第一次操作, 文本内容将变成斜体
  23854. * editor.execCommand( 'italic' );
  23855. *
  23856. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23857. * editor.execCommand( 'italic' );
  23858. * ```
  23859. */
  23860. /**
  23861. * 下标文本,与“superscript”命令互斥
  23862. * @command subscript
  23863. * @method execCommand
  23864. * @remind 把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本
  23865. * @param { String } cmd 命令字符串
  23866. * @example
  23867. * ```javascript
  23868. * //editor是编辑器实例
  23869. * //对当前选中的文本内容执行下标操作
  23870. * //第一次操作, 文本内容将变成下标文本
  23871. * editor.execCommand( 'subscript' );
  23872. *
  23873. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23874. * editor.execCommand( 'subscript' );
  23875. * ```
  23876. */
  23877. /**
  23878. * 上标文本,与“subscript”命令互斥
  23879. * @command superscript
  23880. * @method execCommand
  23881. * @remind 把选中的文本内容切换成上标文本, 如果当前选中的文本已经是上标, 则该操作会把文本内容还原成正常文本
  23882. * @param { String } cmd 命令字符串
  23883. * @example
  23884. * ```javascript
  23885. * //editor是编辑器实例
  23886. * //对当前选中的文本内容执行上标操作
  23887. * //第一次操作, 文本内容将变成上标文本
  23888. * editor.execCommand( 'superscript' );
  23889. *
  23890. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23891. * editor.execCommand( 'superscript' );
  23892. * ```
  23893. */
  23894. var basestyles = {
  23895. bold: ["strong", "b"],
  23896. italic: ["em", "i"],
  23897. subscript: ["sub"],
  23898. superscript: ["sup"]
  23899. },
  23900. getObj = function (editor, tagNames) {
  23901. return domUtils.filterNodeList(
  23902. editor.selection.getStartElementPath(),
  23903. tagNames
  23904. );
  23905. },
  23906. me = this;
  23907. //添加快捷键
  23908. me.addshortcutkey({
  23909. Bold: "ctrl+66", //^B
  23910. Italic: "ctrl+73", //^I
  23911. Underline: "ctrl+85" //^U
  23912. });
  23913. me.addInputRule(function (root) {
  23914. utils.each(root.getNodesByTagName("b i"), function (node) {
  23915. switch (node.tagName) {
  23916. case "b":
  23917. node.tagName = "strong";
  23918. break;
  23919. case "i":
  23920. node.tagName = "em";
  23921. }
  23922. });
  23923. });
  23924. for (var style in basestyles) {
  23925. (function (cmd, tagNames) {
  23926. me.commands[cmd] = {
  23927. execCommand: function (cmdName) {
  23928. var range = me.selection.getRange(),
  23929. obj = getObj(this, tagNames);
  23930. if (range.collapsed) {
  23931. if (obj) {
  23932. var tmpText = me.document.createTextNode("");
  23933. range.insertNode(tmpText).removeInlineStyle(tagNames);
  23934. range.setStartBefore(tmpText);
  23935. domUtils.remove(tmpText);
  23936. } else {
  23937. var tmpNode = range.document.createElement(tagNames[0]);
  23938. if (cmdName == "superscript" || cmdName == "subscript") {
  23939. tmpText = me.document.createTextNode("");
  23940. range
  23941. .insertNode(tmpText)
  23942. .removeInlineStyle(["sub", "sup"])
  23943. .setStartBefore(tmpText)
  23944. .collapse(true);
  23945. }
  23946. range.insertNode(tmpNode).setStart(tmpNode, 0);
  23947. }
  23948. range.collapse(true);
  23949. } else {
  23950. if (cmdName == "superscript" || cmdName == "subscript") {
  23951. if (!obj || obj.tagName.toLowerCase() != cmdName) {
  23952. range.removeInlineStyle(["sub", "sup"]);
  23953. }
  23954. }
  23955. obj
  23956. ? range.removeInlineStyle(tagNames)
  23957. : range.applyInlineStyle(tagNames[0]);
  23958. }
  23959. range.select();
  23960. },
  23961. queryCommandState: function () {
  23962. return getObj(this, tagNames) ? 1 : 0;
  23963. }
  23964. };
  23965. })(style, basestyles[style]);
  23966. }
  23967. };
  23968. // plugins/elementpath.js
  23969. /**
  23970. * 选取路径命令
  23971. * @file
  23972. */
  23973. UE.plugins["elementpath"] = function () {
  23974. var currentLevel,
  23975. tagNames,
  23976. me = this;
  23977. me.setOpt("elementPathEnabled", true);
  23978. if (!me.options.elementPathEnabled) {
  23979. return;
  23980. }
  23981. me.commands["elementpath"] = {
  23982. execCommand: function (cmdName, level) {
  23983. var start = tagNames[level],
  23984. range = me.selection.getRange();
  23985. currentLevel = level * 1;
  23986. range.selectNode(start).select();
  23987. },
  23988. queryCommandValue: function () {
  23989. //产生一个副本,不能修改原来的startElementPath;
  23990. var parents = [].concat(this.selection.getStartElementPath()).reverse(),
  23991. names = [];
  23992. tagNames = parents;
  23993. for (var i = 0, ci; (ci = parents[i]); i++) {
  23994. if (ci.nodeType == 3) {
  23995. continue;
  23996. }
  23997. var name = ci.tagName.toLowerCase();
  23998. if (name == "img" && ci.getAttribute("anchorname")) {
  23999. name = "anchor";
  24000. }
  24001. names[i] = name;
  24002. if (currentLevel == i) {
  24003. currentLevel = -1;
  24004. break;
  24005. }
  24006. }
  24007. return names;
  24008. }
  24009. };
  24010. };
  24011. // plugins/formatmatch.js
  24012. /**
  24013. * 格式刷,只格式inline的
  24014. * @file
  24015. * @since 1.2.6.1
  24016. */
  24017. /**
  24018. * 格式刷
  24019. * @command formatmatch
  24020. * @method execCommand
  24021. * @remind 该操作不能复制段落格式
  24022. * @param { String } cmd 命令字符串
  24023. * @example
  24024. * ```javascript
  24025. * //editor是编辑器实例
  24026. * //获取格式刷
  24027. * editor.execCommand( 'formatmatch' );
  24028. * ```
  24029. */
  24030. UE.plugins["formatmatch"] = function () {
  24031. var me = this,
  24032. list = [],
  24033. img,
  24034. flag = 0;
  24035. me.addListener("reset", function () {
  24036. list = [];
  24037. flag = 0;
  24038. });
  24039. function addList(type, evt) {
  24040. if (browser.webkit) {
  24041. var target = evt.target.tagName == "IMG" ? evt.target : null;
  24042. }
  24043. function addFormat(range) {
  24044. if (text) {
  24045. range.selectNode(text);
  24046. }
  24047. return range.applyInlineStyle(list[list.length - 1].tagName, null, list);
  24048. }
  24049. me.undoManger && me.undoManger.save();
  24050. var range = me.selection.getRange(),
  24051. imgT = target || range.getClosedNode();
  24052. if (img && imgT && imgT.tagName == "IMG") {
  24053. //trace:964
  24054. imgT.style.cssText +=
  24055. ";float:" +
  24056. (img.style.cssFloat || img.style.styleFloat || "none") +
  24057. ";display:" +
  24058. (img.style.display || "inline");
  24059. img = null;
  24060. } else {
  24061. if (!img) {
  24062. var collapsed = range.collapsed;
  24063. if (collapsed) {
  24064. var text = me.document.createTextNode("match");
  24065. range.insertNode(text).select();
  24066. }
  24067. me.__hasEnterExecCommand = true;
  24068. //不能把block上的属性干掉
  24069. //trace:1553
  24070. var removeFormatAttributes = me.options.removeFormatAttributes;
  24071. me.options.removeFormatAttributes = "";
  24072. me.execCommand("removeformat");
  24073. me.options.removeFormatAttributes = removeFormatAttributes;
  24074. me.__hasEnterExecCommand = false;
  24075. //trace:969
  24076. range = me.selection.getRange();
  24077. if (list.length) {
  24078. addFormat(range);
  24079. }
  24080. if (text) {
  24081. range.setStartBefore(text).collapse(true);
  24082. }
  24083. range.select();
  24084. text && domUtils.remove(text);
  24085. }
  24086. }
  24087. me.undoManger && me.undoManger.save();
  24088. me.removeListener("mouseup", addList);
  24089. flag = 0;
  24090. }
  24091. me.commands["formatmatch"] = {
  24092. execCommand: function (cmdName) {
  24093. if (flag) {
  24094. flag = 0;
  24095. list = [];
  24096. me.removeListener("mouseup", addList);
  24097. return;
  24098. }
  24099. var range = me.selection.getRange();
  24100. img = range.getClosedNode();
  24101. if (!img || img.tagName != "IMG") {
  24102. range.collapse(true).shrinkBoundary();
  24103. var start = range.startContainer;
  24104. list = domUtils.findParents(start, true, function (node) {
  24105. return !domUtils.isBlockElm(node) && node.nodeType == 1;
  24106. });
  24107. //a不能加入格式刷, 并且克隆节点
  24108. for (var i = 0, ci; (ci = list[i]); i++) {
  24109. if (ci.tagName == "A") {
  24110. list.splice(i, 1);
  24111. break;
  24112. }
  24113. }
  24114. }
  24115. me.addListener("mouseup", addList);
  24116. flag = 1;
  24117. },
  24118. queryCommandState: function () {
  24119. return flag;
  24120. },
  24121. notNeedUndo: 1
  24122. };
  24123. };
  24124. // plugins/searchreplace.js
  24125. ///import core
  24126. ///commands 查找替换
  24127. ///commandsName SearchReplace
  24128. ///commandsTitle 查询替换
  24129. ///commandsDialog dialogs\searchreplace
  24130. /**
  24131. * @description 查找替换
  24132. * @author zhanyi
  24133. */
  24134. UE.plugin.register("searchreplace", function () {
  24135. var me = this;
  24136. var _blockElm = {table: 1, tbody: 1, tr: 1, ol: 1, ul: 1};
  24137. var lastRng = null;
  24138. function getText(node) {
  24139. var text = node.nodeType == 3
  24140. ? node.nodeValue
  24141. : node[browser.ie ? "innerText" : "textContent"];
  24142. return text.replace(domUtils.fillChar, "");
  24143. }
  24144. function findTextInString(textContent, opt, currentIndex) {
  24145. var str = opt.searchStr;
  24146. var reg = new RegExp(str, "g" + (opt.casesensitive ? "" : "i")),
  24147. match;
  24148. if (opt.dir == -1) {
  24149. textContent = textContent.substr(0, currentIndex);
  24150. textContent = textContent.split("").reverse().join("");
  24151. str = str.split("").reverse().join("");
  24152. match = reg.exec(textContent);
  24153. if (match) {
  24154. return currentIndex - match.index - str.length;
  24155. }
  24156. } else {
  24157. textContent = textContent.substr(currentIndex);
  24158. match = reg.exec(textContent);
  24159. if (match) {
  24160. return match.index + currentIndex;
  24161. }
  24162. }
  24163. return -1;
  24164. }
  24165. function findTextBlockElm(node, currentIndex, opt) {
  24166. var textContent,
  24167. index,
  24168. methodName = opt.all || opt.dir == 1 ? "getNextDomNode" : "getPreDomNode";
  24169. if (domUtils.isBody(node)) {
  24170. node = node.firstChild;
  24171. }
  24172. var first = 1;
  24173. while (node) {
  24174. textContent = getText(node);
  24175. index = findTextInString(textContent, opt, currentIndex);
  24176. first = 0;
  24177. if (index != -1) {
  24178. return {
  24179. node: node,
  24180. index: index
  24181. };
  24182. }
  24183. node = domUtils[methodName](node);
  24184. while (node && _blockElm[node.nodeName.toLowerCase()]) {
  24185. node = domUtils[methodName](node, true);
  24186. }
  24187. if (node) {
  24188. currentIndex = opt.dir == -1 ? getText(node).length : 0;
  24189. }
  24190. }
  24191. }
  24192. function findNTextInBlockElm(node, index, str) {
  24193. var currentIndex = 0,
  24194. currentNode = node.firstChild,
  24195. currentNodeLength = 0,
  24196. result;
  24197. while (currentNode) {
  24198. if (currentNode.nodeType == 3) {
  24199. currentNodeLength = getText(currentNode).replace(
  24200. /(^[\t\r\n]+)|([\t\r\n]+$)/,
  24201. ""
  24202. ).length;
  24203. currentIndex += currentNodeLength;
  24204. if (currentIndex >= index) {
  24205. return {
  24206. node: currentNode,
  24207. index: currentNodeLength - (currentIndex - index)
  24208. };
  24209. }
  24210. } else if (!dtd.$empty[currentNode.tagName]) {
  24211. currentNodeLength = getText(currentNode).replace(
  24212. /(^[\t\r\n]+)|([\t\r\n]+$)/,
  24213. ""
  24214. ).length;
  24215. currentIndex += currentNodeLength;
  24216. if (currentIndex >= index) {
  24217. result = findNTextInBlockElm(
  24218. currentNode,
  24219. currentNodeLength - (currentIndex - index),
  24220. str
  24221. );
  24222. if (result) {
  24223. return result;
  24224. }
  24225. }
  24226. }
  24227. currentNode = domUtils.getNextDomNode(currentNode);
  24228. }
  24229. }
  24230. function searchReplace(me, opt) {
  24231. var rng = lastRng || me.selection.getRange(),
  24232. startBlockNode,
  24233. searchStr = opt.searchStr,
  24234. span = me.document.createElement("span");
  24235. span.innerHTML = "$$ueditor_searchreplace_key$$";
  24236. rng.shrinkBoundary(true);
  24237. //判断是不是第一次选中
  24238. if (!rng.collapsed) {
  24239. rng.select();
  24240. var rngText = me.selection.getText();
  24241. if (
  24242. new RegExp(
  24243. "^" + opt.searchStr + "$",
  24244. opt.casesensitive ? "" : "i"
  24245. ).test(rngText)
  24246. ) {
  24247. if (opt.replaceStr != undefined) {
  24248. replaceText(rng, opt.replaceStr);
  24249. rng.select();
  24250. return true;
  24251. } else {
  24252. rng.collapse(opt.dir == -1);
  24253. }
  24254. }
  24255. }
  24256. rng.insertNode(span);
  24257. rng.enlargeToBlockElm(true);
  24258. startBlockNode = rng.startContainer;
  24259. var currentIndex = getText(startBlockNode).indexOf(
  24260. "$$ueditor_searchreplace_key$$"
  24261. );
  24262. rng.setStartBefore(span);
  24263. domUtils.remove(span);
  24264. var result = findTextBlockElm(startBlockNode, currentIndex, opt);
  24265. if (result) {
  24266. var rngStart = findNTextInBlockElm(result.node, result.index, searchStr);
  24267. var rngEnd = findNTextInBlockElm(
  24268. result.node,
  24269. result.index + searchStr.length,
  24270. searchStr
  24271. );
  24272. rng
  24273. .setStart(rngStart.node, rngStart.index)
  24274. .setEnd(rngEnd.node, rngEnd.index);
  24275. if (opt.replaceStr !== undefined) {
  24276. replaceText(rng, opt.replaceStr);
  24277. }
  24278. rng.select();
  24279. return true;
  24280. } else {
  24281. rng.setCursor();
  24282. }
  24283. }
  24284. function replaceText(rng, str) {
  24285. str = me.document.createTextNode(str);
  24286. rng.deleteContents().insertNode(str);
  24287. }
  24288. return {
  24289. commands: {
  24290. searchreplace: {
  24291. execCommand: function (cmdName, opt) {
  24292. utils.extend(
  24293. opt,
  24294. {
  24295. all: false,
  24296. casesensitive: false,
  24297. dir: 1
  24298. },
  24299. true
  24300. );
  24301. var num = 0;
  24302. if (opt.all) {
  24303. lastRng = null;
  24304. var rng = me.selection.getRange(),
  24305. first = me.body.firstChild;
  24306. if (first && first.nodeType == 1) {
  24307. rng.setStart(first, 0);
  24308. rng.shrinkBoundary(true);
  24309. } else if (first.nodeType == 3) {
  24310. rng.setStartBefore(first);
  24311. }
  24312. rng.collapse(true).select(true);
  24313. if (opt.replaceStr !== undefined) {
  24314. me.fireEvent("saveScene");
  24315. }
  24316. while (searchReplace(this, opt)) {
  24317. num++;
  24318. lastRng = me.selection.getRange();
  24319. lastRng.collapse(opt.dir == -1);
  24320. }
  24321. if (num) {
  24322. me.fireEvent("saveScene");
  24323. }
  24324. } else {
  24325. if (opt.replaceStr !== undefined) {
  24326. me.fireEvent("saveScene");
  24327. }
  24328. if (searchReplace(this, opt)) {
  24329. num++;
  24330. lastRng = me.selection.getRange();
  24331. lastRng.collapse(opt.dir == -1);
  24332. }
  24333. if (num) {
  24334. me.fireEvent("saveScene");
  24335. }
  24336. }
  24337. return num;
  24338. },
  24339. notNeedUndo: 1
  24340. }
  24341. },
  24342. bindEvents: {
  24343. clearlastSearchResult: function () {
  24344. lastRng = null;
  24345. }
  24346. }
  24347. };
  24348. });
  24349. // plugins/customstyle.js
  24350. /**
  24351. * 自定义样式
  24352. * @file
  24353. * @since 1.2.6.1
  24354. */
  24355. /**
  24356. * 根据config配置文件里“customstyle”选项的值对匹配的标签执行样式替换。
  24357. * @command customstyle
  24358. * @method execCommand
  24359. * @param { String } cmd 命令字符串
  24360. * @example
  24361. * ```javascript
  24362. * editor.execCommand( 'customstyle' );
  24363. * ```
  24364. */
  24365. UE.plugins["customstyle"] = function () {
  24366. var me = this;
  24367. me.setOpt({
  24368. customstyle: [
  24369. {
  24370. tag: "h1",
  24371. name: "tc",
  24372. style:
  24373. "font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;"
  24374. },
  24375. {
  24376. tag: "h1",
  24377. name: "tl",
  24378. style:
  24379. "font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;margin:0 0 10px 0;"
  24380. },
  24381. {
  24382. tag: "span",
  24383. name: "im",
  24384. style:
  24385. "font-size:16px;font-style:italic;font-weight:bold;line-height:18px;"
  24386. },
  24387. {
  24388. tag: "span",
  24389. name: "hi",
  24390. style:
  24391. "font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;"
  24392. }
  24393. ]
  24394. });
  24395. me.commands["customstyle"] = {
  24396. execCommand: function (cmdName, obj) {
  24397. var me = this,
  24398. tagName = obj.tag,
  24399. node = domUtils.findParent(
  24400. me.selection.getStart(),
  24401. function (node) {
  24402. return node.getAttribute("label");
  24403. },
  24404. true
  24405. ),
  24406. range,
  24407. bk,
  24408. tmpObj = {};
  24409. for (var p in obj) {
  24410. if (obj[p] !== undefined) tmpObj[p] = obj[p];
  24411. }
  24412. delete tmpObj.tag;
  24413. if (node && node.getAttribute("label") == obj.label) {
  24414. range = this.selection.getRange();
  24415. bk = range.createBookmark();
  24416. if (range.collapsed) {
  24417. //trace:1732 删掉自定义标签,要有p来回填站位
  24418. if (dtd.$block[node.tagName]) {
  24419. var fillNode = me.document.createElement("p");
  24420. domUtils.moveChild(node, fillNode);
  24421. node.parentNode.insertBefore(fillNode, node);
  24422. domUtils.remove(node);
  24423. } else {
  24424. domUtils.remove(node, true);
  24425. }
  24426. } else {
  24427. var common = domUtils.getCommonAncestor(bk.start, bk.end),
  24428. nodes = domUtils.getElementsByTagName(common, tagName);
  24429. if (new RegExp(tagName, "i").test(common.tagName)) {
  24430. nodes.push(common);
  24431. }
  24432. for (var i = 0, ni; (ni = nodes[i++]);) {
  24433. if (ni.getAttribute("label") == obj.label) {
  24434. var ps = domUtils.getPosition(ni, bk.start),
  24435. pe = domUtils.getPosition(ni, bk.end);
  24436. if (
  24437. (ps & domUtils.POSITION_FOLLOWING ||
  24438. ps & domUtils.POSITION_CONTAINS) &&
  24439. (pe & domUtils.POSITION_PRECEDING ||
  24440. pe & domUtils.POSITION_CONTAINS)
  24441. )
  24442. if (dtd.$block[tagName]) {
  24443. var fillNode = me.document.createElement("p");
  24444. domUtils.moveChild(ni, fillNode);
  24445. ni.parentNode.insertBefore(fillNode, ni);
  24446. }
  24447. domUtils.remove(ni, true);
  24448. }
  24449. }
  24450. node = domUtils.findParent(
  24451. common,
  24452. function (node) {
  24453. return node.getAttribute("label") == obj.label;
  24454. },
  24455. true
  24456. );
  24457. if (node) {
  24458. domUtils.remove(node, true);
  24459. }
  24460. }
  24461. range.moveToBookmark(bk).select();
  24462. } else {
  24463. if (dtd.$block[tagName]) {
  24464. this.execCommand("paragraph", tagName, tmpObj, "customstyle");
  24465. range = me.selection.getRange();
  24466. if (!range.collapsed) {
  24467. range.collapse();
  24468. node = domUtils.findParent(
  24469. me.selection.getStart(),
  24470. function (node) {
  24471. return node.getAttribute("label") == obj.label;
  24472. },
  24473. true
  24474. );
  24475. var pNode = me.document.createElement("p");
  24476. domUtils.insertAfter(node, pNode);
  24477. domUtils.fillNode(me.document, pNode);
  24478. range.setStart(pNode, 0).setCursor();
  24479. }
  24480. } else {
  24481. range = me.selection.getRange();
  24482. if (range.collapsed) {
  24483. node = me.document.createElement(tagName);
  24484. domUtils.setAttributes(node, tmpObj);
  24485. range.insertNode(node).setStart(node, 0).setCursor();
  24486. return;
  24487. }
  24488. bk = range.createBookmark();
  24489. range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select();
  24490. }
  24491. }
  24492. },
  24493. queryCommandValue: function () {
  24494. var parent = domUtils.filterNodeList(
  24495. this.selection.getStartElementPath(),
  24496. function (node) {
  24497. return node.getAttribute("label");
  24498. }
  24499. );
  24500. return parent ? parent.getAttribute("label") : "";
  24501. }
  24502. };
  24503. //当去掉customstyle是,如果是块元素,用p代替
  24504. me.addListener("keyup", function (type, evt) {
  24505. var keyCode = evt.keyCode || evt.which;
  24506. if (keyCode == 32 || keyCode == 13) {
  24507. var range = me.selection.getRange();
  24508. if (range.collapsed) {
  24509. var node = domUtils.findParent(
  24510. me.selection.getStart(),
  24511. function (node) {
  24512. return node.getAttribute("label");
  24513. },
  24514. true
  24515. );
  24516. if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
  24517. var p = me.document.createElement("p");
  24518. domUtils.insertAfter(node, p);
  24519. domUtils.fillNode(me.document, p);
  24520. domUtils.remove(node);
  24521. range.setStart(p, 0).setCursor();
  24522. }
  24523. }
  24524. }
  24525. });
  24526. };
  24527. // plugins/catchremoteimage.js
  24528. ///import core
  24529. ///commands 远程图片抓取
  24530. ///commandsName catchRemoteImage,catchremoteimageenable
  24531. ///commandsTitle 远程图片抓取
  24532. /**
  24533. * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
  24534. */
  24535. UE.plugins["catchremoteimage"] = function () {
  24536. var me = this,
  24537. ajax = UE.ajax;
  24538. /* 设置默认值 */
  24539. if (me.options.catchRemoteImageEnable === false) return;
  24540. me.setOpt({
  24541. catchRemoteImageEnable: false
  24542. });
  24543. me.addListener("afterpaste", function () {
  24544. me.fireEvent("catchRemoteImage");
  24545. });
  24546. me.addListener("catchRemoteImage", function () {
  24547. var catcherLocalDomain = me.getOpt("catcherLocalDomain"),
  24548. catcherActionUrl = me.getActionUrl(me.getOpt("catcherActionName")),
  24549. catcherUrlPrefix = me.getOpt("catcherUrlPrefix"),
  24550. catcherFieldName = me.getOpt("catcherFieldName");
  24551. var remoteImages = [],
  24552. loadingIMG = me.options.themePath + me.options.theme + '/images/spacer.gif',
  24553. imgs = me.document.querySelectorAll('[style*="url"],img'),
  24554. test = function (src, urls) {
  24555. if (src.indexOf(location.host) != -1 || /(^\.)|(^\/)/.test(src)) {
  24556. return true;
  24557. }
  24558. if (urls) {
  24559. for (var j = 0, url; (url = urls[j++]);) {
  24560. if (src.indexOf(url) !== -1) {
  24561. return true;
  24562. }
  24563. }
  24564. }
  24565. return false;
  24566. };
  24567. for (var i = 0, ci; (ci = imgs[i++]);) {
  24568. if (ci.getAttribute("word_img")) {
  24569. continue;
  24570. }
  24571. if (ci.nodeName == "IMG") {
  24572. var src = ci.getAttribute("_src") || ci.src || "";
  24573. if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
  24574. remoteImages.push(src);
  24575. // 添加上传时的uploading动画
  24576. domUtils.setAttributes(ci, {
  24577. class: "loadingclass",
  24578. _src: src,
  24579. src: loadingIMG
  24580. })
  24581. }
  24582. } else {
  24583. // 获取背景图片url
  24584. var backgroundImageurl = ci.style.cssText.replace(/.*\s?url\([\'\"]?/, '').replace(/[\'\"]?\).*/, '');
  24585. if (/^(https?|ftp):/i.test(backgroundImageurl) && !test(backgroundImageurl, catcherLocalDomain)) {
  24586. remoteImages.push(backgroundImageurl);
  24587. ci.style.cssText = ci.style.cssText.replace(backgroundImageurl, loadingIMG);
  24588. domUtils.setAttributes(ci, {
  24589. "data-background": backgroundImageurl
  24590. })
  24591. }
  24592. }
  24593. }
  24594. if (remoteImages.length) {
  24595. catchremoteimage(remoteImages, {
  24596. //成功抓取
  24597. success: function (r) {
  24598. try {
  24599. var info = r.state !== undefined
  24600. ? r
  24601. : eval("(" + r.responseText + ")");
  24602. } catch (e) {
  24603. return;
  24604. }
  24605. /* 获取源路径和新路径 */
  24606. var i,
  24607. j,
  24608. ci,
  24609. cj,
  24610. oldSrc,
  24611. newSrc,
  24612. list = info.list;
  24613. /* 抓取失败统计 */
  24614. var catchFailList = [];
  24615. /* 抓取成功统计 */
  24616. var catchSuccessList = [];
  24617. /* 抓取失败时显示的图片 */
  24618. var failIMG = me.options.themePath + me.options.theme + '/images/img-cracked.png';
  24619. for (i = 0; ci = imgs[i++];) {
  24620. oldSrc = ci.getAttribute("_src") || ci.src || "";
  24621. oldBgIMG = ci.getAttribute("data-background") || "";
  24622. for (j = 0; cj = list[j++];) {
  24623. if (oldSrc == cj.source && cj.state == "SUCCESS") {
  24624. newSrc = catcherUrlPrefix + cj.url;
  24625. // 上传成功是删除uploading动画
  24626. domUtils.removeClasses(ci, "loadingclass");
  24627. domUtils.setAttributes(ci, {
  24628. "src": newSrc,
  24629. "_src": newSrc,
  24630. "data-catchResult": "img_catchSuccess" // 添加catch成功标记
  24631. });
  24632. catchSuccessList.push(ci);
  24633. break;
  24634. } else if (oldSrc == cj.source && cj.state == "FAIL") {
  24635. // 替换成统一的失败图片
  24636. domUtils.removeClasses(ci, "loadingclass");
  24637. domUtils.setAttributes(ci, {
  24638. "src": failIMG,
  24639. "_src": failIMG,
  24640. "data-catchResult": "img_catchFail" // 添加catch失败标记
  24641. });
  24642. catchFailList.push(ci);
  24643. break;
  24644. } else if (oldBgIMG == cj.source && cj.state == "SUCCESS") {
  24645. newBgIMG = catcherUrlPrefix + cj.url;
  24646. ci.style.cssText = ci.style.cssText.replace(loadingIMG, newBgIMG);
  24647. domUtils.removeAttributes(ci, "data-background");
  24648. domUtils.setAttributes(ci, {
  24649. "data-catchResult": "img_catchSuccess" // 添加catch成功标记
  24650. });
  24651. catchSuccessList.push(ci);
  24652. break;
  24653. } else if (oldBgIMG == cj.source && cj.state == "FAIL") {
  24654. ci.style.cssText = ci.style.cssText.replace(loadingIMG, failIMG);
  24655. domUtils.removeAttributes(ci, "data-background");
  24656. domUtils.setAttributes(ci, {
  24657. "data-catchResult": "img_catchFail" // 添加catch失败标记
  24658. });
  24659. catchFailList.push(ci);
  24660. break;
  24661. }
  24662. }
  24663. }
  24664. // 监听事件添加成功抓取和抓取失败的dom列表参数
  24665. me.fireEvent('catchremotesuccess', catchSuccessList, catchFailList);
  24666. },
  24667. //回调失败,本次请求超时
  24668. error: function () {
  24669. me.fireEvent("catchremoteerror");
  24670. }
  24671. });
  24672. }
  24673. function catchremoteimage(imgs, callbacks) {
  24674. var params =
  24675. utils.serializeParam(me.queryCommandValue("serverparam")) || "",
  24676. url = utils.formatUrl(
  24677. catcherActionUrl +
  24678. (catcherActionUrl.indexOf("?") == -1 ? "?" : "&") +
  24679. params
  24680. ),
  24681. isJsonp = utils.isCrossDomainUrl(url),
  24682. opt = {
  24683. method: "POST",
  24684. dataType: isJsonp ? "jsonp" : "",
  24685. timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
  24686. onsuccess: callbacks["success"],
  24687. onerror: callbacks["error"]
  24688. };
  24689. opt[catcherFieldName] = imgs;
  24690. ajax.request(url, opt);
  24691. }
  24692. });
  24693. };
  24694. // plugins/snapscreen.js
  24695. /**
  24696. * 截屏插件,为UEditor提供插入支持
  24697. * @file
  24698. * @since 1.4.2
  24699. */
  24700. UE.plugin.register("snapscreen", function () {
  24701. var me = this;
  24702. var snapplugin;
  24703. function getLocation(url) {
  24704. var search,
  24705. a = document.createElement("a"),
  24706. params = utils.serializeParam(me.queryCommandValue("serverparam")) || "";
  24707. a.href = url;
  24708. if (browser.ie) {
  24709. a.href = a.href;
  24710. }
  24711. search = a.search;
  24712. if (params) {
  24713. search = search + (search.indexOf("?") == -1 ? "?" : "&") + params;
  24714. search = search.replace(/[&]+/gi, "&");
  24715. }
  24716. return {
  24717. port: a.port,
  24718. hostname: a.hostname,
  24719. path: a.pathname + search || +a.hash
  24720. };
  24721. }
  24722. return {
  24723. commands: {
  24724. /**
  24725. * 字体背景颜色
  24726. * @command snapscreen
  24727. * @method execCommand
  24728. * @param { String } cmd 命令字符串
  24729. * @example
  24730. * ```javascript
  24731. * editor.execCommand('snapscreen');
  24732. * ```
  24733. */
  24734. snapscreen: {
  24735. execCommand: function (cmd) {
  24736. var url, local, res;
  24737. var lang = me.getLang("snapScreen_plugin");
  24738. if (!snapplugin) {
  24739. var container = me.container;
  24740. var doc = me.container.ownerDocument || me.container.document;
  24741. snapplugin = doc.createElement("object");
  24742. try {
  24743. snapplugin.type = "application/x-pluginbaidusnap";
  24744. } catch (e) {
  24745. return;
  24746. }
  24747. snapplugin.style.cssText =
  24748. "position:absolute;left:-9999px;width:0;height:0;";
  24749. snapplugin.setAttribute("width", "0");
  24750. snapplugin.setAttribute("height", "0");
  24751. container.appendChild(snapplugin);
  24752. }
  24753. function onSuccess(rs) {
  24754. try {
  24755. rs = eval("(" + rs + ")");
  24756. if (rs.state == "SUCCESS") {
  24757. var opt = me.options;
  24758. me.execCommand("insertimage", {
  24759. src: opt.snapscreenUrlPrefix + rs.url,
  24760. _src: opt.snapscreenUrlPrefix + rs.url,
  24761. alt: rs.title || "",
  24762. floatStyle: opt.snapscreenImgAlign
  24763. });
  24764. } else {
  24765. alert(rs.state);
  24766. }
  24767. } catch (e) {
  24768. alert(lang.callBackErrorMsg);
  24769. }
  24770. }
  24771. url = me.getActionUrl(me.getOpt("snapscreenActionName"));
  24772. local = getLocation(url);
  24773. setTimeout(function () {
  24774. try {
  24775. res = snapplugin.saveSnapshot(
  24776. local.hostname,
  24777. local.path,
  24778. local.port
  24779. );
  24780. } catch (e) {
  24781. me.ui._dialogs["snapscreenDialog"].open();
  24782. return;
  24783. }
  24784. onSuccess(res);
  24785. }, 50);
  24786. },
  24787. queryCommandState: function () {
  24788. return navigator.userAgent.indexOf("Windows", 0) != -1 ? 0 : -1;
  24789. }
  24790. }
  24791. }
  24792. };
  24793. });
  24794. // plugins/insertparagraph.js
  24795. /**
  24796. * 插入段落
  24797. * @file
  24798. * @since 1.2.6.1
  24799. */
  24800. /**
  24801. * 插入段落
  24802. * @command insertparagraph
  24803. * @method execCommand
  24804. * @param { String } cmd 命令字符串
  24805. * @example
  24806. * ```javascript
  24807. * //editor是编辑器实例
  24808. * editor.execCommand( 'insertparagraph' );
  24809. * ```
  24810. */
  24811. UE.commands["insertparagraph"] = {
  24812. execCommand: function (cmdName, front) {
  24813. var me = this,
  24814. range = me.selection.getRange(),
  24815. start = range.startContainer,
  24816. tmpNode;
  24817. while (start) {
  24818. if (domUtils.isBody(start)) {
  24819. break;
  24820. }
  24821. tmpNode = start;
  24822. start = start.parentNode;
  24823. }
  24824. if (tmpNode) {
  24825. var p = me.document.createElement("p");
  24826. if (front) {
  24827. tmpNode.parentNode.insertBefore(p, tmpNode);
  24828. } else {
  24829. tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling);
  24830. }
  24831. domUtils.fillNode(me.document, p);
  24832. range.setStart(p, 0).setCursor(false, true);
  24833. }
  24834. }
  24835. };
  24836. // plugins/webapp.js
  24837. /**
  24838. * 百度应用
  24839. * @file
  24840. * @since 1.2.6.1
  24841. */
  24842. /**
  24843. * 插入百度应用
  24844. * @command webapp
  24845. * @method execCommand
  24846. * @remind 需要百度APPKey
  24847. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  24848. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  24849. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  24850. * @example
  24851. * ```javascript
  24852. * //editor是编辑器实例
  24853. * //在编辑器里插入一个“植物大战僵尸”的APP
  24854. * editor.execCommand( 'webapp' , {
  24855. * title: '植物大战僵尸',
  24856. * width: 560,
  24857. * height: 465,
  24858. * logo: '应用展示的图片',
  24859. * url: '百度应用的地址'
  24860. * } );
  24861. * ```
  24862. */
  24863. //UE.plugins['webapp'] = function () {
  24864. // var me = this;
  24865. // function createInsertStr( obj, toIframe, addParagraph ) {
  24866. // return !toIframe ?
  24867. // (addParagraph ? '<p>' : '') + '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
  24868. // ' src="' + me.options.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif" style="background:url(' + obj.logo+') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' + obj.url + '" />' +
  24869. // (addParagraph ? '</p>' : '')
  24870. // :
  24871. // '<iframe class="edui-faked-webapp" title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '" scrolling="no" frameborder="0" src="' + obj.url + '" logo_url = '+obj.logo+'></iframe>';
  24872. // }
  24873. //
  24874. // function switchImgAndIframe( img2frame ) {
  24875. // var tmpdiv,
  24876. // nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
  24877. // for ( var i = 0, node; node = nodes[i++]; ) {
  24878. // if ( node.className != "edui-faked-webapp" ){
  24879. // continue;
  24880. // }
  24881. // tmpdiv = me.document.createElement( "div" );
  24882. // tmpdiv.innerHTML = createInsertStr( img2frame ? {url:node.getAttribute( "_url" ), width:node.width, height:node.height,title:node.title,logo:node.style.backgroundImage.replace("url(","").replace(")","")} : {url:node.getAttribute( "src", 2 ),title:node.title, width:node.width, height:node.height,logo:node.getAttribute("logo_url")}, img2frame ? true : false,false );
  24883. // node.parentNode.replaceChild( tmpdiv.firstChild, node );
  24884. // }
  24885. // }
  24886. //
  24887. // me.addListener( "beforegetcontent", function () {
  24888. // switchImgAndIframe( true );
  24889. // } );
  24890. // me.addListener( 'aftersetcontent', function () {
  24891. // switchImgAndIframe( false );
  24892. // } );
  24893. // me.addListener( 'aftergetcontent', function ( cmdName ) {
  24894. // if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
  24895. // return;
  24896. // }
  24897. // switchImgAndIframe( false );
  24898. // } );
  24899. //
  24900. // me.commands['webapp'] = {
  24901. // execCommand:function ( cmd, obj ) {
  24902. // me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
  24903. // }
  24904. // };
  24905. //};
  24906. UE.plugin.register("webapp", function () {
  24907. var me = this;
  24908. function createInsertStr(obj, toEmbed) {
  24909. return !toEmbed
  24910. ? '<img title="' +
  24911. obj.title +
  24912. '" width="' +
  24913. obj.width +
  24914. '" height="' +
  24915. obj.height +
  24916. '"' +
  24917. ' src="' +
  24918. me.options.UEDITOR_HOME_URL +
  24919. 'themes/notadd/images/spacer.gif" _logo_url="' +
  24920. obj.logo +
  24921. '" style="background:url(' +
  24922. obj.logo +
  24923. ') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' +
  24924. obj.url +
  24925. '" ' +
  24926. (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : "") +
  24927. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : "") +
  24928. "/>"
  24929. : '<iframe class="edui-faked-webapp" title="' +
  24930. obj.title +
  24931. '" ' +
  24932. (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : "") +
  24933. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : "") +
  24934. 'width="' +
  24935. obj.width +
  24936. '" height="' +
  24937. obj.height +
  24938. '" scrolling="no" frameborder="0" src="' +
  24939. obj.url +
  24940. '" logo_url = "' +
  24941. obj.logo +
  24942. '"></iframe>';
  24943. }
  24944. return {
  24945. outputRule: function (root) {
  24946. utils.each(root.getNodesByTagName("img"), function (node) {
  24947. var html;
  24948. if (node.getAttr("class") == "edui-faked-webapp") {
  24949. html = createInsertStr(
  24950. {
  24951. title: node.getAttr("title"),
  24952. width: node.getAttr("width"),
  24953. height: node.getAttr("height"),
  24954. align: node.getAttr("align"),
  24955. cssfloat: node.getStyle("float"),
  24956. url: node.getAttr("_url"),
  24957. logo: node.getAttr("_logo_url")
  24958. },
  24959. true
  24960. );
  24961. var embed = UE.uNode.createElement(html);
  24962. node.parentNode.replaceChild(embed, node);
  24963. }
  24964. });
  24965. },
  24966. inputRule: function (root) {
  24967. utils.each(root.getNodesByTagName("iframe"), function (node) {
  24968. if (node.getAttr("class") == "edui-faked-webapp") {
  24969. var img = UE.uNode.createElement(
  24970. createInsertStr({
  24971. title: node.getAttr("title"),
  24972. width: node.getAttr("width"),
  24973. height: node.getAttr("height"),
  24974. align: node.getAttr("align"),
  24975. cssfloat: node.getStyle("float"),
  24976. url: node.getAttr("src"),
  24977. logo: node.getAttr("logo_url")
  24978. })
  24979. );
  24980. node.parentNode.replaceChild(img, node);
  24981. }
  24982. });
  24983. },
  24984. commands: {
  24985. /**
  24986. * 插入百度应用
  24987. * @command webapp
  24988. * @method execCommand
  24989. * @remind 需要百度APPKey
  24990. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  24991. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  24992. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  24993. * @example
  24994. * ```javascript
  24995. * //editor是编辑器实例
  24996. * //在编辑器里插入一个“植物大战僵尸”的APP
  24997. * editor.execCommand( 'webapp' , {
  24998. * title: '植物大战僵尸',
  24999. * width: 560,
  25000. * height: 465,
  25001. * logo: '应用展示的图片',
  25002. * url: '百度应用的地址'
  25003. * } );
  25004. * ```
  25005. */
  25006. webapp: {
  25007. execCommand: function (cmd, obj) {
  25008. var me = this,
  25009. str = createInsertStr(
  25010. utils.extend(obj, {
  25011. align: "none"
  25012. }),
  25013. false
  25014. );
  25015. me.execCommand("inserthtml", str);
  25016. },
  25017. queryCommandState: function () {
  25018. var me = this,
  25019. img = me.selection.getRange().getClosedNode(),
  25020. flag = img && img.className == "edui-faked-webapp";
  25021. return flag ? 1 : 0;
  25022. }
  25023. }
  25024. }
  25025. };
  25026. });
  25027. // plugins/template.js
  25028. ///import core
  25029. ///import plugins\inserthtml.js
  25030. ///import plugins\cleardoc.js
  25031. ///commands 模板
  25032. ///commandsName template
  25033. ///commandsTitle 模板
  25034. ///commandsDialog dialogs\template
  25035. UE.plugins["template"] = function () {
  25036. UE.commands["template"] = {
  25037. execCommand: function (cmd, obj) {
  25038. obj.html && this.execCommand("inserthtml", obj.html);
  25039. }
  25040. };
  25041. this.addListener("click", function (type, evt) {
  25042. var el = evt.target || evt.srcElement,
  25043. range = this.selection.getRange();
  25044. var tnode = domUtils.findParent(
  25045. el,
  25046. function (node) {
  25047. if (node.className && domUtils.hasClass(node, "ue_t")) {
  25048. return node;
  25049. }
  25050. },
  25051. true
  25052. );
  25053. tnode && range.selectNode(tnode).shrinkBoundary().select();
  25054. });
  25055. this.addListener("keydown", function (type, evt) {
  25056. var range = this.selection.getRange();
  25057. if (!range.collapsed) {
  25058. if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  25059. var tnode = domUtils.findParent(
  25060. range.startContainer,
  25061. function (node) {
  25062. if (node.className && domUtils.hasClass(node, "ue_t")) {
  25063. return node;
  25064. }
  25065. },
  25066. true
  25067. );
  25068. if (tnode) {
  25069. domUtils.removeClasses(tnode, ["ue_t"]);
  25070. }
  25071. }
  25072. }
  25073. });
  25074. };
  25075. // plugins/music.js
  25076. /**
  25077. * 插入音乐命令
  25078. * @file
  25079. */
  25080. UE.plugin.register("music", function () {
  25081. var me = this;
  25082. function creatInsertStr(url, width, height, align, cssfloat, toEmbed) {
  25083. return !toEmbed
  25084. ? "<img " +
  25085. (align && !cssfloat ? 'align="' + align + '"' : "") +
  25086. (cssfloat ? 'style="float:' + cssfloat + '"' : "") +
  25087. ' width="' +
  25088. width +
  25089. '" height="' +
  25090. height +
  25091. '" _url="' +
  25092. url +
  25093. '" class="edui-faked-music"' +
  25094. ' src="' +
  25095. me.options.langPath +
  25096. me.options.lang +
  25097. '/images/music.png" />'
  25098. : '<embed type="application/x-shockwave-flash" class="edui-faked-music" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  25099. ' src="' +
  25100. url +
  25101. '" width="' +
  25102. width +
  25103. '" height="' +
  25104. height +
  25105. '" ' +
  25106. (align && !cssfloat ? 'align="' + align + '"' : "") +
  25107. (cssfloat ? 'style="float:' + cssfloat + '"' : "") +
  25108. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  25109. }
  25110. return {
  25111. outputRule: function (root) {
  25112. utils.each(root.getNodesByTagName("img"), function (node) {
  25113. var html;
  25114. if (node.getAttr("class") == "edui-faked-music") {
  25115. var cssfloat = node.getStyle("float");
  25116. var align = node.getAttr("align");
  25117. html = creatInsertStr(
  25118. node.getAttr("_url"),
  25119. node.getAttr("width"),
  25120. node.getAttr("height"),
  25121. align,
  25122. cssfloat,
  25123. true
  25124. );
  25125. var embed = UE.uNode.createElement(html);
  25126. node.parentNode.replaceChild(embed, node);
  25127. }
  25128. });
  25129. },
  25130. inputRule: function (root) {
  25131. utils.each(root.getNodesByTagName("embed"), function (node) {
  25132. if (node.getAttr("class") == "edui-faked-music") {
  25133. var cssfloat = node.getStyle("float");
  25134. var align = node.getAttr("align");
  25135. html = creatInsertStr(
  25136. node.getAttr("src"),
  25137. node.getAttr("width"),
  25138. node.getAttr("height"),
  25139. align,
  25140. cssfloat,
  25141. false
  25142. );
  25143. var img = UE.uNode.createElement(html);
  25144. node.parentNode.replaceChild(img, node);
  25145. }
  25146. });
  25147. },
  25148. commands: {
  25149. /**
  25150. * 插入音乐
  25151. * @command music
  25152. * @method execCommand
  25153. * @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
  25154. * width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
  25155. * @example
  25156. * ```javascript
  25157. * //editor是编辑器实例
  25158. * //在编辑器里插入一个“植物大战僵尸”的APP
  25159. * editor.execCommand( 'music' , {
  25160. * width: 400,
  25161. * height: 95,
  25162. * align: "center",
  25163. * url: "音乐地址"
  25164. * } );
  25165. * ```
  25166. */
  25167. music: {
  25168. execCommand: function (cmd, musicObj) {
  25169. var me = this,
  25170. str = creatInsertStr(
  25171. musicObj.url,
  25172. musicObj.width || 400,
  25173. musicObj.height || 95,
  25174. "none",
  25175. false
  25176. );
  25177. me.execCommand("inserthtml", str);
  25178. },
  25179. queryCommandState: function () {
  25180. var me = this,
  25181. img = me.selection.getRange().getClosedNode(),
  25182. flag = img && img.className == "edui-faked-music";
  25183. return flag ? 1 : 0;
  25184. }
  25185. }
  25186. }
  25187. };
  25188. });
  25189. // plugins/autoupload.js
  25190. /**
  25191. * @description
  25192. * 1.拖放文件到编辑区域,自动上传并插入到选区
  25193. * 2.插入粘贴板的图片,自动上传并插入到选区
  25194. * @author Jinqn
  25195. * @date 2013-10-14
  25196. */
  25197. UE.plugin.register("autoupload", function () {
  25198. function sendAndInsertFile(file, editor) {
  25199. var me = editor;
  25200. //模拟数据
  25201. var fieldName,
  25202. urlPrefix,
  25203. maxSize,
  25204. allowFiles,
  25205. actionUrl,
  25206. loadingHtml,
  25207. errorHandler,
  25208. successHandler,
  25209. filetype = /image\/\w+/i.test(file.type) ? "image" : "file",
  25210. loadingId = "loading_" + (+new Date()).toString(36);
  25211. fieldName = me.getOpt(filetype + "FieldName");
  25212. urlPrefix = me.getOpt(filetype + "UrlPrefix");
  25213. maxSize = me.getOpt(filetype + "MaxSize");
  25214. allowFiles = me.getOpt(filetype + "AllowFiles");
  25215. actionUrl = me.getActionUrl(me.getOpt(filetype + "ActionName"));
  25216. errorHandler = function (title) {
  25217. var loader = me.document.getElementById(loadingId);
  25218. loader && domUtils.remove(loader);
  25219. me.fireEvent("showmessage", {
  25220. id: loadingId,
  25221. content: title,
  25222. type: "error",
  25223. timeout: 4000
  25224. });
  25225. };
  25226. if (filetype == "image") {
  25227. loadingHtml =
  25228. '<img class="loadingclass" id="' +
  25229. loadingId +
  25230. '" src="' +
  25231. me.options.themePath +
  25232. me.options.theme +
  25233. '/images/spacer.gif">';
  25234. successHandler = function (data) {
  25235. var link = urlPrefix + data.url,
  25236. loader = me.document.getElementById(loadingId);
  25237. if (loader) {
  25238. domUtils.removeClasses(loader, "loadingclass");
  25239. loader.setAttribute("src", link);
  25240. loader.setAttribute("_src", link);
  25241. loader.setAttribute("alt", data.original || "");
  25242. loader.removeAttribute("id");
  25243. me.trigger("contentchange", loader);
  25244. }
  25245. };
  25246. } else {
  25247. loadingHtml =
  25248. "<p>" +
  25249. '<img class="loadingclass" id="' +
  25250. loadingId +
  25251. '" src="' +
  25252. me.options.themePath +
  25253. me.options.theme +
  25254. '/images/spacer.gif">' +
  25255. "</p>";
  25256. successHandler = function (data) {
  25257. var link = urlPrefix + data.url,
  25258. loader = me.document.getElementById(loadingId);
  25259. var rng = me.selection.getRange(),
  25260. bk = rng.createBookmark();
  25261. rng.selectNode(loader).select();
  25262. me.execCommand("insertfile", {url: link});
  25263. rng.moveToBookmark(bk).select();
  25264. };
  25265. }
  25266. /* 插入loading的占位符 */
  25267. me.execCommand("inserthtml", loadingHtml);
  25268. /* 判断后端配置是否没有加载成功 */
  25269. if (!me.getOpt(filetype + "ActionName")) {
  25270. errorHandler(me.getLang("autoupload.errorLoadConfig"));
  25271. return;
  25272. }
  25273. /* 判断文件大小是否超出限制 */
  25274. if (file.size > maxSize) {
  25275. errorHandler(me.getLang("autoupload.exceedSizeError"));
  25276. return;
  25277. }
  25278. /* 判断文件格式是否超出允许 */
  25279. var fileext = file.name ? file.name.substr(file.name.lastIndexOf(".")) : "";
  25280. if (
  25281. (fileext && filetype != "image") ||
  25282. (allowFiles &&
  25283. (allowFiles.join("") + ".").indexOf(fileext.toLowerCase() + ".") == -1)
  25284. ) {
  25285. errorHandler(me.getLang("autoupload.exceedTypeError"));
  25286. return;
  25287. }
  25288. /* 创建Ajax并提交 */
  25289. var xhr = new XMLHttpRequest(),
  25290. fd = new FormData(),
  25291. params = utils.serializeParam(me.queryCommandValue("serverparam")) || "",
  25292. url = utils.formatUrl(
  25293. actionUrl + (actionUrl.indexOf("?") == -1 ? "?" : "&") + params
  25294. );
  25295. fd.append(
  25296. fieldName,
  25297. file,
  25298. file.name || "blob." + file.type.substr("image/".length)
  25299. );
  25300. fd.append("type", "ajax");
  25301. xhr.open("post", url, true);
  25302. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  25303. xhr.addEventListener("load", function (e) {
  25304. try {
  25305. var json = new Function("return " + utils.trim(e.target.response))();
  25306. if (json.state == "SUCCESS" && json.url) {
  25307. successHandler(json);
  25308. } else {
  25309. errorHandler(json.state);
  25310. }
  25311. } catch (er) {
  25312. errorHandler(me.getLang("autoupload.loadError"));
  25313. }
  25314. });
  25315. xhr.send(fd);
  25316. }
  25317. function getPasteImage(e) {
  25318. return e.clipboardData &&
  25319. e.clipboardData.items &&
  25320. e.clipboardData.items.length == 1 &&
  25321. /^image\//.test(e.clipboardData.items[0].type)
  25322. ? e.clipboardData.items
  25323. : null;
  25324. }
  25325. function getDropImage(e) {
  25326. return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files : null;
  25327. }
  25328. return {
  25329. outputRule: function (root) {
  25330. utils.each(root.getNodesByTagName("img"), function (n) {
  25331. if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr("class"))) {
  25332. n.parentNode.removeChild(n);
  25333. }
  25334. });
  25335. utils.each(root.getNodesByTagName("p"), function (n) {
  25336. if (/\bloadpara\b/.test(n.getAttr("class"))) {
  25337. n.parentNode.removeChild(n);
  25338. }
  25339. });
  25340. },
  25341. bindEvents: {
  25342. defaultOptions: {
  25343. //默认间隔时间
  25344. enableDragUpload: true,
  25345. enablePasteUpload: true
  25346. },
  25347. //插入粘贴板的图片,拖放插入图片
  25348. ready: function (e) {
  25349. var me = this;
  25350. if (window.FormData && window.FileReader) {
  25351. var handler = function (e) {
  25352. var hasImg = false,
  25353. items;
  25354. //获取粘贴板文件列表或者拖放文件列表
  25355. items = e.type == "paste" ? getPasteImage(e) : getDropImage(e);
  25356. if (items) {
  25357. var len = items.length,
  25358. file;
  25359. while (len--) {
  25360. file = items[len];
  25361. if (file.getAsFile) file = file.getAsFile();
  25362. if (file && file.size > 0) {
  25363. sendAndInsertFile(file, me);
  25364. hasImg = true;
  25365. }
  25366. }
  25367. hasImg && e.preventDefault();
  25368. }
  25369. };
  25370. if (me.getOpt("enablePasteUpload") !== false) {
  25371. domUtils.on(me.body, "paste ", handler);
  25372. }
  25373. if (me.getOpt("enableDragUpload") !== false) {
  25374. domUtils.on(me.body, "drop", handler);
  25375. //取消拖放图片时出现的文字光标位置提示
  25376. domUtils.on(me.body, "dragover", function (e) {
  25377. if (e.dataTransfer.types[0] == "Files") {
  25378. e.preventDefault();
  25379. }
  25380. });
  25381. } else {
  25382. if (browser.gecko) {
  25383. domUtils.on(me.body, "drop", function (e) {
  25384. if (getDropImage(e)) {
  25385. e.preventDefault();
  25386. }
  25387. });
  25388. }
  25389. }
  25390. //设置loading的样式
  25391. utils.cssRule(
  25392. "loading",
  25393. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  25394. this.options.themePath +
  25395. this.options.theme +
  25396. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n" +
  25397. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  25398. this.options.themePath +
  25399. this.options.theme +
  25400. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  25401. "}",
  25402. this.document
  25403. );
  25404. }
  25405. }
  25406. }
  25407. };
  25408. });
  25409. // plugins/autosave.js
  25410. UE.plugin.register("autosave", function () {
  25411. var me = this,
  25412. //无限循环保护
  25413. lastSaveTime = new Date(),
  25414. //最小保存间隔时间
  25415. MIN_TIME = 20,
  25416. //auto save key
  25417. saveKey = null;
  25418. function save(editor) {
  25419. var saveData;
  25420. if (new Date() - lastSaveTime < MIN_TIME) {
  25421. return;
  25422. }
  25423. if (!editor.hasContents()) {
  25424. //这里不能调用命令来删除, 会造成事件死循环
  25425. saveKey && me.removePreferences(saveKey);
  25426. return;
  25427. }
  25428. lastSaveTime = new Date();
  25429. editor._saveFlag = null;
  25430. saveData = me.body.innerHTML;
  25431. if (
  25432. editor.fireEvent("beforeautosave", {
  25433. content: saveData
  25434. }) === false
  25435. ) {
  25436. return;
  25437. }
  25438. me.setPreferences(saveKey, saveData);
  25439. editor.fireEvent("afterautosave", {
  25440. content: saveData
  25441. });
  25442. }
  25443. return {
  25444. defaultOptions: {
  25445. //默认间隔时间
  25446. saveInterval: 500,
  25447. enableAutoSave: true
  25448. },
  25449. bindEvents: {
  25450. ready: function () {
  25451. var _suffix = "-drafts-data",
  25452. key = null;
  25453. if (me.key) {
  25454. key = me.key + _suffix;
  25455. } else {
  25456. key = (me.container.parentNode.id || "ue-common") + _suffix;
  25457. }
  25458. //页面地址+编辑器ID 保持唯一
  25459. saveKey =
  25460. (location.protocol + location.host + location.pathname).replace(
  25461. /[.:\/]/g,
  25462. "_"
  25463. ) + key;
  25464. },
  25465. contentchange: function () {
  25466. if (!me.getOpt("enableAutoSave")) {
  25467. return;
  25468. }
  25469. if (!saveKey) {
  25470. return;
  25471. }
  25472. if (me._saveFlag) {
  25473. window.clearTimeout(me._saveFlag);
  25474. }
  25475. if (me.options.saveInterval > 0) {
  25476. me._saveFlag = window.setTimeout(function () {
  25477. save(me);
  25478. }, me.options.saveInterval);
  25479. } else {
  25480. save(me);
  25481. }
  25482. }
  25483. },
  25484. commands: {
  25485. clearlocaldata: {
  25486. execCommand: function (cmd, name) {
  25487. if (saveKey && me.getPreferences(saveKey)) {
  25488. me.removePreferences(saveKey);
  25489. }
  25490. },
  25491. notNeedUndo: true,
  25492. ignoreContentChange: true
  25493. },
  25494. getlocaldata: {
  25495. execCommand: function (cmd, name) {
  25496. return saveKey ? me.getPreferences(saveKey) || "" : "";
  25497. },
  25498. notNeedUndo: true,
  25499. ignoreContentChange: true
  25500. },
  25501. drafts: {
  25502. execCommand: function (cmd, name) {
  25503. if (saveKey) {
  25504. me.body.innerHTML =
  25505. me.getPreferences(saveKey) || "<p>" + domUtils.fillHtml + "</p>";
  25506. me.focus(true);
  25507. }
  25508. },
  25509. queryCommandState: function () {
  25510. return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1;
  25511. },
  25512. notNeedUndo: true,
  25513. ignoreContentChange: true
  25514. }
  25515. }
  25516. };
  25517. });
  25518. // plugins/charts.js
  25519. UE.plugin.register("charts", function () {
  25520. var me = this;
  25521. return {
  25522. bindEvents: {
  25523. chartserror: function () {
  25524. }
  25525. },
  25526. commands: {
  25527. charts: {
  25528. execCommand: function (cmd, data) {
  25529. var tableNode = domUtils.findParentByTagName(
  25530. this.selection.getRange().startContainer,
  25531. "table",
  25532. true
  25533. ),
  25534. flagText = [],
  25535. config = {};
  25536. if (!tableNode) {
  25537. return false;
  25538. }
  25539. if (!validData(tableNode)) {
  25540. me.fireEvent("chartserror");
  25541. return false;
  25542. }
  25543. config.title = data.title || "";
  25544. config.subTitle = data.subTitle || "";
  25545. config.xTitle = data.xTitle || "";
  25546. config.yTitle = data.yTitle || "";
  25547. config.suffix = data.suffix || "";
  25548. config.tip = data.tip || "";
  25549. //数据对齐方式
  25550. config.dataFormat = data.tableDataFormat || "";
  25551. //图表类型
  25552. config.chartType = data.chartType || 0;
  25553. for (var key in config) {
  25554. if (!config.hasOwnProperty(key)) {
  25555. continue;
  25556. }
  25557. flagText.push(key + ":" + config[key]);
  25558. }
  25559. tableNode.setAttribute("data-chart", flagText.join(";"));
  25560. domUtils.addClass(tableNode, "edui-charts-table");
  25561. },
  25562. queryCommandState: function (cmd, name) {
  25563. var tableNode = domUtils.findParentByTagName(
  25564. this.selection.getRange().startContainer,
  25565. "table",
  25566. true
  25567. );
  25568. return tableNode && validData(tableNode) ? 0 : -1;
  25569. }
  25570. }
  25571. },
  25572. inputRule: function (root) {
  25573. utils.each(root.getNodesByTagName("table"), function (tableNode) {
  25574. if (tableNode.getAttr("data-chart") !== undefined) {
  25575. tableNode.setAttr("style");
  25576. }
  25577. });
  25578. },
  25579. outputRule: function (root) {
  25580. utils.each(root.getNodesByTagName("table"), function (tableNode) {
  25581. if (tableNode.getAttr("data-chart") !== undefined) {
  25582. tableNode.setAttr("style", "display: none;");
  25583. }
  25584. });
  25585. }
  25586. };
  25587. function validData(table) {
  25588. var firstRows = null,
  25589. cellCount = 0;
  25590. //行数不够
  25591. if (table.rows.length < 2) {
  25592. return false;
  25593. }
  25594. //列数不够
  25595. if (table.rows[0].cells.length < 2) {
  25596. return false;
  25597. }
  25598. //第一行所有cell必须是th
  25599. firstRows = table.rows[0].cells;
  25600. cellCount = firstRows.length;
  25601. for (var i = 0, cell; (cell = firstRows[i]); i++) {
  25602. if (cell.tagName.toLowerCase() !== "th") {
  25603. return false;
  25604. }
  25605. }
  25606. for (var i = 1, row; (row = table.rows[i]); i++) {
  25607. //每行单元格数不匹配, 返回false
  25608. if (row.cells.length != cellCount) {
  25609. return false;
  25610. }
  25611. //第一列不是th也返回false
  25612. if (row.cells[0].tagName.toLowerCase() !== "th") {
  25613. return false;
  25614. }
  25615. for (var j = 1, cell; (cell = row.cells[j]); j++) {
  25616. var value = utils.trim(cell.innerText || cell.textContent || "");
  25617. value = value
  25618. .replace(new RegExp(UE.dom.domUtils.fillChar, "g"), "")
  25619. .replace(/^\s+|\s+$/g, "");
  25620. //必须是数字
  25621. if (!/^\d*\.?\d+$/.test(value)) {
  25622. return false;
  25623. }
  25624. }
  25625. }
  25626. return true;
  25627. }
  25628. });
  25629. // plugins/section.js
  25630. /**
  25631. * 目录大纲支持插件
  25632. * @file
  25633. * @since 1.3.0
  25634. */
  25635. UE.plugin.register("section", function () {
  25636. /* 目录节点对象 */
  25637. function Section(option) {
  25638. this.tag = "";
  25639. (this.level = -1), (this.dom = null);
  25640. this.nextSection = null;
  25641. this.previousSection = null;
  25642. this.parentSection = null;
  25643. this.startAddress = [];
  25644. this.endAddress = [];
  25645. this.children = [];
  25646. }
  25647. function getSection(option) {
  25648. var section = new Section();
  25649. return utils.extend(section, option);
  25650. }
  25651. function getNodeFromAddress(startAddress, root) {
  25652. var current = root;
  25653. for (var i = 0; i < startAddress.length; i++) {
  25654. if (!current.childNodes) return null;
  25655. current = current.childNodes[startAddress[i]];
  25656. }
  25657. return current;
  25658. }
  25659. var me = this;
  25660. return {
  25661. bindMultiEvents: {
  25662. type: "aftersetcontent afterscencerestore",
  25663. handler: function () {
  25664. me.fireEvent("updateSections");
  25665. }
  25666. },
  25667. bindEvents: {
  25668. /* 初始化、拖拽、粘贴、执行setcontent之后 */
  25669. ready: function () {
  25670. me.fireEvent("updateSections");
  25671. domUtils.on(me.body, "drop paste", function () {
  25672. me.fireEvent("updateSections");
  25673. });
  25674. },
  25675. /* 执行paragraph命令之后 */
  25676. afterexeccommand: function (type, cmd) {
  25677. if (cmd == "paragraph") {
  25678. me.fireEvent("updateSections");
  25679. }
  25680. },
  25681. /* 部分键盘操作,触发updateSections事件 */
  25682. keyup: function (type, e) {
  25683. var me = this,
  25684. range = me.selection.getRange();
  25685. if (range.collapsed != true) {
  25686. me.fireEvent("updateSections");
  25687. } else {
  25688. var keyCode = e.keyCode || e.which;
  25689. if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
  25690. me.fireEvent("updateSections");
  25691. }
  25692. }
  25693. }
  25694. },
  25695. commands: {
  25696. getsections: {
  25697. execCommand: function (cmd, levels) {
  25698. var levelFn = levels || ["h1", "h2", "h3", "h4", "h5", "h6"];
  25699. for (var i = 0; i < levelFn.length; i++) {
  25700. if (typeof levelFn[i] == "string") {
  25701. levelFn[i] = (function (fn) {
  25702. return function (node) {
  25703. return node.tagName == fn.toUpperCase();
  25704. };
  25705. })(levelFn[i]);
  25706. } else if (typeof levelFn[i] != "function") {
  25707. levelFn[i] = function (node) {
  25708. return null;
  25709. };
  25710. }
  25711. }
  25712. function getSectionLevel(node) {
  25713. for (var i = 0; i < levelFn.length; i++) {
  25714. if (levelFn[i](node)) return i;
  25715. }
  25716. return -1;
  25717. }
  25718. var me = this,
  25719. Directory = getSection({level: -1, title: "root"}),
  25720. previous = Directory;
  25721. function traversal(node, Directory) {
  25722. var level,
  25723. tmpSection = null,
  25724. parent,
  25725. child,
  25726. children = node.childNodes;
  25727. for (var i = 0, len = children.length; i < len; i++) {
  25728. child = children[i];
  25729. level = getSectionLevel(child);
  25730. if (level >= 0) {
  25731. var address = me.selection
  25732. .getRange()
  25733. .selectNode(child)
  25734. .createAddress(true).startAddress,
  25735. current = getSection({
  25736. tag: child.tagName,
  25737. title: child.innerText || child.textContent || "",
  25738. level: level,
  25739. dom: child,
  25740. startAddress: utils.clone(address, []),
  25741. endAddress: utils.clone(address, []),
  25742. children: []
  25743. });
  25744. previous.nextSection = current;
  25745. current.previousSection = previous;
  25746. parent = previous;
  25747. while (level <= parent.level) {
  25748. parent = parent.parentSection;
  25749. }
  25750. current.parentSection = parent;
  25751. parent.children.push(current);
  25752. tmpSection = previous = current;
  25753. } else {
  25754. child.nodeType === 1 && traversal(child, Directory);
  25755. tmpSection &&
  25756. tmpSection.endAddress[tmpSection.endAddress.length - 1]++;
  25757. }
  25758. }
  25759. }
  25760. traversal(me.body, Directory);
  25761. return Directory;
  25762. },
  25763. notNeedUndo: true
  25764. },
  25765. movesection: {
  25766. execCommand: function (cmd, sourceSection, targetSection, isAfter) {
  25767. var me = this,
  25768. targetAddress,
  25769. target;
  25770. if (!sourceSection || !targetSection || targetSection.level == -1)
  25771. return;
  25772. targetAddress = isAfter
  25773. ? targetSection.endAddress
  25774. : targetSection.startAddress;
  25775. target = getNodeFromAddress(targetAddress, me.body);
  25776. /* 判断目标地址是否被源章节包含 */
  25777. if (
  25778. !targetAddress ||
  25779. !target ||
  25780. isContainsAddress(
  25781. sourceSection.startAddress,
  25782. sourceSection.endAddress,
  25783. targetAddress
  25784. )
  25785. )
  25786. return;
  25787. var startNode = getNodeFromAddress(
  25788. sourceSection.startAddress,
  25789. me.body
  25790. ),
  25791. endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
  25792. current,
  25793. nextNode;
  25794. if (isAfter) {
  25795. current = endNode;
  25796. while (
  25797. current &&
  25798. !(
  25799. domUtils.getPosition(startNode, current) &
  25800. domUtils.POSITION_FOLLOWING
  25801. )
  25802. ) {
  25803. nextNode = current.previousSibling;
  25804. domUtils.insertAfter(target, current);
  25805. if (current == startNode) break;
  25806. current = nextNode;
  25807. }
  25808. } else {
  25809. current = startNode;
  25810. while (
  25811. current &&
  25812. !(
  25813. domUtils.getPosition(current, endNode) &
  25814. domUtils.POSITION_FOLLOWING
  25815. )
  25816. ) {
  25817. nextNode = current.nextSibling;
  25818. target.parentNode.insertBefore(current, target);
  25819. if (current == endNode) break;
  25820. current = nextNode;
  25821. }
  25822. }
  25823. me.fireEvent("updateSections");
  25824. /* 获取地址的包含关系 */
  25825. function isContainsAddress(startAddress, endAddress, addressTarget) {
  25826. var isAfterStartAddress = false,
  25827. isBeforeEndAddress = false;
  25828. for (var i = 0; i < startAddress.length; i++) {
  25829. if (i >= addressTarget.length) break;
  25830. if (addressTarget[i] > startAddress[i]) {
  25831. isAfterStartAddress = true;
  25832. break;
  25833. } else if (addressTarget[i] < startAddress[i]) {
  25834. break;
  25835. }
  25836. }
  25837. for (var i = 0; i < endAddress.length; i++) {
  25838. if (i >= addressTarget.length) break;
  25839. if (addressTarget[i] < startAddress[i]) {
  25840. isBeforeEndAddress = true;
  25841. break;
  25842. } else if (addressTarget[i] > startAddress[i]) {
  25843. break;
  25844. }
  25845. }
  25846. return isAfterStartAddress && isBeforeEndAddress;
  25847. }
  25848. }
  25849. },
  25850. deletesection: {
  25851. execCommand: function (cmd, section, keepChildren) {
  25852. var me = this;
  25853. if (!section) return;
  25854. function getNodeFromAddress(startAddress) {
  25855. var current = me.body;
  25856. for (var i = 0; i < startAddress.length; i++) {
  25857. if (!current.childNodes) return null;
  25858. current = current.childNodes[startAddress[i]];
  25859. }
  25860. return current;
  25861. }
  25862. var startNode = getNodeFromAddress(section.startAddress),
  25863. endNode = getNodeFromAddress(section.endAddress),
  25864. current = startNode,
  25865. nextNode;
  25866. if (!keepChildren) {
  25867. while (
  25868. current &&
  25869. domUtils.inDoc(endNode, me.document) &&
  25870. !(
  25871. domUtils.getPosition(current, endNode) &
  25872. domUtils.POSITION_FOLLOWING
  25873. )
  25874. ) {
  25875. nextNode = current.nextSibling;
  25876. domUtils.remove(current);
  25877. current = nextNode;
  25878. }
  25879. } else {
  25880. domUtils.remove(current);
  25881. }
  25882. me.fireEvent("updateSections");
  25883. }
  25884. },
  25885. selectsection: {
  25886. execCommand: function (cmd, section) {
  25887. if (!section && !section.dom) return false;
  25888. var me = this,
  25889. range = me.selection.getRange(),
  25890. address = {
  25891. startAddress: utils.clone(section.startAddress, []),
  25892. endAddress: utils.clone(section.endAddress, [])
  25893. };
  25894. address.endAddress[address.endAddress.length - 1]++;
  25895. range.moveToAddress(address).select().scrollToView();
  25896. return true;
  25897. },
  25898. notNeedUndo: true
  25899. },
  25900. scrolltosection: {
  25901. execCommand: function (cmd, section) {
  25902. if (!section && !section.dom) return false;
  25903. var me = this,
  25904. range = me.selection.getRange(),
  25905. address = {
  25906. startAddress: section.startAddress,
  25907. endAddress: section.endAddress
  25908. };
  25909. address.endAddress[address.endAddress.length - 1]++;
  25910. range.moveToAddress(address).scrollToView();
  25911. return true;
  25912. },
  25913. notNeedUndo: true
  25914. }
  25915. }
  25916. };
  25917. });
  25918. // plugins/simpleupload.js
  25919. /**
  25920. * @description
  25921. * 简单上传:点击按钮,直接选择文件上传
  25922. * @author Jinqn
  25923. * @date 2014-03-31
  25924. */
  25925. UE.plugin.register("simpleupload", function () {
  25926. var me = this,
  25927. isLoaded = false,
  25928. containerBtn;
  25929. function initUploadBtn() {
  25930. var w = containerBtn.offsetWidth || 20,
  25931. h = containerBtn.offsetHeight || 20,
  25932. btnIframe = document.createElement("iframe"),
  25933. btnStyle =
  25934. "display:block;width:" +
  25935. w +
  25936. "px;height:" +
  25937. h +
  25938. "px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;";
  25939. domUtils.on(btnIframe, "load", function () {
  25940. var timestrap = (+new Date()).toString(36),
  25941. wrapper,
  25942. btnIframeDoc,
  25943. btnIframeBody;
  25944. btnIframeDoc =
  25945. btnIframe.contentDocument || btnIframe.contentWindow.document;
  25946. btnIframeBody = btnIframeDoc.body;
  25947. wrapper = btnIframeDoc.createElement("div");
  25948. wrapper.innerHTML =
  25949. '<form id="edui_form_' +
  25950. timestrap +
  25951. '" target="edui_iframe_' +
  25952. timestrap +
  25953. '" method="POST" enctype="multipart/form-data" action="' +
  25954. me.getOpt("serverUrl") +
  25955. '" ' +
  25956. 'style="' +
  25957. btnStyle +
  25958. '">' +
  25959. '<input id="edui_input_' +
  25960. timestrap +
  25961. '" type="file" accept="image/*" name="' +
  25962. me.options.imageFieldName +
  25963. '" ' +
  25964. 'style="' +
  25965. btnStyle +
  25966. '">' +
  25967. "</form>" +
  25968. '<iframe id="edui_iframe_' +
  25969. timestrap +
  25970. '" name="edui_iframe_' +
  25971. timestrap +
  25972. '" style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>';
  25973. wrapper.className = "edui-" + me.options.theme;
  25974. wrapper.id = me.ui.id + "_iframeupload";
  25975. btnIframeBody.style.cssText = btnStyle;
  25976. btnIframeBody.style.width = w + "px";
  25977. btnIframeBody.style.height = h + "px";
  25978. btnIframeBody.appendChild(wrapper);
  25979. if (btnIframeBody.parentNode) {
  25980. btnIframeBody.parentNode.style.width = w + "px";
  25981. btnIframeBody.parentNode.style.height = w + "px";
  25982. }
  25983. var form = btnIframeDoc.getElementById("edui_form_" + timestrap);
  25984. var input = btnIframeDoc.getElementById("edui_input_" + timestrap);
  25985. var iframe = btnIframeDoc.getElementById("edui_iframe_" + timestrap);
  25986. domUtils.on(input, "change", function () {
  25987. if (!input.value) return;
  25988. var loadingId = "loading_" + (+new Date()).toString(36);
  25989. var params =
  25990. utils.serializeParam(me.queryCommandValue("serverparam")) || "";
  25991. var imageActionUrl = me.getActionUrl(me.getOpt("imageActionName"));
  25992. var allowFiles = me.getOpt("imageAllowFiles");
  25993. me.focus();
  25994. me.execCommand(
  25995. "inserthtml",
  25996. '<img class="loadingclass" id="' +
  25997. loadingId +
  25998. '" src="' +
  25999. me.options.themePath +
  26000. me.options.theme +
  26001. '/images/spacer.gif">'
  26002. );
  26003. function callback() {
  26004. try {
  26005. var link,
  26006. json,
  26007. loader,
  26008. body = (iframe.contentDocument || iframe.contentWindow.document)
  26009. .body,
  26010. result = body.innerText || body.textContent || "";
  26011. json = new Function("return " + result)();
  26012. link = me.options.imageUrlPrefix + json.url;
  26013. if (json.state == "SUCCESS" && json.url) {
  26014. loader = me.document.getElementById(loadingId);
  26015. domUtils.removeClasses(loader, "loadingclass");
  26016. domUtils.on(loader, 'load', function () {
  26017. me.fireEvent('contentchange');
  26018. });
  26019. loader.setAttribute("src", link);
  26020. loader.setAttribute("_src", link);
  26021. loader.setAttribute("alt", json.original || "");
  26022. loader.removeAttribute("id");
  26023. } else {
  26024. showErrorLoader && showErrorLoader(json.state);
  26025. }
  26026. } catch (er) {
  26027. showErrorLoader &&
  26028. showErrorLoader(me.getLang("simpleupload.loadError"));
  26029. }
  26030. form.reset();
  26031. domUtils.un(iframe, "load", callback);
  26032. }
  26033. function showErrorLoader(title) {
  26034. if (loadingId) {
  26035. var loader = me.document.getElementById(loadingId);
  26036. loader && domUtils.remove(loader);
  26037. me.fireEvent("showmessage", {
  26038. id: loadingId,
  26039. content: title,
  26040. type: "error",
  26041. timeout: 4000
  26042. });
  26043. }
  26044. }
  26045. /* 判断后端配置是否没有加载成功 */
  26046. if (!me.getOpt("imageActionName")) {
  26047. errorHandler(me.getLang("autoupload.errorLoadConfig"));
  26048. return;
  26049. }
  26050. // 判断文件格式是否错误
  26051. var filename = input.value,
  26052. fileext = filename ? filename.substr(filename.lastIndexOf(".")) : "";
  26053. if (
  26054. !fileext ||
  26055. (allowFiles &&
  26056. (allowFiles.join("") + ".").indexOf(fileext.toLowerCase() + ".") ==
  26057. -1)
  26058. ) {
  26059. showErrorLoader(me.getLang("simpleupload.exceedTypeError"));
  26060. return;
  26061. }
  26062. domUtils.on(iframe, "load", callback);
  26063. form.action = utils.formatUrl(
  26064. imageActionUrl +
  26065. (imageActionUrl.indexOf("?") == -1 ? "?" : "&") +
  26066. params
  26067. );
  26068. form.submit();
  26069. });
  26070. var stateTimer;
  26071. me.addListener("selectionchange", function () {
  26072. clearTimeout(stateTimer);
  26073. stateTimer = setTimeout(function () {
  26074. var state = me.queryCommandState("simpleupload");
  26075. if (state == -1) {
  26076. input.disabled = "disabled";
  26077. } else {
  26078. input.disabled = false;
  26079. }
  26080. }, 400);
  26081. });
  26082. isLoaded = true;
  26083. });
  26084. btnIframe.style.cssText = btnStyle;
  26085. containerBtn.appendChild(btnIframe);
  26086. }
  26087. return {
  26088. bindEvents: {
  26089. ready: function () {
  26090. //设置loading的样式
  26091. utils.cssRule(
  26092. "loading",
  26093. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  26094. this.options.themePath +
  26095. this.options.theme +
  26096. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n" +
  26097. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  26098. this.options.themePath +
  26099. this.options.theme +
  26100. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  26101. "}",
  26102. this.document
  26103. );
  26104. },
  26105. /* 初始化简单上传按钮 */
  26106. simpleuploadbtnready: function (type, container) {
  26107. containerBtn = container;
  26108. me.afterConfigReady(initUploadBtn);
  26109. }
  26110. },
  26111. outputRule: function (root) {
  26112. utils.each(root.getNodesByTagName("img"), function (n) {
  26113. if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr("class"))) {
  26114. n.parentNode.removeChild(n);
  26115. }
  26116. });
  26117. },
  26118. commands: {
  26119. simpleupload: {
  26120. queryCommandState: function () {
  26121. return isLoaded ? 0 : -1;
  26122. }
  26123. }
  26124. }
  26125. };
  26126. });
  26127. // plugins/serverparam.js
  26128. /**
  26129. * 服务器提交的额外参数列表设置插件
  26130. * @file
  26131. * @since 1.2.6.1
  26132. */
  26133. UE.plugin.register("serverparam", function () {
  26134. var me = this,
  26135. serverParam = {};
  26136. return {
  26137. commands: {
  26138. /**
  26139. * 修改服务器提交的额外参数列表,清除所有项
  26140. * @command serverparam
  26141. * @method execCommand
  26142. * @param { String } cmd 命令字符串
  26143. * @example
  26144. * ```javascript
  26145. * editor.execCommand('serverparam');
  26146. * editor.queryCommandValue('serverparam'); //返回空
  26147. * ```
  26148. */
  26149. /**
  26150. * 修改服务器提交的额外参数列表,删除指定项
  26151. * @command serverparam
  26152. * @method execCommand
  26153. * @param { String } cmd 命令字符串
  26154. * @param { String } key 要清除的属性
  26155. * @example
  26156. * ```javascript
  26157. * editor.execCommand('serverparam', 'name'); //删除属性name
  26158. * ```
  26159. */
  26160. /**
  26161. * 修改服务器提交的额外参数列表,使用键值添加项
  26162. * @command serverparam
  26163. * @method execCommand
  26164. * @param { String } cmd 命令字符串
  26165. * @param { String } key 要添加的属性
  26166. * @param { String } value 要添加属性的值
  26167. * @example
  26168. * ```javascript
  26169. * editor.execCommand('serverparam', 'name', 'hello');
  26170. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  26171. * ```
  26172. */
  26173. /**
  26174. * 修改服务器提交的额外参数列表,传入键值对对象添加多项
  26175. * @command serverparam
  26176. * @method execCommand
  26177. * @param { String } cmd 命令字符串
  26178. * @param { Object } key 传入的键值对对象
  26179. * @example
  26180. * ```javascript
  26181. * editor.execCommand('serverparam', {'name': 'hello'});
  26182. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  26183. * ```
  26184. */
  26185. /**
  26186. * 修改服务器提交的额外参数列表,使用自定义函数添加多项
  26187. * @command serverparam
  26188. * @method execCommand
  26189. * @param { String } cmd 命令字符串
  26190. * @param { Function } key 自定义获取参数的函数
  26191. * @example
  26192. * ```javascript
  26193. * editor.execCommand('serverparam', function(editor){
  26194. * return {'key': 'value'};
  26195. * });
  26196. * editor.queryCommandValue('serverparam'); //返回对象 {'key': 'value'}
  26197. * ```
  26198. */
  26199. /**
  26200. * 获取服务器提交的额外参数列表
  26201. * @command serverparam
  26202. * @method queryCommandValue
  26203. * @param { String } cmd 命令字符串
  26204. * @example
  26205. * ```javascript
  26206. * editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'}
  26207. * ```
  26208. */
  26209. serverparam: {
  26210. execCommand: function (cmd, key, value) {
  26211. if (key === undefined || key === null) {
  26212. //不传参数,清空列表
  26213. serverParam = {};
  26214. } else if (utils.isString(key)) {
  26215. //传入键值
  26216. if (value === undefined || value === null) {
  26217. delete serverParam[key];
  26218. } else {
  26219. serverParam[key] = value;
  26220. }
  26221. } else if (utils.isObject(key)) {
  26222. //传入对象,覆盖列表项
  26223. utils.extend(serverParam, key, false);
  26224. } else if (utils.isFunction(key)) {
  26225. //传入函数,添加列表项
  26226. utils.extend(serverParam, key(), false);
  26227. }
  26228. },
  26229. queryCommandValue: function () {
  26230. return serverParam || {};
  26231. }
  26232. }
  26233. }
  26234. };
  26235. });
  26236. // plugins/insertfile.js
  26237. /**
  26238. * 插入附件
  26239. */
  26240. UE.plugin.register("insertfile", function () {
  26241. var me = this;
  26242. function getFileIcon(url) {
  26243. var ext = url.substr(url.lastIndexOf(".") + 1).toLowerCase(),
  26244. maps = {
  26245. rar: "icon_rar.gif",
  26246. zip: "icon_rar.gif",
  26247. tar: "icon_rar.gif",
  26248. gz: "icon_rar.gif",
  26249. bz2: "icon_rar.gif",
  26250. doc: "icon_doc.gif",
  26251. docx: "icon_doc.gif",
  26252. pdf: "icon_pdf.gif",
  26253. mp3: "icon_mp3.gif",
  26254. xls: "icon_xls.gif",
  26255. chm: "icon_chm.gif",
  26256. ppt: "icon_ppt.gif",
  26257. pptx: "icon_ppt.gif",
  26258. avi: "icon_mv.gif",
  26259. rmvb: "icon_mv.gif",
  26260. wmv: "icon_mv.gif",
  26261. flv: "icon_mv.gif",
  26262. swf: "icon_mv.gif",
  26263. rm: "icon_mv.gif",
  26264. exe: "icon_exe.gif",
  26265. psd: "icon_psd.gif",
  26266. txt: "icon_txt.gif",
  26267. jpg: "icon_jpg.gif",
  26268. png: "icon_jpg.gif",
  26269. jpeg: "icon_jpg.gif",
  26270. gif: "icon_jpg.gif",
  26271. ico: "icon_jpg.gif",
  26272. bmp: "icon_jpg.gif"
  26273. };
  26274. return maps[ext] ? maps[ext] : maps["txt"];
  26275. }
  26276. return {
  26277. commands: {
  26278. insertfile: {
  26279. execCommand: function (command, filelist) {
  26280. filelist = utils.isArray(filelist) ? filelist : [filelist];
  26281. if (me.fireEvent("beforeinsertfile", filelist) === true) {
  26282. return;
  26283. }
  26284. var i,
  26285. item,
  26286. icon,
  26287. title,
  26288. html = "",
  26289. URL = me.getOpt("UEDITOR_HOME_URL"),
  26290. iconDir =
  26291. URL +
  26292. (URL.substr(URL.length - 1) == "/" ? "" : "/") +
  26293. "dialogs/attachment/fileTypeImages/";
  26294. for (i = 0; i < filelist.length; i++) {
  26295. item = filelist[i];
  26296. icon = iconDir + getFileIcon(item.url);
  26297. title =
  26298. item.title || item.url.substr(item.url.lastIndexOf("/") + 1);
  26299. html +=
  26300. '<p style="line-height: 16px;">' +
  26301. '<img style="vertical-align: middle; margin-right: 2px;" src="' +
  26302. icon +
  26303. '" _src="' +
  26304. icon +
  26305. '" />' +
  26306. '<a style="font-size:12px; color:#0066cc;" href="' +
  26307. item.url +
  26308. '" title="' +
  26309. title +
  26310. '">' +
  26311. title +
  26312. "</a>" +
  26313. "</p>";
  26314. }
  26315. me.execCommand("insertHtml", html);
  26316. me.fireEvent("afterinsertfile", filelist);
  26317. }
  26318. }
  26319. }
  26320. };
  26321. });
  26322. // plugins/xssFilter.js
  26323. /**
  26324. * @file xssFilter.js
  26325. * @desc xss过滤器
  26326. * @author robbenmu
  26327. */
  26328. UE.plugins.xssFilter = function () {
  26329. var config = UEDITOR_CONFIG;
  26330. var whitList = config.whitList;
  26331. function filter(node) {
  26332. var tagName = node.tagName;
  26333. var attrs = node.attrs;
  26334. if (!whitList.hasOwnProperty(tagName)) {
  26335. node.parentNode.removeChild(node);
  26336. return false;
  26337. }
  26338. UE.utils.each(attrs, function (val, key) {
  26339. if (whitList[tagName].indexOf(key) === -1) {
  26340. node.setAttr(key);
  26341. }
  26342. });
  26343. }
  26344. // 添加inserthtml\paste等操作用的过滤规则
  26345. if (whitList && config.xssFilterRules) {
  26346. this.options.filterRules = function () {
  26347. var result = {};
  26348. UE.utils.each(whitList, function (val, key) {
  26349. result[key] = function (node) {
  26350. return filter(node);
  26351. };
  26352. });
  26353. return result;
  26354. }();
  26355. }
  26356. var tagList = [];
  26357. UE.utils.each(whitList, function (val, key) {
  26358. tagList.push(key);
  26359. });
  26360. // 添加input过滤规则
  26361. //
  26362. if (whitList && config.inputXssFilter) {
  26363. this.addInputRule(function (root) {
  26364. root.traversal(function (node) {
  26365. if (node.type !== 'element') {
  26366. return false;
  26367. }
  26368. filter(node);
  26369. });
  26370. });
  26371. }
  26372. // 添加output过滤规则
  26373. //
  26374. if (whitList && config.outputXssFilter) {
  26375. this.addOutputRule(function (root) {
  26376. root.traversal(function (node) {
  26377. if (node.type !== 'element') {
  26378. return false;
  26379. }
  26380. filter(node);
  26381. });
  26382. });
  26383. }
  26384. };
  26385. // ui/ui.js
  26386. var baidu = baidu || {};
  26387. baidu.editor = baidu.editor || {};
  26388. UE.ui = baidu.editor.ui = {};
  26389. // ui/uiutils.js
  26390. ;(function () {
  26391. var browser = baidu.editor.browser,
  26392. domUtils = baidu.editor.dom.domUtils;
  26393. var magic = "$EDITORUI";
  26394. var root = (window[magic] = {});
  26395. var uidMagic = "ID" + magic;
  26396. var uidCount = 0;
  26397. var uiUtils = (baidu.editor.ui.uiUtils = {
  26398. uid: function (obj) {
  26399. return obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount;
  26400. },
  26401. hook: function (fn, callback) {
  26402. var dg;
  26403. if (fn && fn._callbacks) {
  26404. dg = fn;
  26405. } else {
  26406. dg = function () {
  26407. var q;
  26408. if (fn) {
  26409. q = fn.apply(this, arguments);
  26410. }
  26411. var callbacks = dg._callbacks;
  26412. var k = callbacks.length;
  26413. while (k--) {
  26414. var r = callbacks[k].apply(this, arguments);
  26415. if (q === undefined) {
  26416. q = r;
  26417. }
  26418. }
  26419. return q;
  26420. };
  26421. dg._callbacks = [];
  26422. }
  26423. dg._callbacks.push(callback);
  26424. return dg;
  26425. },
  26426. createElementByHtml: function (html) {
  26427. var el = document.createElement("div");
  26428. el.innerHTML = html;
  26429. el = el.firstChild;
  26430. el.parentNode.removeChild(el);
  26431. return el;
  26432. },
  26433. getViewportElement: function () {
  26434. return browser.ie && browser.quirks
  26435. ? document.body
  26436. : document.documentElement;
  26437. },
  26438. getClientRect: function (element) {
  26439. var bcr;
  26440. //trace IE6下在控制编辑器显隐时可能会报错,catch一下
  26441. try {
  26442. bcr = element.getBoundingClientRect();
  26443. } catch (e) {
  26444. bcr = {left: 0, top: 0, height: 0, width: 0};
  26445. }
  26446. var rect = {
  26447. left: Math.round(bcr.left),
  26448. top: Math.round(bcr.top),
  26449. height: Math.round(bcr.bottom - bcr.top),
  26450. width: Math.round(bcr.right - bcr.left)
  26451. };
  26452. var doc;
  26453. while (
  26454. (doc = element.ownerDocument) !== document &&
  26455. (element = domUtils.getWindow(doc).frameElement)
  26456. ) {
  26457. bcr = element.getBoundingClientRect();
  26458. rect.left += bcr.left;
  26459. rect.top += bcr.top;
  26460. }
  26461. rect.bottom = rect.top + rect.height;
  26462. rect.right = rect.left + rect.width;
  26463. return rect;
  26464. },
  26465. getViewportRect: function () {
  26466. var viewportEl = uiUtils.getViewportElement();
  26467. var width = (window.innerWidth || viewportEl.clientWidth) | 0;
  26468. var height = (window.innerHeight || viewportEl.clientHeight) | 0;
  26469. return {
  26470. left: 0,
  26471. top: 0,
  26472. height: height,
  26473. width: width,
  26474. bottom: height,
  26475. right: width
  26476. };
  26477. },
  26478. setViewportOffset: function (element, offset) {
  26479. var rect;
  26480. var fixedLayer = uiUtils.getFixedLayer();
  26481. if (element.parentNode === fixedLayer) {
  26482. element.style.left = offset.left + "px";
  26483. element.style.top = offset.top + "px";
  26484. } else {
  26485. domUtils.setViewportOffset(element, offset);
  26486. }
  26487. },
  26488. getEventOffset: function (evt) {
  26489. var el = evt.target || evt.srcElement;
  26490. var rect = uiUtils.getClientRect(el);
  26491. var offset = uiUtils.getViewportOffsetByEvent(evt);
  26492. return {
  26493. left: offset.left - rect.left,
  26494. top: offset.top - rect.top
  26495. };
  26496. },
  26497. getViewportOffsetByEvent: function (evt) {
  26498. var el = evt.target || evt.srcElement;
  26499. var frameEl = domUtils.getWindow(el).frameElement;
  26500. var offset = {
  26501. left: evt.clientX,
  26502. top: evt.clientY
  26503. };
  26504. if (frameEl && el.ownerDocument !== document) {
  26505. var rect = uiUtils.getClientRect(frameEl);
  26506. offset.left += rect.left;
  26507. offset.top += rect.top;
  26508. }
  26509. return offset;
  26510. },
  26511. setGlobal: function (id, obj) {
  26512. root[id] = obj;
  26513. return magic + '["' + id + '"]';
  26514. },
  26515. unsetGlobal: function (id) {
  26516. delete root[id];
  26517. },
  26518. copyAttributes: function (tgt, src) {
  26519. var attributes = src.attributes;
  26520. var k = attributes.length;
  26521. while (k--) {
  26522. var attrNode = attributes[k];
  26523. if (
  26524. attrNode.nodeName != "style" &&
  26525. attrNode.nodeName != "class" &&
  26526. (!browser.ie || attrNode.specified)
  26527. ) {
  26528. tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue);
  26529. }
  26530. }
  26531. if (src.className) {
  26532. domUtils.addClass(tgt, src.className);
  26533. }
  26534. if (src.style.cssText) {
  26535. tgt.style.cssText += ";" + src.style.cssText;
  26536. }
  26537. },
  26538. removeStyle: function (el, styleName) {
  26539. if (el.style.removeProperty) {
  26540. el.style.removeProperty(styleName);
  26541. } else if (el.style.removeAttribute) {
  26542. el.style.removeAttribute(styleName);
  26543. } else throw "";
  26544. },
  26545. contains: function (elA, elB) {
  26546. return (
  26547. elA &&
  26548. elB &&
  26549. (elA === elB
  26550. ? false
  26551. : elA.contains
  26552. ? elA.contains(elB)
  26553. : elA.compareDocumentPosition(elB) & 16)
  26554. );
  26555. },
  26556. startDrag: function (evt, callbacks, doc) {
  26557. var doc = doc || document;
  26558. var startX = evt.clientX;
  26559. var startY = evt.clientY;
  26560. function handleMouseMove(evt) {
  26561. var x = evt.clientX - startX;
  26562. var y = evt.clientY - startY;
  26563. callbacks.ondragmove(x, y, evt);
  26564. if (evt.stopPropagation) {
  26565. evt.stopPropagation();
  26566. } else {
  26567. evt.cancelBubble = true;
  26568. }
  26569. }
  26570. if (doc.addEventListener) {
  26571. function handleMouseUp(evt) {
  26572. doc.removeEventListener("mousemove", handleMouseMove, true);
  26573. doc.removeEventListener("mouseup", handleMouseUp, true);
  26574. window.removeEventListener("mouseup", handleMouseUp, true);
  26575. callbacks.ondragstop();
  26576. }
  26577. doc.addEventListener("mousemove", handleMouseMove, true);
  26578. doc.addEventListener("mouseup", handleMouseUp, true);
  26579. window.addEventListener("mouseup", handleMouseUp, true);
  26580. evt.preventDefault();
  26581. } else {
  26582. var elm = evt.srcElement;
  26583. elm.setCapture();
  26584. function releaseCaptrue() {
  26585. elm.releaseCapture();
  26586. elm.detachEvent("onmousemove", handleMouseMove);
  26587. elm.detachEvent("onmouseup", releaseCaptrue);
  26588. elm.detachEvent("onlosecaptrue", releaseCaptrue);
  26589. callbacks.ondragstop();
  26590. }
  26591. elm.attachEvent("onmousemove", handleMouseMove);
  26592. elm.attachEvent("onmouseup", releaseCaptrue);
  26593. elm.attachEvent("onlosecaptrue", releaseCaptrue);
  26594. evt.returnValue = false;
  26595. }
  26596. callbacks.ondragstart();
  26597. },
  26598. getFixedLayer: function () {
  26599. var layer = document.getElementById("edui_fixedlayer");
  26600. if (layer == null) {
  26601. layer = document.createElement("div");
  26602. layer.id = "edui_fixedlayer";
  26603. document.body.appendChild(layer);
  26604. if (browser.ie && browser.version <= 8) {
  26605. layer.style.position = "absolute";
  26606. bindFixedLayer();
  26607. setTimeout(updateFixedOffset);
  26608. } else {
  26609. layer.style.position = "fixed";
  26610. }
  26611. layer.style.left = "0";
  26612. layer.style.top = "0";
  26613. layer.style.width = "0";
  26614. layer.style.height = "0";
  26615. }
  26616. return layer;
  26617. },
  26618. makeUnselectable: function (element) {
  26619. if (browser.opera || (browser.ie && browser.version < 9)) {
  26620. element.unselectable = "on";
  26621. if (element.hasChildNodes()) {
  26622. for (var i = 0; i < element.childNodes.length; i++) {
  26623. if (element.childNodes[i].nodeType == 1) {
  26624. uiUtils.makeUnselectable(element.childNodes[i]);
  26625. }
  26626. }
  26627. }
  26628. } else {
  26629. if (element.style.MozUserSelect !== undefined) {
  26630. element.style.MozUserSelect = "none";
  26631. } else if (element.style.WebkitUserSelect !== undefined) {
  26632. element.style.WebkitUserSelect = "none";
  26633. } else if (element.style.KhtmlUserSelect !== undefined) {
  26634. element.style.KhtmlUserSelect = "none";
  26635. }
  26636. }
  26637. }
  26638. });
  26639. function updateFixedOffset() {
  26640. var layer = document.getElementById("edui_fixedlayer");
  26641. uiUtils.setViewportOffset(layer, {
  26642. left: 0,
  26643. top: 0
  26644. });
  26645. // layer.style.display = 'none';
  26646. // layer.style.display = 'block';
  26647. //#trace: 1354
  26648. // setTimeout(updateFixedOffset);
  26649. }
  26650. function bindFixedLayer(adjOffset) {
  26651. domUtils.on(window, "scroll", updateFixedOffset);
  26652. domUtils.on(
  26653. window,
  26654. "resize",
  26655. baidu.editor.utils.defer(updateFixedOffset, 0, true)
  26656. );
  26657. }
  26658. })();
  26659. // ui/uibase.js
  26660. ;(function () {
  26661. var utils = baidu.editor.utils,
  26662. uiUtils = baidu.editor.ui.uiUtils,
  26663. EventBase = baidu.editor.EventBase,
  26664. UIBase = (baidu.editor.ui.UIBase = function () {
  26665. });
  26666. UIBase.prototype = {
  26667. className: "",
  26668. uiName: "",
  26669. initOptions: function (options) {
  26670. var me = this;
  26671. for (var k in options) {
  26672. me[k] = options[k];
  26673. }
  26674. this.id = this.id || "edui" + uiUtils.uid();
  26675. },
  26676. initUIBase: function () {
  26677. this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this));
  26678. },
  26679. render: function (holder) {
  26680. var html = this.renderHtml();
  26681. var el = uiUtils.createElementByHtml(html);
  26682. //by xuheng 给每个node添加class
  26683. var list = domUtils.getElementsByTagName(el, "*");
  26684. var theme = "edui-" + (this.theme || this.editor.options.theme);
  26685. var layer = document.getElementById("edui_fixedlayer");
  26686. for (var i = 0, node; (node = list[i++]);) {
  26687. domUtils.addClass(node, theme);
  26688. }
  26689. domUtils.addClass(el, theme);
  26690. if (layer) {
  26691. layer.className = "";
  26692. domUtils.addClass(layer, theme);
  26693. }
  26694. var seatEl = this.getDom();
  26695. if (seatEl != null) {
  26696. seatEl.parentNode.replaceChild(el, seatEl);
  26697. uiUtils.copyAttributes(el, seatEl);
  26698. } else {
  26699. if (typeof holder == "string") {
  26700. holder = document.getElementById(holder);
  26701. }
  26702. holder = holder || uiUtils.getFixedLayer();
  26703. domUtils.addClass(holder, theme);
  26704. holder.appendChild(el);
  26705. }
  26706. this.postRender();
  26707. },
  26708. getDom: function (name) {
  26709. if (!name) {
  26710. return document.getElementById(this.id);
  26711. } else {
  26712. return document.getElementById(this.id + "_" + name);
  26713. }
  26714. },
  26715. postRender: function () {
  26716. this.fireEvent("postrender");
  26717. },
  26718. getHtmlTpl: function () {
  26719. return "";
  26720. },
  26721. formatHtml: function (tpl) {
  26722. var prefix = "edui-" + this.uiName;
  26723. return tpl
  26724. .replace(/##/g, this.id)
  26725. .replace(/%%-/g, this.uiName ? prefix + "-" : "")
  26726. .replace(/%%/g, (this.uiName ? prefix : "") + " " + this.className)
  26727. .replace(/\$\$/g, this._globalKey);
  26728. },
  26729. renderHtml: function () {
  26730. return this.formatHtml(this.getHtmlTpl());
  26731. },
  26732. dispose: function () {
  26733. var box = this.getDom();
  26734. if (box) baidu.editor.dom.domUtils.remove(box);
  26735. uiUtils.unsetGlobal(this.id);
  26736. }
  26737. };
  26738. utils.inherits(UIBase, EventBase);
  26739. })();
  26740. // ui/separator.js
  26741. ;(function () {
  26742. var utils = baidu.editor.utils,
  26743. UIBase = baidu.editor.ui.UIBase,
  26744. Separator = (baidu.editor.ui.Separator = function (options) {
  26745. this.initOptions(options);
  26746. this.initSeparator();
  26747. });
  26748. Separator.prototype = {
  26749. uiName: "separator",
  26750. initSeparator: function () {
  26751. this.initUIBase();
  26752. },
  26753. getHtmlTpl: function () {
  26754. return '<div id="##" class="edui-box %%"></div>';
  26755. }
  26756. };
  26757. utils.inherits(Separator, UIBase);
  26758. })();
  26759. // ui/mask.js
  26760. ///import core
  26761. ///import uicore
  26762. ;(function () {
  26763. var utils = baidu.editor.utils,
  26764. domUtils = baidu.editor.dom.domUtils,
  26765. UIBase = baidu.editor.ui.UIBase,
  26766. uiUtils = baidu.editor.ui.uiUtils;
  26767. var Mask = (baidu.editor.ui.Mask = function (options) {
  26768. this.initOptions(options);
  26769. this.initUIBase();
  26770. });
  26771. Mask.prototype = {
  26772. getHtmlTpl: function () {
  26773. return '<div id="##" class="edui-mask %%" onclick="return $$._onClick(event, this);" onmousedown="return $$._onMouseDown(event, this);"></div>';
  26774. },
  26775. postRender: function () {
  26776. var me = this;
  26777. domUtils.on(window, "resize", function () {
  26778. setTimeout(function () {
  26779. if (!me.isHidden()) {
  26780. me._fill();
  26781. }
  26782. });
  26783. });
  26784. },
  26785. show: function (zIndex) {
  26786. this._fill();
  26787. this.getDom().style.display = "";
  26788. this.getDom().style.zIndex = zIndex;
  26789. },
  26790. hide: function () {
  26791. this.getDom().style.display = "none";
  26792. this.getDom().style.zIndex = "";
  26793. },
  26794. isHidden: function () {
  26795. return this.getDom().style.display == "none";
  26796. },
  26797. _onMouseDown: function () {
  26798. return false;
  26799. },
  26800. _onClick: function (e, target) {
  26801. this.fireEvent("click", e, target);
  26802. },
  26803. _fill: function () {
  26804. var el = this.getDom();
  26805. var vpRect = uiUtils.getViewportRect();
  26806. el.style.width = vpRect.width + "px";
  26807. el.style.height = vpRect.height + "px";
  26808. }
  26809. };
  26810. utils.inherits(Mask, UIBase);
  26811. })();
  26812. // ui/popup.js
  26813. ///import core
  26814. ///import uicore
  26815. ;(function () {
  26816. var utils = baidu.editor.utils,
  26817. uiUtils = baidu.editor.ui.uiUtils,
  26818. domUtils = baidu.editor.dom.domUtils,
  26819. UIBase = baidu.editor.ui.UIBase,
  26820. Popup = (baidu.editor.ui.Popup = function (options) {
  26821. this.initOptions(options);
  26822. this.initPopup();
  26823. });
  26824. var allPopups = [];
  26825. function closeAllPopup(evt, el) {
  26826. for (var i = 0; i < allPopups.length; i++) {
  26827. var pop = allPopups[i];
  26828. if (!pop.isHidden()) {
  26829. if (pop.queryAutoHide(el) !== false) {
  26830. if (
  26831. evt &&
  26832. /scroll/gi.test(evt.type) &&
  26833. pop.className == "edui-wordpastepop"
  26834. )
  26835. return;
  26836. pop.hide();
  26837. }
  26838. }
  26839. }
  26840. if (allPopups.length) pop.editor.fireEvent("afterhidepop");
  26841. }
  26842. Popup.postHide = closeAllPopup;
  26843. var ANCHOR_CLASSES = [
  26844. "edui-anchor-topleft",
  26845. "edui-anchor-topright",
  26846. "edui-anchor-bottomleft",
  26847. "edui-anchor-bottomright"
  26848. ];
  26849. Popup.prototype = {
  26850. SHADOW_RADIUS: 5,
  26851. content: null,
  26852. _hidden: false,
  26853. autoRender: true,
  26854. canSideLeft: true,
  26855. canSideUp: true,
  26856. initPopup: function () {
  26857. this.initUIBase();
  26858. allPopups.push(this);
  26859. },
  26860. getHtmlTpl: function () {
  26861. return (
  26862. '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
  26863. ' <div id="##_body" class="edui-popup-body">' +
  26864. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  26865. ' <div class="edui-shadow"></div>' +
  26866. ' <div id="##_content" class="edui-popup-content">' +
  26867. this.getContentHtmlTpl() +
  26868. " </div>" +
  26869. " </div>" +
  26870. "</div>"
  26871. );
  26872. },
  26873. getContentHtmlTpl: function () {
  26874. if (this.content) {
  26875. if (typeof this.content == "string") {
  26876. return this.content;
  26877. }
  26878. return this.content.renderHtml();
  26879. } else {
  26880. return "";
  26881. }
  26882. },
  26883. _UIBase_postRender: UIBase.prototype.postRender,
  26884. postRender: function () {
  26885. if (this.content instanceof UIBase) {
  26886. this.content.postRender();
  26887. }
  26888. //捕获鼠标滚轮
  26889. if (this.captureWheel && !this.captured) {
  26890. this.captured = true;
  26891. var winHeight =
  26892. (document.documentElement.clientHeight ||
  26893. document.body.clientHeight) - 80,
  26894. _height = this.getDom().offsetHeight,
  26895. _top = uiUtils.getClientRect(this.combox.getDom()).top,
  26896. content = this.getDom("content"),
  26897. ifr = this.getDom("body").getElementsByTagName("iframe"),
  26898. me = this;
  26899. ifr.length && (ifr = ifr[0]);
  26900. while (_top + _height > winHeight) {
  26901. _height -= 30;
  26902. }
  26903. content.style.height = _height + "px";
  26904. //同步更改iframe高度
  26905. ifr && (ifr.style.height = _height + "px");
  26906. //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
  26907. if (window.XMLHttpRequest) {
  26908. domUtils.on(
  26909. content,
  26910. "onmousewheel" in document.body ? "mousewheel" : "DOMMouseScroll",
  26911. function (e) {
  26912. if (e.preventDefault) {
  26913. e.preventDefault();
  26914. } else {
  26915. e.returnValue = false;
  26916. }
  26917. if (e.wheelDelta) {
  26918. content.scrollTop -= e.wheelDelta / 120 * 60;
  26919. } else {
  26920. content.scrollTop -= e.detail / -3 * 60;
  26921. }
  26922. }
  26923. );
  26924. } else {
  26925. //ie6
  26926. domUtils.on(this.getDom(), "mousewheel", function (e) {
  26927. e.returnValue = false;
  26928. me.getDom("content").scrollTop -= e.wheelDelta / 120 * 60;
  26929. });
  26930. }
  26931. }
  26932. this.fireEvent("postRenderAfter");
  26933. this.hide(true);
  26934. this._UIBase_postRender();
  26935. },
  26936. _doAutoRender: function () {
  26937. if (!this.getDom() && this.autoRender) {
  26938. this.render();
  26939. }
  26940. },
  26941. mesureSize: function () {
  26942. var box = this.getDom("content");
  26943. return uiUtils.getClientRect(box);
  26944. },
  26945. fitSize: function () {
  26946. if (this.captureWheel && this.sized) {
  26947. return this.__size;
  26948. }
  26949. this.sized = true;
  26950. var popBodyEl = this.getDom("body");
  26951. popBodyEl.style.width = "";
  26952. popBodyEl.style.height = "";
  26953. var size = this.mesureSize();
  26954. if (this.captureWheel) {
  26955. popBodyEl.style.width = -(-20 - size.width) + "px";
  26956. var height = parseInt(this.getDom("content").style.height, 10);
  26957. !window.isNaN(height) && (size.height = height);
  26958. } else {
  26959. popBodyEl.style.width = size.width + "px";
  26960. }
  26961. popBodyEl.style.height = size.height + "px";
  26962. this.__size = size;
  26963. this.captureWheel && (this.getDom("content").style.overflow = "auto");
  26964. return size;
  26965. },
  26966. showAnchor: function (element, hoz) {
  26967. this.showAnchorRect(uiUtils.getClientRect(element), hoz);
  26968. },
  26969. showAnchorRect: function (rect, hoz, adj) {
  26970. this._doAutoRender();
  26971. var vpRect = uiUtils.getViewportRect();
  26972. this.getDom().style.visibility = "hidden";
  26973. this._show();
  26974. var popSize = this.fitSize();
  26975. var sideLeft, sideUp, left, top;
  26976. if (hoz) {
  26977. sideLeft =
  26978. this.canSideLeft &&
  26979. (rect.right + popSize.width > vpRect.right &&
  26980. rect.left > popSize.width);
  26981. sideUp =
  26982. this.canSideUp &&
  26983. (rect.top + popSize.height > vpRect.bottom &&
  26984. rect.bottom > popSize.height);
  26985. left = sideLeft ? rect.left - popSize.width : rect.right;
  26986. top = sideUp ? rect.bottom - popSize.height : rect.top;
  26987. } else {
  26988. sideLeft =
  26989. this.canSideLeft &&
  26990. (rect.right + popSize.width > vpRect.right &&
  26991. rect.left > popSize.width);
  26992. sideUp =
  26993. this.canSideUp &&
  26994. (rect.top + popSize.height > vpRect.bottom &&
  26995. rect.bottom > popSize.height);
  26996. left = sideLeft ? rect.right - popSize.width : rect.left;
  26997. top = sideUp ? rect.top - popSize.height : rect.bottom;
  26998. }
  26999. var popEl = this.getDom();
  27000. uiUtils.setViewportOffset(popEl, {
  27001. left: left,
  27002. top: top
  27003. });
  27004. domUtils.removeClasses(popEl, ANCHOR_CLASSES);
  27005. popEl.className +=
  27006. " " + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
  27007. if (this.editor) {
  27008. popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
  27009. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
  27010. popEl.style.zIndex - 1;
  27011. }
  27012. this.getDom().style.visibility = "visible";
  27013. },
  27014. showAt: function (offset) {
  27015. var left = offset.left;
  27016. var top = offset.top;
  27017. var rect = {
  27018. left: left,
  27019. top: top,
  27020. right: left,
  27021. bottom: top,
  27022. height: 0,
  27023. width: 0
  27024. };
  27025. this.showAnchorRect(rect, false, true);
  27026. },
  27027. _show: function () {
  27028. if (this._hidden) {
  27029. var box = this.getDom();
  27030. box.style.display = "";
  27031. this._hidden = false;
  27032. // if (box.setActive) {
  27033. // box.setActive();
  27034. // }
  27035. this.fireEvent("show");
  27036. }
  27037. },
  27038. isHidden: function () {
  27039. return this._hidden;
  27040. },
  27041. show: function () {
  27042. this._doAutoRender();
  27043. this._show();
  27044. },
  27045. hide: function (notNofity) {
  27046. if (!this._hidden && this.getDom()) {
  27047. this.getDom().style.display = "none";
  27048. this._hidden = true;
  27049. if (!notNofity) {
  27050. this.fireEvent("hide");
  27051. }
  27052. }
  27053. },
  27054. queryAutoHide: function (el) {
  27055. return !el || !uiUtils.contains(this.getDom(), el);
  27056. }
  27057. };
  27058. utils.inherits(Popup, UIBase);
  27059. domUtils.on(document, "mousedown", function (evt) {
  27060. var el = evt.target || evt.srcElement;
  27061. closeAllPopup(evt, el);
  27062. });
  27063. domUtils.on(window, "scroll", function (evt, el) {
  27064. closeAllPopup(evt, el);
  27065. });
  27066. })();
  27067. // ui/colorpicker.js
  27068. ///import core
  27069. ///import uicore
  27070. ;(function () {
  27071. var utils = baidu.editor.utils,
  27072. UIBase = baidu.editor.ui.UIBase,
  27073. ColorPicker = (baidu.editor.ui.ColorPicker = function (options) {
  27074. this.initOptions(options);
  27075. this.noColorText = this.noColorText || this.editor.getLang("clearColor");
  27076. this.initUIBase();
  27077. });
  27078. ColorPicker.prototype = {
  27079. getHtmlTpl: function () {
  27080. return genColorPicker(this.noColorText, this.editor);
  27081. },
  27082. _onTableClick: function (evt) {
  27083. var tgt = evt.target || evt.srcElement;
  27084. var color = tgt.getAttribute("data-color");
  27085. if (color) {
  27086. this.fireEvent("pickcolor", color);
  27087. }
  27088. },
  27089. _onTableOver: function (evt) {
  27090. var tgt = evt.target || evt.srcElement;
  27091. var color = tgt.getAttribute("data-color");
  27092. if (color) {
  27093. this.getDom("preview").style.backgroundColor = color;
  27094. }
  27095. },
  27096. _onTableOut: function () {
  27097. this.getDom("preview").style.backgroundColor = "";
  27098. },
  27099. _onPickNoColor: function () {
  27100. this.fireEvent("picknocolor");
  27101. }
  27102. };
  27103. utils.inherits(ColorPicker, UIBase);
  27104. var COLORS = ("ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646," +
  27105. "f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada," +
  27106. "d8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5," +
  27107. "bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f," +
  27108. "a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09," +
  27109. "7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806," +
  27110. "c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,").split(
  27111. ","
  27112. );
  27113. function genColorPicker(noColorText, editor) {
  27114. var html =
  27115. '<div id="##" class="edui-colorpicker %%">' +
  27116. '<div class="edui-colorpicker-topbar edui-clearfix">' +
  27117. '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
  27118. '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">' +
  27119. noColorText +
  27120. "</div>" +
  27121. "</div>" +
  27122. '<table class="edui-box" style="border-collapse: collapse;" onmouseover="$$._onTableOver(event, this);" onmouseout="$$._onTableOut(event, this);" onclick="return $$._onTableClick(event, this);" cellspacing="0" cellpadding="0">' +
  27123. '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;padding-top: 2px"><td colspan="10">' +
  27124. editor.getLang("themeColor") +
  27125. "</td> </tr>" +
  27126. '<tr class="edui-colorpicker-tablefirstrow" >';
  27127. for (var i = 0; i < COLORS.length; i++) {
  27128. if (i && i % 10 === 0) {
  27129. html +=
  27130. "</tr>" +
  27131. (i == 60
  27132. ? '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;"><td colspan="10">' +
  27133. editor.getLang("standardColor") +
  27134. "</td></tr>"
  27135. : "") +
  27136. "<tr" +
  27137. (i == 60 ? ' class="edui-colorpicker-tablefirstrow"' : "") +
  27138. ">";
  27139. }
  27140. html += i < 70
  27141. ? '<td style="padding: 0 2px;"><a hidefocus title="' +
  27142. COLORS[i] +
  27143. '" onclick="return false;" href="javascript:" unselectable="on" class="edui-box edui-colorpicker-colorcell"' +
  27144. ' data-color="#' +
  27145. COLORS[i] +
  27146. '"' +
  27147. ' style="background-color:#' +
  27148. COLORS[i] +
  27149. ";border:solid #ccc;" +
  27150. (i < 10 || i >= 60
  27151. ? "border-width:1px;"
  27152. : i >= 10 && i < 20
  27153. ? "border-width:1px 1px 0 1px;"
  27154. : "border-width:0 1px 0 1px;") +
  27155. '"' +
  27156. "></a></td>"
  27157. : "";
  27158. }
  27159. html += "</tr></table></div>";
  27160. return html;
  27161. }
  27162. })();
  27163. // ui/tablepicker.js
  27164. ///import core
  27165. ///import uicore
  27166. ;(function () {
  27167. var utils = baidu.editor.utils,
  27168. uiUtils = baidu.editor.ui.uiUtils,
  27169. UIBase = baidu.editor.ui.UIBase;
  27170. var TablePicker = (baidu.editor.ui.TablePicker = function (options) {
  27171. this.initOptions(options);
  27172. this.initTablePicker();
  27173. });
  27174. TablePicker.prototype = {
  27175. defaultNumRows: 10,
  27176. defaultNumCols: 10,
  27177. maxNumRows: 20,
  27178. maxNumCols: 20,
  27179. numRows: 10,
  27180. numCols: 10,
  27181. lengthOfCellSide: 22,
  27182. initTablePicker: function () {
  27183. this.initUIBase();
  27184. },
  27185. getHtmlTpl: function () {
  27186. var me = this;
  27187. return (
  27188. '<div id="##" class="edui-tablepicker %%">' +
  27189. '<div class="edui-tablepicker-body">' +
  27190. '<div class="edui-infoarea">' +
  27191. '<span id="##_label" class="edui-label"></span>' +
  27192. "</div>" +
  27193. '<div class="edui-pickarea"' +
  27194. ' onmousemove="$$._onMouseMove(event, this);"' +
  27195. ' onmouseover="$$._onMouseOver(event, this);"' +
  27196. ' onmouseout="$$._onMouseOut(event, this);"' +
  27197. ' onclick="$$._onClick(event, this);"' +
  27198. ">" +
  27199. '<div id="##_overlay" class="edui-overlay"></div>' +
  27200. "</div>" +
  27201. "</div>" +
  27202. "</div>"
  27203. );
  27204. },
  27205. _UIBase_render: UIBase.prototype.render,
  27206. render: function (holder) {
  27207. this._UIBase_render(holder);
  27208. this.getDom("label").innerHTML =
  27209. "0" +
  27210. this.editor.getLang("t_row") +
  27211. " x 0" +
  27212. this.editor.getLang("t_col");
  27213. },
  27214. _track: function (numCols, numRows) {
  27215. var style = this.getDom("overlay").style;
  27216. var sideLen = this.lengthOfCellSide;
  27217. style.width = numCols * sideLen + "px";
  27218. style.height = numRows * sideLen + "px";
  27219. var label = this.getDom("label");
  27220. label.innerHTML =
  27221. numCols +
  27222. this.editor.getLang("t_col") +
  27223. " x " +
  27224. numRows +
  27225. this.editor.getLang("t_row");
  27226. this.numCols = numCols;
  27227. this.numRows = numRows;
  27228. },
  27229. _onMouseOver: function (evt, el) {
  27230. var rel = evt.relatedTarget || evt.fromElement;
  27231. if (!uiUtils.contains(el, rel) && el !== rel) {
  27232. this.getDom("label").innerHTML =
  27233. "0" +
  27234. this.editor.getLang("t_col") +
  27235. " x 0" +
  27236. this.editor.getLang("t_row");
  27237. this.getDom("overlay").style.visibility = "";
  27238. }
  27239. },
  27240. _onMouseOut: function (evt, el) {
  27241. var rel = evt.relatedTarget || evt.toElement;
  27242. if (!uiUtils.contains(el, rel) && el !== rel) {
  27243. this.getDom("label").innerHTML =
  27244. "0" +
  27245. this.editor.getLang("t_col") +
  27246. " x 0" +
  27247. this.editor.getLang("t_row");
  27248. this.getDom("overlay").style.visibility = "hidden";
  27249. }
  27250. },
  27251. _onMouseMove: function (evt, el) {
  27252. var style = this.getDom("overlay").style;
  27253. var offset = uiUtils.getEventOffset(evt);
  27254. var sideLen = this.lengthOfCellSide;
  27255. var numCols = Math.ceil(offset.left / sideLen);
  27256. var numRows = Math.ceil(offset.top / sideLen);
  27257. this._track(numCols, numRows);
  27258. },
  27259. _onClick: function () {
  27260. this.fireEvent("picktable", this.numCols, this.numRows);
  27261. }
  27262. };
  27263. utils.inherits(TablePicker, UIBase);
  27264. })();
  27265. // ui/stateful.js
  27266. ;(function () {
  27267. var browser = baidu.editor.browser,
  27268. domUtils = baidu.editor.dom.domUtils,
  27269. uiUtils = baidu.editor.ui.uiUtils;
  27270. var TPL_STATEFUL =
  27271. 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
  27272. ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
  27273. (browser.ie
  27274. ? ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
  27275. ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"'
  27276. : ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
  27277. ' onmouseout="$$.Stateful_onMouseOut(event, this);"');
  27278. baidu.editor.ui.Stateful = {
  27279. alwalysHoverable: false,
  27280. target: null, //目标元素和this指向dom不一样
  27281. Stateful_init: function () {
  27282. this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
  27283. this.getHtmlTpl = this.Stateful_getHtmlTpl;
  27284. },
  27285. Stateful_getHtmlTpl: function () {
  27286. var tpl = this._Stateful_dGetHtmlTpl();
  27287. // 使用function避免$转义
  27288. return tpl.replace(/stateful/g, function () {
  27289. return TPL_STATEFUL;
  27290. });
  27291. },
  27292. Stateful_onMouseEnter: function (evt, el) {
  27293. this.target = el;
  27294. if (!this.isDisabled() || this.alwalysHoverable) {
  27295. this.addState("hover");
  27296. this.fireEvent("over");
  27297. }
  27298. },
  27299. Stateful_onMouseLeave: function (evt, el) {
  27300. if (!this.isDisabled() || this.alwalysHoverable) {
  27301. this.removeState("hover");
  27302. this.removeState("active");
  27303. this.fireEvent("out");
  27304. }
  27305. },
  27306. Stateful_onMouseOver: function (evt, el) {
  27307. var rel = evt.relatedTarget;
  27308. if (!uiUtils.contains(el, rel) && el !== rel) {
  27309. this.Stateful_onMouseEnter(evt, el);
  27310. }
  27311. },
  27312. Stateful_onMouseOut: function (evt, el) {
  27313. var rel = evt.relatedTarget;
  27314. if (!uiUtils.contains(el, rel) && el !== rel) {
  27315. this.Stateful_onMouseLeave(evt, el);
  27316. }
  27317. },
  27318. Stateful_onMouseDown: function (evt, el) {
  27319. if (!this.isDisabled()) {
  27320. this.addState("active");
  27321. }
  27322. },
  27323. Stateful_onMouseUp: function (evt, el) {
  27324. if (!this.isDisabled()) {
  27325. this.removeState("active");
  27326. }
  27327. },
  27328. Stateful_postRender: function () {
  27329. if (this.disabled && !this.hasState("disabled")) {
  27330. this.addState("disabled");
  27331. }
  27332. },
  27333. hasState: function (state) {
  27334. return domUtils.hasClass(this.getStateDom(), "edui-state-" + state);
  27335. },
  27336. addState: function (state) {
  27337. if (!this.hasState(state)) {
  27338. this.getStateDom().className += " edui-state-" + state;
  27339. }
  27340. },
  27341. removeState: function (state) {
  27342. if (this.hasState(state)) {
  27343. domUtils.removeClasses(this.getStateDom(), ["edui-state-" + state]);
  27344. }
  27345. },
  27346. getStateDom: function () {
  27347. return this.getDom("state");
  27348. },
  27349. isChecked: function () {
  27350. return this.hasState("checked");
  27351. },
  27352. setChecked: function (checked) {
  27353. if (!this.isDisabled() && checked) {
  27354. this.addState("checked");
  27355. } else {
  27356. this.removeState("checked");
  27357. }
  27358. },
  27359. isDisabled: function () {
  27360. return this.hasState("disabled");
  27361. },
  27362. setDisabled: function (disabled) {
  27363. if (disabled) {
  27364. this.removeState("hover");
  27365. this.removeState("checked");
  27366. this.removeState("active");
  27367. this.addState("disabled");
  27368. } else {
  27369. this.removeState("disabled");
  27370. }
  27371. }
  27372. };
  27373. })();
  27374. // ui/button.js
  27375. ///import core
  27376. ///import uicore
  27377. ///import ui/stateful.js
  27378. ;(function () {
  27379. var utils = baidu.editor.utils,
  27380. UIBase = baidu.editor.ui.UIBase,
  27381. Stateful = baidu.editor.ui.Stateful,
  27382. Button = (baidu.editor.ui.Button = function (options) {
  27383. if (options.name) {
  27384. var btnName = options.name;
  27385. var cssRules = options.cssRules;
  27386. if (!options.className) {
  27387. options.className = "edui-for-" + btnName;
  27388. }
  27389. options.cssRules =
  27390. ".edui-" +
  27391. (options.theme || "default") +
  27392. " .edui-toolbar .edui-button.edui-for-" +
  27393. btnName +
  27394. " .edui-icon {" +
  27395. cssRules +
  27396. "}";
  27397. }
  27398. this.initOptions(options);
  27399. this.initButton();
  27400. });
  27401. Button.prototype = {
  27402. uiName: "button",
  27403. label: "",
  27404. title: "",
  27405. showIcon: true,
  27406. showText: true,
  27407. cssRules: "",
  27408. initButton: function () {
  27409. this.initUIBase();
  27410. this.Stateful_init();
  27411. if (this.cssRules) {
  27412. utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules);
  27413. }
  27414. },
  27415. getHtmlTpl: function () {
  27416. return (
  27417. '<div id="##" class="edui-box %%">' +
  27418. '<div id="##_state" stateful>' +
  27419. '<div class="%%-wrap"><div id="##_body" unselectable="on" ' +
  27420. (this.title ? 'title="' + this.title + '"' : "") +
  27421. ' class="%%-body" onmousedown="return $$._onMouseDown(event, this);" onclick="return $$._onClick(event, this);">' +
  27422. (this.showIcon ? '<div class="edui-box edui-icon"><svg class="edui-iconfont"><use xlink:href="#' + this.className + '"></use></svg></div>' : "") +
  27423. (this.showText
  27424. ? '<div class="edui-box edui-label">' + this.label + "</div>"
  27425. : "") +
  27426. "</div>" +
  27427. "</div>" +
  27428. "</div></div>"
  27429. );
  27430. },
  27431. postRender: function () {
  27432. this.Stateful_postRender();
  27433. this.setDisabled(this.disabled);
  27434. },
  27435. _onMouseDown: function (e) {
  27436. var target = e.target || e.srcElement,
  27437. tagName = target && target.tagName && target.tagName.toLowerCase();
  27438. if (tagName == "input" || tagName == "object" || tagName == "object") {
  27439. return false;
  27440. }
  27441. },
  27442. _onClick: function () {
  27443. if (!this.isDisabled()) {
  27444. this.fireEvent("click");
  27445. }
  27446. },
  27447. setTitle: function (text) {
  27448. var label = this.getDom("label");
  27449. label.innerHTML = text;
  27450. }
  27451. };
  27452. utils.inherits(Button, UIBase);
  27453. utils.extend(Button.prototype, Stateful);
  27454. })();
  27455. // ui/splitbutton.js
  27456. ///import core
  27457. ///import uicore
  27458. ///import ui/stateful.js
  27459. ;(function () {
  27460. var utils = baidu.editor.utils,
  27461. uiUtils = baidu.editor.ui.uiUtils,
  27462. domUtils = baidu.editor.dom.domUtils,
  27463. UIBase = baidu.editor.ui.UIBase,
  27464. Stateful = baidu.editor.ui.Stateful,
  27465. SplitButton = (baidu.editor.ui.SplitButton = function (options) {
  27466. this.initOptions(options);
  27467. this.initSplitButton();
  27468. });
  27469. SplitButton.prototype = {
  27470. popup: null,
  27471. uiName: "splitbutton",
  27472. title: "",
  27473. initSplitButton: function () {
  27474. this.initUIBase();
  27475. this.Stateful_init();
  27476. var me = this;
  27477. if (this.popup != null) {
  27478. var popup = this.popup;
  27479. this.popup = null;
  27480. this.setPopup(popup);
  27481. }
  27482. },
  27483. _UIBase_postRender: UIBase.prototype.postRender,
  27484. postRender: function () {
  27485. this.Stateful_postRender();
  27486. this._UIBase_postRender();
  27487. },
  27488. setPopup: function (popup) {
  27489. if (this.popup === popup) return;
  27490. if (this.popup != null) {
  27491. this.popup.dispose();
  27492. }
  27493. popup.addListener("show", utils.bind(this._onPopupShow, this));
  27494. popup.addListener("hide", utils.bind(this._onPopupHide, this));
  27495. popup.addListener(
  27496. "postrender",
  27497. utils.bind(function () {
  27498. popup
  27499. .getDom("body")
  27500. .appendChild(
  27501. uiUtils.createElementByHtml(
  27502. '<div id="' +
  27503. this.popup.id +
  27504. '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
  27505. (uiUtils.getClientRect(this.getDom()).width + 20) +
  27506. 'px"></div>'
  27507. )
  27508. );
  27509. popup.getDom().className += " " + this.className;
  27510. }, this)
  27511. );
  27512. this.popup = popup;
  27513. },
  27514. _onPopupShow: function () {
  27515. this.addState("opened");
  27516. },
  27517. _onPopupHide: function () {
  27518. this.removeState("opened");
  27519. },
  27520. getHtmlTpl: function () {
  27521. return (
  27522. '<div id="##" class="edui-box %%">' +
  27523. "<div " +
  27524. (this.title ? 'title="' + this.title + '"' : "") +
  27525. ' id="##_state" stateful><div class="%%-body">' +
  27526. '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
  27527. '<div class="edui-box edui-icon"><svg class="edui-iconfont"><use xlink:href="#' + this.className + '"></use></svg></div>' +
  27528. "</div>" +
  27529. '<div class="edui-box edui-splitborder"></div>' +
  27530. '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
  27531. "</div></div></div>"
  27532. );
  27533. },
  27534. showPopup: function () {
  27535. // 当popup往上弹出的时候,做特殊处理
  27536. var rect = uiUtils.getClientRect(this.getDom());
  27537. rect.top -= this.popup.SHADOW_RADIUS;
  27538. rect.height += this.popup.SHADOW_RADIUS;
  27539. this.popup.showAnchorRect(rect);
  27540. },
  27541. _onArrowClick: function (event, el) {
  27542. if (!this.isDisabled()) {
  27543. this.showPopup();
  27544. }
  27545. },
  27546. _onButtonClick: function () {
  27547. if (!this.isDisabled()) {
  27548. this.fireEvent("buttonclick");
  27549. }
  27550. }
  27551. };
  27552. utils.inherits(SplitButton, UIBase);
  27553. utils.extend(SplitButton.prototype, Stateful, true);
  27554. })();
  27555. // ui/colorbutton.js
  27556. ///import core
  27557. ///import uicore
  27558. ///import ui/colorpicker.js
  27559. ///import ui/popup.js
  27560. ///import ui/splitbutton.js
  27561. ;(function () {
  27562. var utils = baidu.editor.utils,
  27563. uiUtils = baidu.editor.ui.uiUtils,
  27564. ColorPicker = baidu.editor.ui.ColorPicker,
  27565. Popup = baidu.editor.ui.Popup,
  27566. SplitButton = baidu.editor.ui.SplitButton,
  27567. ColorButton = (baidu.editor.ui.ColorButton = function (options) {
  27568. this.initOptions(options);
  27569. this.initColorButton();
  27570. });
  27571. ColorButton.prototype = {
  27572. initColorButton: function () {
  27573. var me = this;
  27574. this.popup = new Popup({
  27575. content: new ColorPicker({
  27576. noColorText: me.editor.getLang("clearColor"),
  27577. editor: me.editor,
  27578. onpickcolor: function (t, color) {
  27579. me._onPickColor(color);
  27580. },
  27581. onpicknocolor: function (t, color) {
  27582. me._onPickNoColor(color);
  27583. }
  27584. }),
  27585. editor: me.editor
  27586. });
  27587. this.initSplitButton();
  27588. },
  27589. _SplitButton_postRender: SplitButton.prototype.postRender,
  27590. postRender: function () {
  27591. this._SplitButton_postRender();
  27592. this.getDom("button_body").appendChild(
  27593. uiUtils.createElementByHtml(
  27594. '<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>'
  27595. )
  27596. );
  27597. this.getDom().className += " edui-colorbutton";
  27598. },
  27599. setColor: function (color) {
  27600. this.getDom("colorlump").style.backgroundColor = color;
  27601. this.color = color;
  27602. },
  27603. _onPickColor: function (color) {
  27604. if (this.fireEvent("pickcolor", color) !== false) {
  27605. this.setColor(color);
  27606. this.popup.hide();
  27607. }
  27608. },
  27609. _onPickNoColor: function (color) {
  27610. if (this.fireEvent("picknocolor") !== false) {
  27611. this.popup.hide();
  27612. }
  27613. }
  27614. };
  27615. utils.inherits(ColorButton, SplitButton);
  27616. })();
  27617. // ui/tablebutton.js
  27618. ///import core
  27619. ///import uicore
  27620. ///import ui/popup.js
  27621. ///import ui/tablepicker.js
  27622. ///import ui/splitbutton.js
  27623. ;(function () {
  27624. var utils = baidu.editor.utils,
  27625. Popup = baidu.editor.ui.Popup,
  27626. TablePicker = baidu.editor.ui.TablePicker,
  27627. SplitButton = baidu.editor.ui.SplitButton,
  27628. TableButton = (baidu.editor.ui.TableButton = function (options) {
  27629. this.initOptions(options);
  27630. this.initTableButton();
  27631. });
  27632. TableButton.prototype = {
  27633. initTableButton: function () {
  27634. var me = this;
  27635. this.popup = new Popup({
  27636. content: new TablePicker({
  27637. editor: me.editor,
  27638. onpicktable: function (t, numCols, numRows) {
  27639. me._onPickTable(numCols, numRows);
  27640. }
  27641. }),
  27642. editor: me.editor
  27643. });
  27644. this.initSplitButton();
  27645. },
  27646. _onPickTable: function (numCols, numRows) {
  27647. if (this.fireEvent("picktable", numCols, numRows) !== false) {
  27648. this.popup.hide();
  27649. }
  27650. }
  27651. };
  27652. utils.inherits(TableButton, SplitButton);
  27653. })();
  27654. // ui/autotypesetpicker.js
  27655. ///import core
  27656. ///import uicore
  27657. ;(function () {
  27658. var utils = baidu.editor.utils,
  27659. UIBase = baidu.editor.ui.UIBase;
  27660. var AutoTypeSetPicker = (baidu.editor.ui.AutoTypeSetPicker = function (
  27661. options
  27662. ) {
  27663. this.initOptions(options);
  27664. this.initAutoTypeSetPicker();
  27665. });
  27666. AutoTypeSetPicker.prototype = {
  27667. initAutoTypeSetPicker: function () {
  27668. this.initUIBase();
  27669. },
  27670. getHtmlTpl: function () {
  27671. var me = this.editor,
  27672. opt = me.options.autotypeset,
  27673. lang = me.getLang("autoTypeSet");
  27674. var textAlignInputName = "textAlignValue" + me.uid,
  27675. imageBlockInputName = "imageBlockLineValue" + me.uid,
  27676. symbolConverInputName = "symbolConverValue" + me.uid;
  27677. return (
  27678. '<div id="##" class="edui-autotypesetpicker %%">' +
  27679. '<div class="edui-autotypesetpicker-body">' +
  27680. "<table >" +
  27681. '<tr><td nowrap><input type="checkbox" name="mergeEmptyline" ' +
  27682. (opt["mergeEmptyline"] ? "checked" : "") +
  27683. ">" +
  27684. lang.mergeLine +
  27685. '</td><td colspan="2"><input type="checkbox" name="removeEmptyline" ' +
  27686. (opt["removeEmptyline"] ? "checked" : "") +
  27687. ">" +
  27688. lang.delLine +
  27689. "</td></tr>" +
  27690. '<tr><td nowrap><input type="checkbox" name="removeClass" ' +
  27691. (opt["removeClass"] ? "checked" : "") +
  27692. ">" +
  27693. lang.removeFormat +
  27694. '</td><td colspan="2"><input type="checkbox" name="indent" ' +
  27695. (opt["indent"] ? "checked" : "") +
  27696. ">" +
  27697. lang.indent +
  27698. "</td></tr>" +
  27699. "<tr>" +
  27700. '<td nowrap><input type="checkbox" name="textAlign" ' +
  27701. (opt["textAlign"] ? "checked" : "") +
  27702. ">" +
  27703. lang.alignment +
  27704. "</td>" +
  27705. '<td colspan="2" id="' +
  27706. textAlignInputName +
  27707. '">' +
  27708. '<input type="radio" name="' +
  27709. textAlignInputName +
  27710. '" value="left" ' +
  27711. (opt["textAlign"] && opt["textAlign"] == "left" ? "checked" : "") +
  27712. ">" +
  27713. me.getLang("justifyleft") +
  27714. '<input type="radio" name="' +
  27715. textAlignInputName +
  27716. '" value="center" ' +
  27717. (opt["textAlign"] && opt["textAlign"] == "center" ? "checked" : "") +
  27718. ">" +
  27719. me.getLang("justifycenter") +
  27720. '<input type="radio" name="' +
  27721. textAlignInputName +
  27722. '" value="right" ' +
  27723. (opt["textAlign"] && opt["textAlign"] == "right" ? "checked" : "") +
  27724. ">" +
  27725. me.getLang("justifyright") +
  27726. "</td>" +
  27727. "</tr>" +
  27728. "<tr>" +
  27729. '<td nowrap><input type="checkbox" name="imageBlockLine" ' +
  27730. (opt["imageBlockLine"] ? "checked" : "") +
  27731. ">" +
  27732. lang.imageFloat +
  27733. "</td>" +
  27734. '<td nowrap id="' +
  27735. imageBlockInputName +
  27736. '">' +
  27737. '<input type="radio" name="' +
  27738. imageBlockInputName +
  27739. '" value="none" ' +
  27740. (opt["imageBlockLine"] && opt["imageBlockLine"] == "none"
  27741. ? "checked"
  27742. : "") +
  27743. ">" +
  27744. me.getLang("default") +
  27745. '<input type="radio" name="' +
  27746. imageBlockInputName +
  27747. '" value="left" ' +
  27748. (opt["imageBlockLine"] && opt["imageBlockLine"] == "left"
  27749. ? "checked"
  27750. : "") +
  27751. ">" +
  27752. me.getLang("justifyleft") +
  27753. '<input type="radio" name="' +
  27754. imageBlockInputName +
  27755. '" value="center" ' +
  27756. (opt["imageBlockLine"] && opt["imageBlockLine"] == "center"
  27757. ? "checked"
  27758. : "") +
  27759. ">" +
  27760. me.getLang("justifycenter") +
  27761. '<input type="radio" name="' +
  27762. imageBlockInputName +
  27763. '" value="right" ' +
  27764. (opt["imageBlockLine"] && opt["imageBlockLine"] == "right"
  27765. ? "checked"
  27766. : "") +
  27767. ">" +
  27768. me.getLang("justifyright") +
  27769. "</td>" +
  27770. "</tr>" +
  27771. '<tr><td nowrap><input type="checkbox" name="clearFontSize" ' +
  27772. (opt["clearFontSize"] ? "checked" : "") +
  27773. ">" +
  27774. lang.removeFontsize +
  27775. '</td><td colspan="2"><input type="checkbox" name="clearFontFamily" ' +
  27776. (opt["clearFontFamily"] ? "checked" : "") +
  27777. ">" +
  27778. lang.removeFontFamily +
  27779. "</td></tr>" +
  27780. '<tr><td nowrap colspan="3"><input type="checkbox" name="removeEmptyNode" ' +
  27781. (opt["removeEmptyNode"] ? "checked" : "") +
  27782. ">" +
  27783. lang.removeHtml +
  27784. "</td></tr>" +
  27785. '<tr><td nowrap colspan="3"><input type="checkbox" name="pasteFilter" ' +
  27786. (opt["pasteFilter"] ? "checked" : "") +
  27787. ">" +
  27788. lang.pasteFilter +
  27789. "</td></tr>" +
  27790. "<tr>" +
  27791. '<td nowrap><input type="checkbox" name="symbolConver" ' +
  27792. (opt["bdc2sb"] || opt["tobdc"] ? "checked" : "") +
  27793. ">" +
  27794. lang.symbol +
  27795. "</td>" +
  27796. '<td id="' +
  27797. symbolConverInputName +
  27798. '">' +
  27799. '<input type="radio" name="bdc" value="bdc2sb" ' +
  27800. (opt["bdc2sb"] ? "checked" : "") +
  27801. ">" +
  27802. lang.bdc2sb +
  27803. '<input type="radio" name="bdc" value="tobdc" ' +
  27804. (opt["tobdc"] ? "checked" : "") +
  27805. ">" +
  27806. lang.tobdc +
  27807. "" +
  27808. "</td>" +
  27809. '<td nowrap align="right"><button >' +
  27810. lang.run +
  27811. "</button></td>" +
  27812. "</tr>" +
  27813. "</table>" +
  27814. "</div>" +
  27815. "</div>"
  27816. );
  27817. },
  27818. _UIBase_render: UIBase.prototype.render
  27819. };
  27820. utils.inherits(AutoTypeSetPicker, UIBase);
  27821. })();
  27822. // ui/autotypesetbutton.js
  27823. ///import core
  27824. ///import uicore
  27825. ///import ui/popup.js
  27826. ///import ui/autotypesetpicker.js
  27827. ///import ui/splitbutton.js
  27828. ;(function () {
  27829. var utils = baidu.editor.utils,
  27830. Popup = baidu.editor.ui.Popup,
  27831. AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
  27832. SplitButton = baidu.editor.ui.SplitButton,
  27833. AutoTypeSetButton = (baidu.editor.ui.AutoTypeSetButton = function (options) {
  27834. this.initOptions(options);
  27835. this.initAutoTypeSetButton();
  27836. });
  27837. function getPara(me) {
  27838. var opt = {},
  27839. cont = me.getDom(),
  27840. editorId = me.editor.uid,
  27841. inputType = null,
  27842. attrName = null,
  27843. ipts = domUtils.getElementsByTagName(cont, "input");
  27844. for (var i = ipts.length - 1, ipt; (ipt = ipts[i--]);) {
  27845. inputType = ipt.getAttribute("type");
  27846. if (inputType == "checkbox") {
  27847. attrName = ipt.getAttribute("name");
  27848. opt[attrName] && delete opt[attrName];
  27849. if (ipt.checked) {
  27850. var attrValue = document.getElementById(
  27851. attrName + "Value" + editorId
  27852. );
  27853. if (attrValue) {
  27854. if (/input/gi.test(attrValue.tagName)) {
  27855. opt[attrName] = attrValue.value;
  27856. } else {
  27857. var iptChilds = attrValue.getElementsByTagName("input");
  27858. for (
  27859. var j = iptChilds.length - 1, iptchild;
  27860. (iptchild = iptChilds[j--]);
  27861. ) {
  27862. if (iptchild.checked) {
  27863. opt[attrName] = iptchild.value;
  27864. break;
  27865. }
  27866. }
  27867. }
  27868. } else {
  27869. opt[attrName] = true;
  27870. }
  27871. } else {
  27872. opt[attrName] = false;
  27873. }
  27874. } else {
  27875. opt[ipt.getAttribute("value")] = ipt.checked;
  27876. }
  27877. }
  27878. var selects = domUtils.getElementsByTagName(cont, "select");
  27879. for (var i = 0, si; (si = selects[i++]);) {
  27880. var attr = si.getAttribute("name");
  27881. opt[attr] = opt[attr] ? si.value : "";
  27882. }
  27883. utils.extend(me.editor.options.autotypeset, opt);
  27884. me.editor.setPreferences("autotypeset", opt);
  27885. }
  27886. AutoTypeSetButton.prototype = {
  27887. initAutoTypeSetButton: function () {
  27888. var me = this;
  27889. this.popup = new Popup({
  27890. //传入配置参数
  27891. content: new AutoTypeSetPicker({editor: me.editor}),
  27892. editor: me.editor,
  27893. hide: function () {
  27894. if (!this._hidden && this.getDom()) {
  27895. getPara(this);
  27896. this.getDom().style.display = "none";
  27897. this._hidden = true;
  27898. this.fireEvent("hide");
  27899. }
  27900. }
  27901. });
  27902. var flag = 0;
  27903. this.popup.addListener("postRenderAfter", function () {
  27904. var popupUI = this;
  27905. if (flag) return;
  27906. var cont = this.getDom(),
  27907. btn = cont.getElementsByTagName("button")[0];
  27908. btn.onclick = function () {
  27909. getPara(popupUI);
  27910. me.editor.execCommand("autotypeset");
  27911. popupUI.hide();
  27912. };
  27913. domUtils.on(cont, "click", function (e) {
  27914. var target = e.target || e.srcElement,
  27915. editorId = me.editor.uid;
  27916. if (target && target.tagName == "INPUT") {
  27917. // 点击图片浮动的checkbox,去除对应的radio
  27918. if (
  27919. target.name == "imageBlockLine" ||
  27920. target.name == "textAlign" ||
  27921. target.name == "symbolConver"
  27922. ) {
  27923. var checked = target.checked,
  27924. radioTd = document.getElementById(
  27925. target.name + "Value" + editorId
  27926. ),
  27927. radios = radioTd.getElementsByTagName("input"),
  27928. defalutSelect = {
  27929. imageBlockLine: "none",
  27930. textAlign: "left",
  27931. symbolConver: "tobdc"
  27932. };
  27933. for (var i = 0; i < radios.length; i++) {
  27934. if (checked) {
  27935. if (radios[i].value == defalutSelect[target.name]) {
  27936. radios[i].checked = "checked";
  27937. }
  27938. } else {
  27939. radios[i].checked = false;
  27940. }
  27941. }
  27942. }
  27943. // 点击radio,选中对应的checkbox
  27944. if (
  27945. target.name == "imageBlockLineValue" + editorId ||
  27946. target.name == "textAlignValue" + editorId ||
  27947. target.name == "bdc"
  27948. ) {
  27949. var checkboxs = target.parentNode.previousSibling.getElementsByTagName(
  27950. "input"
  27951. );
  27952. checkboxs && (checkboxs[0].checked = true);
  27953. }
  27954. getPara(popupUI);
  27955. }
  27956. });
  27957. flag = 1;
  27958. });
  27959. this.initSplitButton();
  27960. }
  27961. };
  27962. utils.inherits(AutoTypeSetButton, SplitButton);
  27963. })();
  27964. // ui/cellalignpicker.js
  27965. ///import core
  27966. ///import uicore
  27967. ;(function () {
  27968. var utils = baidu.editor.utils,
  27969. Popup = baidu.editor.ui.Popup,
  27970. Stateful = baidu.editor.ui.Stateful,
  27971. UIBase = baidu.editor.ui.UIBase;
  27972. /**
  27973. * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
  27974. * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
  27975. * @update 2013/4/2 hancong03@baidu.com
  27976. */
  27977. var CellAlignPicker = (baidu.editor.ui.CellAlignPicker = function (options) {
  27978. this.initOptions(options);
  27979. this.initSelected();
  27980. this.initCellAlignPicker();
  27981. });
  27982. CellAlignPicker.prototype = {
  27983. //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
  27984. initSelected: function () {
  27985. var status = {
  27986. valign: {
  27987. top: 0,
  27988. middle: 1,
  27989. bottom: 2
  27990. },
  27991. align: {
  27992. left: 0,
  27993. center: 1,
  27994. right: 2
  27995. },
  27996. count: 3
  27997. },
  27998. result = -1;
  27999. if (this.selected) {
  28000. this.selectedIndex =
  28001. status.valign[this.selected.valign] * status.count +
  28002. status.align[this.selected.align];
  28003. }
  28004. },
  28005. initCellAlignPicker: function () {
  28006. this.initUIBase();
  28007. this.Stateful_init();
  28008. },
  28009. getHtmlTpl: function () {
  28010. var alignType = ["left", "center", "right"],
  28011. COUNT = 9,
  28012. tempClassName = null,
  28013. tempIndex = -1,
  28014. tmpl = [];
  28015. for (var i = 0; i < COUNT; i++) {
  28016. tempClassName = this.selectedIndex === i
  28017. ? ' class="edui-cellalign-selected" '
  28018. : "";
  28019. tempIndex = i % 3;
  28020. tempIndex === 0 && tmpl.push("<tr>");
  28021. tmpl.push(
  28022. '<td index="' +
  28023. i +
  28024. '" ' +
  28025. tempClassName +
  28026. ' stateful><div class="edui-icon edui-' +
  28027. alignType[tempIndex] +
  28028. '"></div></td>'
  28029. );
  28030. tempIndex === 2 && tmpl.push("</tr>");
  28031. }
  28032. return (
  28033. '<div id="##" class="edui-cellalignpicker %%">' +
  28034. '<div class="edui-cellalignpicker-body">' +
  28035. '<table onclick="$$._onClick(event);">' +
  28036. tmpl.join("") +
  28037. "</table>" +
  28038. "</div>" +
  28039. "</div>"
  28040. );
  28041. },
  28042. getStateDom: function () {
  28043. return this.target;
  28044. },
  28045. _onClick: function (evt) {
  28046. var target = evt.target || evt.srcElement;
  28047. if (/icon/.test(target.className)) {
  28048. this.items[target.parentNode.getAttribute("index")].onclick();
  28049. Popup.postHide(evt);
  28050. }
  28051. },
  28052. _UIBase_render: UIBase.prototype.render
  28053. };
  28054. utils.inherits(CellAlignPicker, UIBase);
  28055. utils.extend(CellAlignPicker.prototype, Stateful, true);
  28056. })();
  28057. // ui/pastepicker.js
  28058. ///import core
  28059. ///import uicore
  28060. ;(function () {
  28061. var utils = baidu.editor.utils,
  28062. Stateful = baidu.editor.ui.Stateful,
  28063. uiUtils = baidu.editor.ui.uiUtils,
  28064. UIBase = baidu.editor.ui.UIBase;
  28065. var PastePicker = (baidu.editor.ui.PastePicker = function (options) {
  28066. this.initOptions(options);
  28067. this.initPastePicker();
  28068. });
  28069. PastePicker.prototype = {
  28070. initPastePicker: function () {
  28071. this.initUIBase();
  28072. this.Stateful_init();
  28073. },
  28074. getHtmlTpl: function () {
  28075. return (
  28076. '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
  28077. '<div class="edui-pastecontainer">' +
  28078. '<div class="edui-title">' +
  28079. this.editor.getLang("pasteOpt") +
  28080. "</div>" +
  28081. '<div class="edui-button">' +
  28082. '<div title="' +
  28083. this.editor.getLang("pasteSourceFormat") +
  28084. '" onclick="$$.format(false)" stateful>' +
  28085. '<div class="edui-richtxticon"></div></div>' +
  28086. '<div title="' +
  28087. this.editor.getLang("tagFormat") +
  28088. '" onclick="$$.format(2)" stateful>' +
  28089. '<div class="edui-tagicon"></div></div>' +
  28090. '<div title="' +
  28091. this.editor.getLang("pasteTextFormat") +
  28092. '" onclick="$$.format(true)" stateful>' +
  28093. '<div class="edui-plaintxticon"></div></div>' +
  28094. "</div>" +
  28095. "</div>" +
  28096. "</div>"
  28097. );
  28098. },
  28099. getStateDom: function () {
  28100. return this.target;
  28101. },
  28102. format: function (param) {
  28103. this.editor.ui._isTransfer = true;
  28104. this.editor.fireEvent("pasteTransfer", param);
  28105. },
  28106. _onClick: function (cur) {
  28107. var node = domUtils.getNextDomNode(cur),
  28108. screenHt = uiUtils.getViewportRect().height,
  28109. subPop = uiUtils.getClientRect(node);
  28110. if (subPop.top + subPop.height > screenHt)
  28111. node.style.top = -subPop.height - cur.offsetHeight + "px";
  28112. else node.style.top = "";
  28113. if (/hidden/gi.test(domUtils.getComputedStyle(node, "visibility"))) {
  28114. node.style.visibility = "visible";
  28115. domUtils.addClass(cur, "edui-state-opened");
  28116. } else {
  28117. node.style.visibility = "hidden";
  28118. domUtils.removeClasses(cur, "edui-state-opened");
  28119. }
  28120. },
  28121. _UIBase_render: UIBase.prototype.render
  28122. };
  28123. utils.inherits(PastePicker, UIBase);
  28124. utils.extend(PastePicker.prototype, Stateful, true);
  28125. })();
  28126. // ui/toolbar.js
  28127. ;(function () {
  28128. var utils = baidu.editor.utils,
  28129. uiUtils = baidu.editor.ui.uiUtils,
  28130. UIBase = baidu.editor.ui.UIBase,
  28131. Toolbar = (baidu.editor.ui.Toolbar = function (options) {
  28132. this.initOptions(options);
  28133. this.initToolbar();
  28134. });
  28135. Toolbar.prototype = {
  28136. items: null,
  28137. initToolbar: function () {
  28138. this.items = this.items || [];
  28139. this.initUIBase();
  28140. },
  28141. add: function (item, index) {
  28142. if (index === undefined) {
  28143. this.items.push(item);
  28144. } else {
  28145. this.items.splice(index, 0, item);
  28146. }
  28147. },
  28148. getHtmlTpl: function () {
  28149. var buff = [];
  28150. for (var i = 0; i < this.items.length; i++) {
  28151. buff[i] = this.items[i].renderHtml();
  28152. }
  28153. return (
  28154. '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
  28155. buff.join("") +
  28156. "</div>"
  28157. );
  28158. },
  28159. postRender: function () {
  28160. var box = this.getDom();
  28161. for (var i = 0; i < this.items.length; i++) {
  28162. this.items[i].postRender();
  28163. }
  28164. uiUtils.makeUnselectable(box);
  28165. },
  28166. _onMouseDown: function (e) {
  28167. var target = e.target || e.srcElement,
  28168. tagName = target && target.tagName && target.tagName.toLowerCase();
  28169. if (tagName == "input" || tagName == "object" || tagName == "object") {
  28170. return false;
  28171. }
  28172. }
  28173. };
  28174. utils.inherits(Toolbar, UIBase);
  28175. })();
  28176. // ui/menu.js
  28177. ///import core
  28178. ///import uicore
  28179. ///import ui\popup.js
  28180. ///import ui\stateful.js
  28181. ;(function () {
  28182. var utils = baidu.editor.utils,
  28183. domUtils = baidu.editor.dom.domUtils,
  28184. uiUtils = baidu.editor.ui.uiUtils,
  28185. UIBase = baidu.editor.ui.UIBase,
  28186. Popup = baidu.editor.ui.Popup,
  28187. Stateful = baidu.editor.ui.Stateful,
  28188. CellAlignPicker = baidu.editor.ui.CellAlignPicker,
  28189. Menu = (baidu.editor.ui.Menu = function (options) {
  28190. this.initOptions(options);
  28191. this.initMenu();
  28192. });
  28193. var menuSeparator = {
  28194. renderHtml: function () {
  28195. return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>';
  28196. },
  28197. postRender: function () {
  28198. },
  28199. queryAutoHide: function () {
  28200. return true;
  28201. }
  28202. };
  28203. Menu.prototype = {
  28204. items: null,
  28205. uiName: "menu",
  28206. initMenu: function () {
  28207. this.items = this.items || [];
  28208. this.initPopup();
  28209. this.initItems();
  28210. },
  28211. initItems: function () {
  28212. for (var i = 0; i < this.items.length; i++) {
  28213. var item = this.items[i];
  28214. if (item == "-") {
  28215. this.items[i] = this.getSeparator();
  28216. } else if (!(item instanceof MenuItem)) {
  28217. item.editor = this.editor;
  28218. item.theme = this.editor.options.theme;
  28219. this.items[i] = this.createItem(item);
  28220. }
  28221. }
  28222. },
  28223. getSeparator: function () {
  28224. return menuSeparator;
  28225. },
  28226. createItem: function (item) {
  28227. //新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  28228. item.menu = this;
  28229. return new MenuItem(item);
  28230. },
  28231. _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
  28232. getContentHtmlTpl: function () {
  28233. if (this.items.length == 0) {
  28234. return this._Popup_getContentHtmlTpl();
  28235. }
  28236. var buff = [];
  28237. for (var i = 0; i < this.items.length; i++) {
  28238. var item = this.items[i];
  28239. buff[i] = item.renderHtml();
  28240. }
  28241. return '<div class="%%-body">' + buff.join("") + "</div>";
  28242. },
  28243. _Popup_postRender: Popup.prototype.postRender,
  28244. postRender: function () {
  28245. var me = this;
  28246. for (var i = 0; i < this.items.length; i++) {
  28247. var item = this.items[i];
  28248. item.ownerMenu = this;
  28249. item.postRender();
  28250. }
  28251. domUtils.on(this.getDom(), "mouseover", function (evt) {
  28252. evt = evt || event;
  28253. var rel = evt.relatedTarget || evt.fromElement;
  28254. var el = me.getDom();
  28255. if (!uiUtils.contains(el, rel) && el !== rel) {
  28256. me.fireEvent("over");
  28257. }
  28258. });
  28259. this._Popup_postRender();
  28260. },
  28261. queryAutoHide: function (el) {
  28262. if (el) {
  28263. if (uiUtils.contains(this.getDom(), el)) {
  28264. return false;
  28265. }
  28266. for (var i = 0; i < this.items.length; i++) {
  28267. var item = this.items[i];
  28268. if (item.queryAutoHide(el) === false) {
  28269. return false;
  28270. }
  28271. }
  28272. }
  28273. },
  28274. clearItems: function () {
  28275. for (var i = 0; i < this.items.length; i++) {
  28276. var item = this.items[i];
  28277. clearTimeout(item._showingTimer);
  28278. clearTimeout(item._closingTimer);
  28279. if (item.subMenu) {
  28280. item.subMenu.destroy();
  28281. }
  28282. }
  28283. this.items = [];
  28284. },
  28285. destroy: function () {
  28286. if (this.getDom()) {
  28287. domUtils.remove(this.getDom());
  28288. }
  28289. this.clearItems();
  28290. },
  28291. dispose: function () {
  28292. this.destroy();
  28293. }
  28294. };
  28295. utils.inherits(Menu, Popup);
  28296. /**
  28297. * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  28298. * @type {Function}
  28299. */
  28300. var MenuItem = (baidu.editor.ui.MenuItem = function (options) {
  28301. this.initOptions(options);
  28302. this.initUIBase();
  28303. this.Stateful_init();
  28304. if (this.subMenu && !(this.subMenu instanceof Menu)) {
  28305. if (options.className && options.className.indexOf("aligntd") != -1) {
  28306. var me = this;
  28307. //获取单元格对齐初始状态
  28308. this.subMenu.selected = this.editor.queryCommandValue("cellalignment");
  28309. this.subMenu = new Popup({
  28310. content: new CellAlignPicker(this.subMenu),
  28311. parentMenu: me,
  28312. editor: me.editor,
  28313. destroy: function () {
  28314. if (this.getDom()) {
  28315. domUtils.remove(this.getDom());
  28316. }
  28317. }
  28318. });
  28319. this.subMenu.addListener("postRenderAfter", function () {
  28320. domUtils.on(this.getDom(), "mouseover", function () {
  28321. me.addState("opened");
  28322. });
  28323. });
  28324. } else {
  28325. this.subMenu = new Menu(this.subMenu);
  28326. }
  28327. }
  28328. });
  28329. MenuItem.prototype = {
  28330. label: "",
  28331. subMenu: null,
  28332. ownerMenu: null,
  28333. uiName: "menuitem",
  28334. alwalysHoverable: true,
  28335. getHtmlTpl: function () {
  28336. return (
  28337. '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
  28338. '<div class="%%-body">' +
  28339. this.renderLabelHtml() +
  28340. "</div>" +
  28341. "</div>"
  28342. );
  28343. },
  28344. postRender: function () {
  28345. var me = this;
  28346. this.addListener("over", function () {
  28347. me.ownerMenu.fireEvent("submenuover", me);
  28348. if (me.subMenu) {
  28349. me.delayShowSubMenu();
  28350. }
  28351. });
  28352. if (this.subMenu) {
  28353. this.getDom().className += " edui-hassubmenu";
  28354. this.subMenu.render();
  28355. this.addListener("out", function () {
  28356. me.delayHideSubMenu();
  28357. });
  28358. this.subMenu.addListener("over", function () {
  28359. clearTimeout(me._closingTimer);
  28360. me._closingTimer = null;
  28361. me.addState("opened");
  28362. });
  28363. this.ownerMenu.addListener("hide", function () {
  28364. me.hideSubMenu();
  28365. });
  28366. this.ownerMenu.addListener("submenuover", function (t, subMenu) {
  28367. if (subMenu !== me) {
  28368. me.delayHideSubMenu();
  28369. }
  28370. });
  28371. this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
  28372. this.subMenu.queryAutoHide = function (el) {
  28373. if (el && uiUtils.contains(me.getDom(), el)) {
  28374. return false;
  28375. }
  28376. return this._bakQueryAutoHide(el);
  28377. };
  28378. }
  28379. this.getDom().style.tabIndex = "-1";
  28380. uiUtils.makeUnselectable(this.getDom());
  28381. this.Stateful_postRender();
  28382. },
  28383. delayShowSubMenu: function () {
  28384. var me = this;
  28385. if (!me.isDisabled()) {
  28386. me.addState("opened");
  28387. clearTimeout(me._showingTimer);
  28388. clearTimeout(me._closingTimer);
  28389. me._closingTimer = null;
  28390. me._showingTimer = setTimeout(function () {
  28391. me.showSubMenu();
  28392. }, 250);
  28393. }
  28394. },
  28395. delayHideSubMenu: function () {
  28396. var me = this;
  28397. if (!me.isDisabled()) {
  28398. me.removeState("opened");
  28399. clearTimeout(me._showingTimer);
  28400. if (!me._closingTimer) {
  28401. me._closingTimer = setTimeout(function () {
  28402. if (!me.hasState("opened")) {
  28403. me.hideSubMenu();
  28404. }
  28405. me._closingTimer = null;
  28406. }, 400);
  28407. }
  28408. }
  28409. },
  28410. renderLabelHtml: function () {
  28411. return (
  28412. '<div class="edui-arrow"></div>' +
  28413. '<div class="edui-box edui-icon"></div>' +
  28414. '<div class="edui-box edui-label %%-label">' +
  28415. (this.label || "") +
  28416. "</div>"
  28417. );
  28418. },
  28419. getStateDom: function () {
  28420. return this.getDom();
  28421. },
  28422. queryAutoHide: function (el) {
  28423. if (this.subMenu && this.hasState("opened")) {
  28424. return this.subMenu.queryAutoHide(el);
  28425. }
  28426. },
  28427. _onClick: function (event, this_) {
  28428. if (this.hasState("disabled")) return;
  28429. if (this.fireEvent("click", event, this_) !== false) {
  28430. if (this.subMenu) {
  28431. this.showSubMenu();
  28432. } else {
  28433. Popup.postHide(event);
  28434. }
  28435. }
  28436. },
  28437. showSubMenu: function () {
  28438. var rect = uiUtils.getClientRect(this.getDom());
  28439. rect.right -= 5;
  28440. rect.left += 2;
  28441. rect.width -= 7;
  28442. rect.top -= 4;
  28443. rect.bottom += 4;
  28444. rect.height += 8;
  28445. this.subMenu.showAnchorRect(rect, true, true);
  28446. },
  28447. hideSubMenu: function () {
  28448. this.subMenu.hide();
  28449. }
  28450. };
  28451. utils.inherits(MenuItem, UIBase);
  28452. utils.extend(MenuItem.prototype, Stateful, true);
  28453. })();
  28454. // ui/combox.js
  28455. ///import core
  28456. ///import uicore
  28457. ///import ui/menu.js
  28458. ///import ui/splitbutton.js
  28459. ;(function () {
  28460. // todo: menu和item提成通用list
  28461. var utils = baidu.editor.utils,
  28462. uiUtils = baidu.editor.ui.uiUtils,
  28463. Menu = baidu.editor.ui.Menu,
  28464. SplitButton = baidu.editor.ui.SplitButton,
  28465. Combox = (baidu.editor.ui.Combox = function (options) {
  28466. this.initOptions(options);
  28467. this.initCombox();
  28468. });
  28469. Combox.prototype = {
  28470. uiName: "combox",
  28471. onbuttonclick: function () {
  28472. this.showPopup();
  28473. },
  28474. initCombox: function () {
  28475. var me = this;
  28476. this.items = this.items || [];
  28477. for (var i = 0; i < this.items.length; i++) {
  28478. var item = this.items[i];
  28479. item.uiName = "listitem";
  28480. item.index = i;
  28481. item.onclick = function () {
  28482. me.selectByIndex(this.index);
  28483. };
  28484. }
  28485. this.popup = new Menu({
  28486. items: this.items,
  28487. uiName: "list",
  28488. editor: this.editor,
  28489. captureWheel: true,
  28490. combox: this
  28491. });
  28492. this.initSplitButton();
  28493. },
  28494. _SplitButton_postRender: SplitButton.prototype.postRender,
  28495. postRender: function () {
  28496. this._SplitButton_postRender();
  28497. this.setLabel(this.label || "");
  28498. this.setValue(this.initValue || "");
  28499. },
  28500. showPopup: function () {
  28501. var rect = uiUtils.getClientRect(this.getDom());
  28502. rect.top += 1;
  28503. rect.bottom -= 1;
  28504. rect.height -= 2;
  28505. this.popup.showAnchorRect(rect);
  28506. },
  28507. getValue: function () {
  28508. return this.value;
  28509. },
  28510. setValue: function (value) {
  28511. var index = this.indexByValue(value);
  28512. if (index != -1) {
  28513. this.selectedIndex = index;
  28514. this.setLabel(this.items[index].label);
  28515. this.value = this.items[index].value;
  28516. } else {
  28517. this.selectedIndex = -1;
  28518. this.setLabel(this.getLabelForUnknowValue(value));
  28519. this.value = value;
  28520. }
  28521. },
  28522. setLabel: function (label) {
  28523. this.getDom("button_body").innerHTML = label;
  28524. this.label = label;
  28525. },
  28526. getLabelForUnknowValue: function (value) {
  28527. return value;
  28528. },
  28529. indexByValue: function (value) {
  28530. for (var i = 0; i < this.items.length; i++) {
  28531. if (value == this.items[i].value) {
  28532. return i;
  28533. }
  28534. }
  28535. return -1;
  28536. },
  28537. getItem: function (index) {
  28538. return this.items[index];
  28539. },
  28540. selectByIndex: function (index) {
  28541. if (
  28542. index < this.items.length &&
  28543. this.fireEvent("select", index) !== false
  28544. ) {
  28545. this.selectedIndex = index;
  28546. this.value = this.items[index].value;
  28547. this.setLabel(this.items[index].label);
  28548. }
  28549. }
  28550. };
  28551. utils.inherits(Combox, SplitButton);
  28552. })();
  28553. // ui/dialog.js
  28554. ///import core
  28555. ///import uicore
  28556. ///import ui/mask.js
  28557. ///import ui/button.js
  28558. ;(function () {
  28559. var utils = baidu.editor.utils,
  28560. domUtils = baidu.editor.dom.domUtils,
  28561. uiUtils = baidu.editor.ui.uiUtils,
  28562. Mask = baidu.editor.ui.Mask,
  28563. UIBase = baidu.editor.ui.UIBase,
  28564. Button = baidu.editor.ui.Button,
  28565. Dialog = (baidu.editor.ui.Dialog = function (options) {
  28566. if (options.name) {
  28567. var name = options.name;
  28568. var cssRules = options.cssRules;
  28569. if (!options.className) {
  28570. options.className = "edui-for-" + name;
  28571. }
  28572. if (cssRules) {
  28573. options.cssRules =
  28574. ".edui-for-" + name + " .edui-dialog-content {" + cssRules + "}";
  28575. }
  28576. }
  28577. this.initOptions(
  28578. utils.extend(
  28579. {
  28580. autoReset: true,
  28581. draggable: true,
  28582. onok: function () {
  28583. },
  28584. oncancel: function () {
  28585. },
  28586. onclose: function (t, ok) {
  28587. return ok ? this.onok() : this.oncancel();
  28588. },
  28589. //是否控制dialog中的scroll事件, 默认为不阻止
  28590. holdScroll: false
  28591. },
  28592. options
  28593. )
  28594. );
  28595. this.initDialog();
  28596. });
  28597. var modalMask;
  28598. var dragMask;
  28599. var activeDialog;
  28600. Dialog.prototype = {
  28601. draggable: false,
  28602. uiName: "dialog",
  28603. initDialog: function () {
  28604. var me = this,
  28605. theme = this.editor.options.theme;
  28606. if (this.cssRules) {
  28607. this.cssRules = ".edui-" + theme + " " + this.cssRules;
  28608. utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules);
  28609. }
  28610. this.initUIBase();
  28611. this.modalMask =
  28612. modalMask ||
  28613. (modalMask = new Mask({
  28614. className: "edui-dialog-modalmask",
  28615. theme: theme,
  28616. onclick: function () {
  28617. activeDialog && activeDialog.close(false);
  28618. }
  28619. }));
  28620. this.dragMask =
  28621. dragMask ||
  28622. (dragMask = new Mask({
  28623. className: "edui-dialog-dragmask",
  28624. theme: theme
  28625. }));
  28626. this.closeButton = new Button({
  28627. className: "edui-dialog-closebutton",
  28628. title: me.closeDialog,
  28629. theme: theme,
  28630. onclick: function () {
  28631. me.close(false);
  28632. }
  28633. });
  28634. this.fullscreen && this.initResizeEvent();
  28635. if (this.buttons) {
  28636. for (var i = 0; i < this.buttons.length; i++) {
  28637. if (!(this.buttons[i] instanceof Button)) {
  28638. this.buttons[i] = new Button(
  28639. utils.extend(
  28640. this.buttons[i],
  28641. {
  28642. editor: this.editor
  28643. },
  28644. true
  28645. )
  28646. );
  28647. }
  28648. }
  28649. }
  28650. },
  28651. initResizeEvent: function () {
  28652. var me = this;
  28653. domUtils.on(window, "resize", function () {
  28654. if (me._hidden || me._hidden === undefined) {
  28655. return;
  28656. }
  28657. if (me.__resizeTimer) {
  28658. window.clearTimeout(me.__resizeTimer);
  28659. }
  28660. me.__resizeTimer = window.setTimeout(function () {
  28661. me.__resizeTimer = null;
  28662. var dialogWrapNode = me.getDom(),
  28663. contentNode = me.getDom("content"),
  28664. wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
  28665. contentRect = UE.ui.uiUtils.getClientRect(contentNode),
  28666. vpRect = uiUtils.getViewportRect();
  28667. contentNode.style.width =
  28668. vpRect.width - wrapRect.width + contentRect.width + "px";
  28669. contentNode.style.height =
  28670. vpRect.height - wrapRect.height + contentRect.height + "px";
  28671. dialogWrapNode.style.width = vpRect.width + "px";
  28672. dialogWrapNode.style.height = vpRect.height + "px";
  28673. me.fireEvent("resize");
  28674. }, 100);
  28675. });
  28676. },
  28677. fitSize: function () {
  28678. var popBodyEl = this.getDom("body");
  28679. // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
  28680. // uiUtils.removeStyle(popBodyEl, 'width');
  28681. // uiUtils.removeStyle(popBodyEl, 'height');
  28682. // }
  28683. var size = this.mesureSize();
  28684. popBodyEl.style.width = size.width + "px";
  28685. popBodyEl.style.height = size.height + "px";
  28686. return size;
  28687. },
  28688. safeSetOffset: function (offset) {
  28689. var me = this;
  28690. var el = me.getDom();
  28691. var vpRect = uiUtils.getViewportRect();
  28692. var rect = uiUtils.getClientRect(el);
  28693. var left = offset.left;
  28694. if (left + rect.width > vpRect.right) {
  28695. left = vpRect.right - rect.width;
  28696. }
  28697. var top = offset.top;
  28698. if (top + rect.height > vpRect.bottom) {
  28699. top = vpRect.bottom - rect.height;
  28700. }
  28701. el.style.left = Math.max(left, 0) + "px";
  28702. el.style.top = Math.max(top, 0) + "px";
  28703. },
  28704. showAtCenter: function () {
  28705. var vpRect = uiUtils.getViewportRect();
  28706. if (!this.fullscreen) {
  28707. this.getDom().style.display = "";
  28708. var popSize = this.fitSize();
  28709. var titleHeight = this.getDom("titlebar").offsetHeight | 0;
  28710. var left = vpRect.width / 2 - popSize.width / 2;
  28711. var top =
  28712. vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
  28713. var popEl = this.getDom();
  28714. this.safeSetOffset({
  28715. left: Math.max(left | 0, 0),
  28716. top: Math.max(top | 0, 0)
  28717. });
  28718. if (!domUtils.hasClass(popEl, "edui-state-centered")) {
  28719. popEl.className += " edui-state-centered";
  28720. }
  28721. } else {
  28722. var dialogWrapNode = this.getDom(),
  28723. contentNode = this.getDom("content");
  28724. dialogWrapNode.style.display = "block";
  28725. var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
  28726. contentRect = UE.ui.uiUtils.getClientRect(contentNode);
  28727. dialogWrapNode.style.left = "-100000px";
  28728. contentNode.style.width =
  28729. vpRect.width - wrapRect.width + contentRect.width + "px";
  28730. contentNode.style.height =
  28731. vpRect.height - wrapRect.height + contentRect.height + "px";
  28732. dialogWrapNode.style.width = vpRect.width + "px";
  28733. dialogWrapNode.style.height = vpRect.height + "px";
  28734. dialogWrapNode.style.left = 0;
  28735. //保存环境的overflow值
  28736. this._originalContext = {
  28737. html: {
  28738. overflowX: document.documentElement.style.overflowX,
  28739. overflowY: document.documentElement.style.overflowY
  28740. },
  28741. body: {
  28742. overflowX: document.body.style.overflowX,
  28743. overflowY: document.body.style.overflowY
  28744. }
  28745. };
  28746. document.documentElement.style.overflowX = "hidden";
  28747. document.documentElement.style.overflowY = "hidden";
  28748. document.body.style.overflowX = "hidden";
  28749. document.body.style.overflowY = "hidden";
  28750. }
  28751. this._show();
  28752. },
  28753. getContentHtml: function () {
  28754. var contentHtml = "";
  28755. if (typeof this.content == "string") {
  28756. contentHtml = this.content;
  28757. } else if (this.iframeUrl) {
  28758. contentHtml =
  28759. '<span id="' +
  28760. this.id +
  28761. '_contmask" class="dialogcontmask"></span><iframe id="' +
  28762. this.id +
  28763. '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="' +
  28764. this.iframeUrl +
  28765. '"></iframe>';
  28766. }
  28767. return contentHtml;
  28768. },
  28769. getHtmlTpl: function () {
  28770. var footHtml = "";
  28771. if (this.buttons) {
  28772. var buff = [];
  28773. for (var i = 0; i < this.buttons.length; i++) {
  28774. buff[i] = this.buttons[i].renderHtml();
  28775. }
  28776. footHtml =
  28777. '<div class="%%-foot">' +
  28778. '<div id="##_buttons" class="%%-buttons">' +
  28779. buff.join("") +
  28780. "</div>" +
  28781. "</div>";
  28782. }
  28783. return (
  28784. '<div id="##" class="%%"><div ' +
  28785. (!this.fullscreen
  28786. ? 'class="%%"'
  28787. : 'class="%%-wrap edui-dialog-fullscreen-flag"') +
  28788. '><div id="##_body" class="%%-body">' +
  28789. '<div class="%%-shadow"></div>' +
  28790. '<div id="##_titlebar" class="%%-titlebar">' +
  28791. '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
  28792. '<span class="%%-caption">' +
  28793. (this.title || "") +
  28794. "</span>" +
  28795. "</div>" +
  28796. this.closeButton.renderHtml() +
  28797. "</div>" +
  28798. '<div id="##_content" class="%%-content">' +
  28799. (this.autoReset ? "" : this.getContentHtml()) +
  28800. "</div>" +
  28801. footHtml +
  28802. "</div></div></div>"
  28803. );
  28804. },
  28805. postRender: function () {
  28806. // todo: 保持居中/记住上次关闭位置选项
  28807. if (!this.modalMask.getDom()) {
  28808. this.modalMask.render();
  28809. this.modalMask.hide();
  28810. }
  28811. if (!this.dragMask.getDom()) {
  28812. this.dragMask.render();
  28813. this.dragMask.hide();
  28814. }
  28815. var me = this;
  28816. this.addListener("show", function () {
  28817. me.modalMask.show(this.getDom().style.zIndex - 2);
  28818. });
  28819. this.addListener("hide", function () {
  28820. me.modalMask.hide();
  28821. });
  28822. if (this.buttons) {
  28823. for (var i = 0; i < this.buttons.length; i++) {
  28824. this.buttons[i].postRender();
  28825. }
  28826. }
  28827. domUtils.on(window, "resize", function () {
  28828. setTimeout(function () {
  28829. if (!me.isHidden()) {
  28830. me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
  28831. }
  28832. });
  28833. });
  28834. //hold住scroll事件,防止dialog的滚动影响页面
  28835. // if( this.holdScroll ) {
  28836. //
  28837. // if( !me.iframeUrl ) {
  28838. // domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  28839. // domUtils.preventDefault(e);
  28840. // } );
  28841. // } else {
  28842. // me.addListener('dialogafterreset', function(){
  28843. // window.setTimeout(function(){
  28844. // var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
  28845. //
  28846. // if( browser.ie ) {
  28847. //
  28848. // var timer = window.setInterval(function(){
  28849. //
  28850. // if( iframeWindow.document && iframeWindow.document.body ) {
  28851. // window.clearInterval( timer );
  28852. // timer = null;
  28853. // domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  28854. // domUtils.preventDefault(e);
  28855. // } );
  28856. // }
  28857. //
  28858. // }, 100);
  28859. //
  28860. // } else {
  28861. // domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  28862. // domUtils.preventDefault(e);
  28863. // } );
  28864. // }
  28865. //
  28866. // }, 1);
  28867. // });
  28868. // }
  28869. //
  28870. // }
  28871. this._hide();
  28872. },
  28873. mesureSize: function () {
  28874. var body = this.getDom("body");
  28875. var width = uiUtils.getClientRect(this.getDom("content")).width;
  28876. var dialogBodyStyle = body.style;
  28877. dialogBodyStyle.width = width;
  28878. return uiUtils.getClientRect(body);
  28879. },
  28880. _onTitlebarMouseDown: function (evt, el) {
  28881. if (this.draggable) {
  28882. var rect;
  28883. var vpRect = uiUtils.getViewportRect();
  28884. var me = this;
  28885. uiUtils.startDrag(evt, {
  28886. ondragstart: function () {
  28887. rect = uiUtils.getClientRect(me.getDom());
  28888. me.getDom("contmask").style.visibility = "visible";
  28889. me.dragMask.show(me.getDom().style.zIndex - 1);
  28890. },
  28891. ondragmove: function (x, y) {
  28892. var left = rect.left + x;
  28893. var top = rect.top + y;
  28894. me.safeSetOffset({
  28895. left: left,
  28896. top: top
  28897. });
  28898. },
  28899. ondragstop: function () {
  28900. me.getDom("contmask").style.visibility = "hidden";
  28901. domUtils.removeClasses(me.getDom(), ["edui-state-centered"]);
  28902. me.dragMask.hide();
  28903. }
  28904. });
  28905. }
  28906. },
  28907. reset: function () {
  28908. this.getDom("content").innerHTML = this.getContentHtml();
  28909. this.fireEvent("dialogafterreset");
  28910. },
  28911. _show: function () {
  28912. if (this._hidden) {
  28913. this.getDom().style.display = "";
  28914. //要高过编辑器的zindxe
  28915. this.editor.container.style.zIndex &&
  28916. (this.getDom().style.zIndex =
  28917. this.editor.container.style.zIndex * 1 + 10);
  28918. this._hidden = false;
  28919. this.fireEvent("show");
  28920. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
  28921. this.getDom().style.zIndex - 4;
  28922. }
  28923. },
  28924. isHidden: function () {
  28925. return this._hidden;
  28926. },
  28927. _hide: function () {
  28928. if (!this._hidden) {
  28929. var wrapNode = this.getDom();
  28930. wrapNode.style.display = "none";
  28931. wrapNode.style.zIndex = "";
  28932. wrapNode.style.width = "";
  28933. wrapNode.style.height = "";
  28934. this._hidden = true;
  28935. this.fireEvent("hide");
  28936. }
  28937. },
  28938. open: function () {
  28939. if (this.autoReset) {
  28940. //有可能还没有渲染
  28941. try {
  28942. this.reset();
  28943. } catch (e) {
  28944. this.render();
  28945. this.open();
  28946. }
  28947. }
  28948. this.showAtCenter();
  28949. if (this.iframeUrl) {
  28950. try {
  28951. this.getDom("iframe").focus();
  28952. } catch (ex) {
  28953. }
  28954. }
  28955. activeDialog = this;
  28956. },
  28957. _onCloseButtonClick: function (evt, el) {
  28958. this.close(false);
  28959. },
  28960. close: function (ok) {
  28961. if (this.fireEvent("close", ok) !== false) {
  28962. //还原环境
  28963. if (this.fullscreen) {
  28964. document.documentElement.style.overflowX = this._originalContext.html.overflowX;
  28965. document.documentElement.style.overflowY = this._originalContext.html.overflowY;
  28966. document.body.style.overflowX = this._originalContext.body.overflowX;
  28967. document.body.style.overflowY = this._originalContext.body.overflowY;
  28968. delete this._originalContext;
  28969. }
  28970. this._hide();
  28971. //销毁content
  28972. var content = this.getDom("content");
  28973. var iframe = this.getDom("iframe");
  28974. if (content && iframe) {
  28975. var doc = iframe.contentDocument || iframe.contentWindow.document;
  28976. doc && (doc.body.innerHTML = "");
  28977. domUtils.remove(content);
  28978. }
  28979. }
  28980. }
  28981. };
  28982. utils.inherits(Dialog, UIBase);
  28983. })();
  28984. // ui/menubutton.js
  28985. ///import core
  28986. ///import uicore
  28987. ///import ui/menu.js
  28988. ///import ui/splitbutton.js
  28989. ;(function () {
  28990. var utils = baidu.editor.utils,
  28991. Menu = baidu.editor.ui.Menu,
  28992. SplitButton = baidu.editor.ui.SplitButton,
  28993. MenuButton = (baidu.editor.ui.MenuButton = function (options) {
  28994. this.initOptions(options);
  28995. this.initMenuButton();
  28996. });
  28997. MenuButton.prototype = {
  28998. initMenuButton: function () {
  28999. var me = this;
  29000. this.uiName = "menubutton";
  29001. this.popup = new Menu({
  29002. items: me.items,
  29003. className: me.className,
  29004. editor: me.editor
  29005. });
  29006. this.popup.addListener("show", function () {
  29007. var list = this;
  29008. for (var i = 0; i < list.items.length; i++) {
  29009. list.items[i].removeState("checked");
  29010. if (list.items[i].value == me._value) {
  29011. list.items[i].addState("checked");
  29012. this.value = me._value;
  29013. }
  29014. }
  29015. });
  29016. this.initSplitButton();
  29017. },
  29018. setValue: function (value) {
  29019. this._value = value;
  29020. }
  29021. };
  29022. utils.inherits(MenuButton, SplitButton);
  29023. })();
  29024. // ui/multiMenu.js
  29025. ///import core
  29026. ///import uicore
  29027. ///commands 表情
  29028. ;(function () {
  29029. var utils = baidu.editor.utils,
  29030. Popup = baidu.editor.ui.Popup,
  29031. SplitButton = baidu.editor.ui.SplitButton,
  29032. MultiMenuPop = (baidu.editor.ui.MultiMenuPop = function (options) {
  29033. this.initOptions(options);
  29034. this.initMultiMenu();
  29035. });
  29036. MultiMenuPop.prototype = {
  29037. initMultiMenu: function () {
  29038. var me = this;
  29039. this.popup = new Popup({
  29040. content: "",
  29041. editor: me.editor,
  29042. iframe_rendered: false,
  29043. onshow: function () {
  29044. if (!this.iframe_rendered) {
  29045. this.iframe_rendered = true;
  29046. this.getDom("content").innerHTML =
  29047. '<iframe id="' +
  29048. me.id +
  29049. '_iframe" src="' +
  29050. me.iframeUrl +
  29051. '" frameborder="0"></iframe>';
  29052. me.editor.container.style.zIndex &&
  29053. (this.getDom().style.zIndex =
  29054. me.editor.container.style.zIndex * 1 + 1);
  29055. }
  29056. }
  29057. // canSideUp:false,
  29058. // canSideLeft:false
  29059. });
  29060. this.onbuttonclick = function () {
  29061. this.showPopup();
  29062. };
  29063. this.initSplitButton();
  29064. }
  29065. };
  29066. utils.inherits(MultiMenuPop, SplitButton);
  29067. })();
  29068. // ui/shortcutmenu.js
  29069. ;(function () {
  29070. var UI = baidu.editor.ui,
  29071. UIBase = UI.UIBase,
  29072. uiUtils = UI.uiUtils,
  29073. utils = baidu.editor.utils,
  29074. domUtils = baidu.editor.dom.domUtils;
  29075. var allMenus = [], //存储所有快捷菜单
  29076. timeID,
  29077. isSubMenuShow = false; //是否有子pop显示
  29078. var ShortCutMenu = (UI.ShortCutMenu = function (options) {
  29079. this.initOptions(options);
  29080. this.initShortCutMenu();
  29081. });
  29082. ShortCutMenu.postHide = hideAllMenu;
  29083. ShortCutMenu.prototype = {
  29084. isHidden: true,
  29085. SPACE: 5,
  29086. initShortCutMenu: function () {
  29087. this.items = this.items || [];
  29088. this.initUIBase();
  29089. this.initItems();
  29090. this.initEvent();
  29091. allMenus.push(this);
  29092. },
  29093. initEvent: function () {
  29094. var me = this,
  29095. doc = me.editor.document;
  29096. domUtils.on(doc, "mousemove", function (e) {
  29097. if (me.isHidden === false) {
  29098. //有pop显示就不隐藏快捷菜单
  29099. if (me.getSubMenuMark() || me.eventType == "contextmenu") return;
  29100. var flag = true,
  29101. el = me.getDom(),
  29102. wt = el.offsetWidth,
  29103. ht = el.offsetHeight,
  29104. distanceX = wt / 2 + me.SPACE, //距离中心X标准
  29105. distanceY = ht / 2, //距离中心Y标准
  29106. x = Math.abs(e.screenX - me.left), //离中心距离横坐标
  29107. y = Math.abs(e.screenY - me.top); //离中心距离纵坐标
  29108. clearTimeout(timeID);
  29109. timeID = setTimeout(function () {
  29110. if (y > 0 && y < distanceY) {
  29111. me.setOpacity(el, "1");
  29112. } else if (y > distanceY && y < distanceY + 70) {
  29113. me.setOpacity(el, "0.5");
  29114. flag = false;
  29115. } else if (y > distanceY + 70 && y < distanceY + 140) {
  29116. me.hide();
  29117. }
  29118. if (flag && x > 0 && x < distanceX) {
  29119. me.setOpacity(el, "1");
  29120. } else if (x > distanceX && x < distanceX + 70) {
  29121. me.setOpacity(el, "0.5");
  29122. } else if (x > distanceX + 70 && x < distanceX + 140) {
  29123. me.hide();
  29124. }
  29125. });
  29126. }
  29127. });
  29128. //ie\ff下 mouseout不准
  29129. if (browser.chrome) {
  29130. domUtils.on(doc, "mouseout", function (e) {
  29131. var relatedTgt = e.relatedTarget || e.toElement;
  29132. if (relatedTgt == null || relatedTgt.tagName == "HTML") {
  29133. me.hide();
  29134. }
  29135. });
  29136. }
  29137. me.editor.addListener("afterhidepop", function () {
  29138. if (!me.isHidden) {
  29139. isSubMenuShow = true;
  29140. }
  29141. });
  29142. },
  29143. initItems: function () {
  29144. if (utils.isArray(this.items)) {
  29145. for (var i = 0, len = this.items.length; i < len; i++) {
  29146. var item = this.items[i].toLowerCase();
  29147. if (UI[item]) {
  29148. this.items[i] = new UI[item](this.editor);
  29149. this.items[i].className += " edui-shortcutsubmenu ";
  29150. }
  29151. }
  29152. }
  29153. },
  29154. setOpacity: function (el, value) {
  29155. if (browser.ie && browser.version < 9) {
  29156. el.style.filter = "alpha(opacity = " + parseFloat(value) * 100 + ");";
  29157. } else {
  29158. el.style.opacity = value;
  29159. }
  29160. },
  29161. getSubMenuMark: function () {
  29162. isSubMenuShow = false;
  29163. var layerEle = uiUtils.getFixedLayer();
  29164. var list = domUtils.getElementsByTagName(layerEle, "div", function (node) {
  29165. return domUtils.hasClass(node, "edui-shortcutsubmenu edui-popup");
  29166. });
  29167. for (var i = 0, node; (node = list[i++]);) {
  29168. if (node.style.display != "none") {
  29169. isSubMenuShow = true;
  29170. }
  29171. }
  29172. return isSubMenuShow;
  29173. },
  29174. show: function (e, hasContextmenu) {
  29175. var me = this,
  29176. offset = {},
  29177. el = this.getDom(),
  29178. fixedlayer = uiUtils.getFixedLayer();
  29179. function setPos(offset) {
  29180. if (offset.left < 0) {
  29181. offset.left = 0;
  29182. }
  29183. if (offset.top < 0) {
  29184. offset.top = 0;
  29185. }
  29186. el.style.cssText =
  29187. "position:absolute;left:" +
  29188. offset.left +
  29189. "px;top:" +
  29190. offset.top +
  29191. "px;";
  29192. }
  29193. function setPosByCxtMenu(menu) {
  29194. if (!menu.tagName) {
  29195. menu = menu.getDom();
  29196. }
  29197. offset.left = parseInt(menu.style.left);
  29198. offset.top = parseInt(menu.style.top);
  29199. offset.top -= el.offsetHeight + 15;
  29200. setPos(offset);
  29201. }
  29202. me.eventType = e.type;
  29203. el.style.cssText = "display:block;left:-9999px";
  29204. if (e.type == "contextmenu" && hasContextmenu) {
  29205. var menu = domUtils.getElementsByTagName(
  29206. fixedlayer,
  29207. "div",
  29208. "edui-contextmenu"
  29209. )[0];
  29210. if (menu) {
  29211. setPosByCxtMenu(menu);
  29212. } else {
  29213. me.editor.addListener("aftershowcontextmenu", function (type, menu) {
  29214. setPosByCxtMenu(menu);
  29215. });
  29216. }
  29217. } else {
  29218. offset = uiUtils.getViewportOffsetByEvent(e);
  29219. offset.top -= el.offsetHeight + me.SPACE;
  29220. offset.left += me.SPACE + 20;
  29221. setPos(offset);
  29222. me.setOpacity(el, 0.2);
  29223. }
  29224. me.isHidden = false;
  29225. me.left = e.screenX + el.offsetWidth / 2 - me.SPACE;
  29226. me.top = e.screenY - el.offsetHeight / 2 - me.SPACE;
  29227. if (me.editor) {
  29228. el.style.zIndex = me.editor.container.style.zIndex * 1 + 10;
  29229. fixedlayer.style.zIndex = el.style.zIndex - 1;
  29230. }
  29231. },
  29232. hide: function () {
  29233. if (this.getDom()) {
  29234. this.getDom().style.display = "none";
  29235. }
  29236. this.isHidden = true;
  29237. },
  29238. postRender: function () {
  29239. if (utils.isArray(this.items)) {
  29240. for (var i = 0, item; (item = this.items[i++]);) {
  29241. item.postRender();
  29242. }
  29243. }
  29244. },
  29245. getHtmlTpl: function () {
  29246. var buff;
  29247. if (utils.isArray(this.items)) {
  29248. buff = [];
  29249. for (var i = 0; i < this.items.length; i++) {
  29250. buff[i] = this.items[i].renderHtml();
  29251. }
  29252. buff = buff.join("");
  29253. } else {
  29254. buff = this.items;
  29255. }
  29256. return (
  29257. '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
  29258. buff +
  29259. "</div>"
  29260. );
  29261. }
  29262. };
  29263. utils.inherits(ShortCutMenu, UIBase);
  29264. function hideAllMenu(e) {
  29265. var tgt = e.target || e.srcElement,
  29266. cur = domUtils.findParent(
  29267. tgt,
  29268. function (node) {
  29269. return (
  29270. domUtils.hasClass(node, "edui-shortcutmenu") ||
  29271. domUtils.hasClass(node, "edui-popup")
  29272. );
  29273. },
  29274. true
  29275. );
  29276. if (!cur) {
  29277. for (var i = 0, menu; (menu = allMenus[i++]);) {
  29278. menu.hide();
  29279. }
  29280. }
  29281. }
  29282. domUtils.on(document, "mousedown", function (e) {
  29283. hideAllMenu(e);
  29284. });
  29285. domUtils.on(window, "scroll", function (e) {
  29286. hideAllMenu(e);
  29287. });
  29288. })();
  29289. // ui/breakline.js
  29290. ;(function () {
  29291. var utils = baidu.editor.utils,
  29292. UIBase = baidu.editor.ui.UIBase,
  29293. Breakline = (baidu.editor.ui.Breakline = function (options) {
  29294. this.initOptions(options);
  29295. this.initSeparator();
  29296. });
  29297. Breakline.prototype = {
  29298. uiName: "Breakline",
  29299. initSeparator: function () {
  29300. this.initUIBase();
  29301. },
  29302. getHtmlTpl: function () {
  29303. return "<br/>";
  29304. }
  29305. };
  29306. utils.inherits(Breakline, UIBase);
  29307. })();
  29308. // ui/message.js
  29309. ///import core
  29310. ///import uicore
  29311. ;(function () {
  29312. var utils = baidu.editor.utils,
  29313. domUtils = baidu.editor.dom.domUtils,
  29314. UIBase = baidu.editor.ui.UIBase,
  29315. Message = (baidu.editor.ui.Message = function (options) {
  29316. this.initOptions(options);
  29317. this.initMessage();
  29318. });
  29319. Message.prototype = {
  29320. initMessage: function () {
  29321. this.initUIBase();
  29322. },
  29323. getHtmlTpl: function () {
  29324. return (
  29325. '<div id="##" class="edui-message %%">' +
  29326. ' <div id="##_closer" class="edui-message-closer">×</div>' +
  29327. ' <div id="##_body" class="edui-message-body edui-message-type-info">' +
  29328. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  29329. ' <div class="edui-shadow"></div>' +
  29330. ' <div id="##_content" class="edui-message-content">' +
  29331. " </div>" +
  29332. " </div>" +
  29333. "</div>"
  29334. );
  29335. },
  29336. reset: function (opt) {
  29337. var me = this;
  29338. if (!opt.keepshow) {
  29339. clearTimeout(this.timer);
  29340. me.timer = setTimeout(function () {
  29341. me.hide();
  29342. }, opt.timeout || 4000);
  29343. }
  29344. opt.content !== undefined && me.setContent(opt.content);
  29345. opt.type !== undefined && me.setType(opt.type);
  29346. me.show();
  29347. },
  29348. postRender: function () {
  29349. var me = this,
  29350. closer = this.getDom("closer");
  29351. closer &&
  29352. domUtils.on(closer, "click", function () {
  29353. me.hide();
  29354. });
  29355. },
  29356. setContent: function (content) {
  29357. this.getDom("content").innerHTML = content;
  29358. },
  29359. setType: function (type) {
  29360. type = type || "info";
  29361. var body = this.getDom("body");
  29362. body.className = body.className.replace(
  29363. /edui-message-type-[\w-]+/,
  29364. "edui-message-type-" + type
  29365. );
  29366. },
  29367. getContent: function () {
  29368. return this.getDom("content").innerHTML;
  29369. },
  29370. getType: function () {
  29371. var arr = this.getDom("body").match(/edui-message-type-([\w-]+)/);
  29372. return arr ? arr[1] : "";
  29373. },
  29374. show: function () {
  29375. this.getDom().style.display = "block";
  29376. },
  29377. hide: function () {
  29378. var dom = this.getDom();
  29379. if (dom) {
  29380. dom.style.display = "none";
  29381. dom.parentNode && dom.parentNode.removeChild(dom);
  29382. }
  29383. }
  29384. };
  29385. utils.inherits(Message, UIBase);
  29386. })();
  29387. // ui/iconfont.js
  29388. ;(function (window) {
  29389. var svgSprite = '<svg><symbol id="edui-for-close" viewBox="0 0 1024 1024"><path d="M960 153.6L870.4 64 512 422.4 153.6 64 64 153.6 422.4 512 64 870.4 153.6 960 512 601.6l358.4 358.4 89.6-89.6L601.6 512 960 153.6z" fill="#666666" ></path></symbol><symbol id="edui-for-italic" viewBox="0 0 1024 1024"><path d="M384 64v64h128L384 896H256v64h384v-64H512l128-768h128V64z" fill="#666666" ></path></symbol><symbol id="edui-for-insertcaption" viewBox="0 0 1024 1024"><path d="M576 0v448h448V0z m384 256h-128v128h-64V256h-128V192h128V64h64v128h128z" fill="#1C7C59" ></path><path d="M997.12 448H0v576h1024V448zM60.16 960v-256H320v256z m481.92 0H384v-256h256v256z m421.76 0H704v-256h259.84zM448 0H0v64h192v384h64V64h192V0z" fill="#666666" ></path></symbol><symbol id="edui-for-insertparagraph" viewBox="0 0 1024 1024"><path d="M997.12 0H0v576h1024V0zM60.16 512V256H320v256z m481.92 0H384V256h256v256z m421.76 0H704V256h259.84zM448 576H0v64h192v384h64v-384h192V576z" fill="#666666" ></path></symbol><symbol id="edui-for-inserttitlecol" viewBox="0 0 1024 1024"><path d="M64 960v-128H0v192h192v-64H64zM448 1024h576V0H448z m512-320v256h-192v-256z m-256 0v256H512v-256z m256-320v256h-192V384z m-256 0v256H512V384z m256-320v256h-192V64z m-256 0v256H512V64zM64 512h128V448H0v192h64V512zM384 512v128h64V448H256v64h128zM384 960H256v64h192v-192H384v128z" fill="#666666" ></path><path d="M64 960v-128H0v192h192v-64H64zM448 1024h576V0H448z m512-320v256h-192v-256z m-256 0v256H512v-256z m256-320v256h-192V384z m-256 0v256H512V384z m256-320v256h-192V64z m-256 0v256H512V64zM64 512h128V448H0v192h64V512zM384 512v128h64V448H256v64h128zM384 960H256v64h192v-192H384v128z" fill="#666666" ></path><path d="M0 448h448V0H0z m256-384v128h128v64H256v128H192V256H64V192h128V64z" fill="#1C7C59" ></path></symbol><symbol id="edui-for-insertimage" viewBox="0 0 1024 1024"><path d="M350.08 535.04l128 192 263.68-430.08 156.16 256V576h64V117.12a53.12 53.12 0 0 0-55.04-53.12H53.12a53.12 53.12 0 0 0-53.12 53.12v727.04a51.84 51.84 0 0 0 51.84 51.84H640v-64H154.88z m-53.12-350.72a119.04 119.04 0 1 1-118.4 118.4 119.04 119.04 0 0 1 118.4-118.4z" fill="#666666" ></path><path d="M1024 704h-192V512h-64v192H576v64h192v192h64v-192h192v-64z" fill="#666666" ></path></symbol><symbol id="edui-for-previousstep" viewBox="0 0 1024 1024"><path d="M483.84 896a53.76 53.76 0 0 1-24.96-6.4h-3.84L87.04 556.8A55.04 55.04 0 0 1 64 517.76a56.96 56.96 0 0 1 22.4-48.64l371.2-328.32a46.08 46.08 0 0 1 30.72-12.8 40.96 40.96 0 0 1 35.84 21.12 60.16 60.16 0 0 1 7.04 28.16v192h29.44a400 400 0 0 1 97.28 12.16 363.52 363.52 0 0 1 120.32 54.4A384 384 0 0 1 889.6 556.8 602.88 602.88 0 0 1 960 768a60.16 60.16 0 0 1-10.24 53.12 39.68 39.68 0 0 1-29.44 13.44 55.04 55.04 0 0 1-42.24-26.24 229.12 229.12 0 0 0-64-68.48 314.24 314.24 0 0 0-89.6-47.36 437.76 437.76 0 0 0-141.44-21.76h-48.64V832a68.48 68.48 0 0 1-12.8 51.2 43.52 43.52 0 0 1-37.76 12.8zM145.28 512l312.96 281.6v-148.48a64 64 0 0 1 68.48-48h53.12a507.52 507.52 0 0 1 167.68 26.88 384 384 0 0 1 110.72 60.16l9.6 7.68a354.56 354.56 0 0 0-128-197.76 312.32 312.32 0 0 0-176-53.12 240 240 0 0 0-33.92 0h-12.8a56.96 56.96 0 0 1-49.28-24.96 55.04 55.04 0 0 1-8.96-26.24V234.88z" fill="#666666" ></path></symbol><symbol id="edui-for-nextstep" viewBox="0 0 1024 1024"><path d="M506.88 880.64a68.48 68.48 0 0 1-12.8-51.2v-160h-48.64a437.76 437.76 0 0 0-141.44 21.76 314.24 314.24 0 0 0-89.6 47.36 229.12 229.12 0 0 0-64 68.48 55.04 55.04 0 0 1-42.24 26.24 39.68 39.68 0 0 1-29.44-13.44A60.16 60.16 0 0 1 64 768a602.88 602.88 0 0 1 70.4-211.2 384 384 0 0 1 111.36-124.16 363.52 363.52 0 0 1 120.32-54.4 400 400 0 0 1 97.28-12.16h29.44v-192a60.16 60.16 0 0 1 7.04-28.16 40.96 40.96 0 0 1 35.84-17.92 46.08 46.08 0 0 1 30.72 12.8l370.56 328.32a56.96 56.96 0 0 1 22.4 48.64 55.04 55.04 0 0 1-22.4 39.68l-368 330.24h-3.84a53.76 53.76 0 0 1-24.96 6.4 43.52 43.52 0 0 1-33.28-13.44z m58.24-645.76v154.24a55.04 55.04 0 0 1-8.96 26.24 56.96 56.96 0 0 1-49.28 24.96h-9.6a240 240 0 0 0-33.92 0 312.32 312.32 0 0 0-176 53.12 354.56 354.56 0 0 0-128 197.76l9.6-7.68a384 384 0 0 1 110.72-60.16 507.52 507.52 0 0 1 163.84-28.16h53.12a64 64 0 0 1 68.48 48v150.4l313.6-281.6z" fill="#666666" ></path></symbol><symbol id="edui-for-scaleboard" viewBox="0 0 1024 1024"><path d="M374.935252 651.624033a35.190169 35.190169 0 0 0-26.872492-11.516783H39.029096a40.308739 40.308739 0 0 0-39.029096 39.668918V704.089375a41.588381 41.588381 0 0 0 43.507845 37.749454h163.154419L19.834459 932.505561a53.105164 53.105164 0 0 0 0 74.859087 51.825521 51.825521 0 0 0 73.579443 0l186.827805-188.107448v165.073883a37.749454 37.749454 0 0 0 37.109633 39.029096h26.872492a36.469811 36.469811 0 0 0 39.668918-33.910526v-309.673485a36.469811 36.469811 0 0 0-8.957498-26.872493zM383.89275 325.955016V34.196526A35.82999 35.82999 0 0 0 343.584011 0.286h-28.152135a37.109632 37.109632 0 0 0-37.109632 39.029096v166.353525L94.053724 21.400101a51.1857 51.1857 0 0 0-72.939623 0 52.465342 52.465342 0 0 0 0 73.579444l184.26852 184.26852H43.507845A42.228202 42.228202 0 0 0 0 320.196625v26.872493A40.308739 40.308739 0 0 0 38.389275 384.17875h310.313306a35.190169 35.190169 0 0 0 26.232671-10.876961A35.82999 35.82999 0 0 0 383.89275 345.789475v-19.194637zM648.778747 372.661968a35.190169 35.190169 0 0 0 26.872493 10.876961H984.684904a40.308739 40.308739 0 0 0 39.029096-39.029096V320.196625a41.588381 41.588381 0 0 0-43.507845-37.749454h-163.154419l186.827805-187.467626a53.105164 53.105164 0 0 0 0-74.859086 51.825521 51.825521 0 0 0-73.579444 0L743.472292 205.0288V39.954918a37.749454 37.749454 0 0 0-36.469811-39.668918h-26.872492a36.469811 36.469811 0 0 0-40.308739 34.550348v309.673485a36.469811 36.469811 0 0 0 8.957497 26.872492zM639.82125 698.330984v291.118669a35.82999 35.82999 0 0 0 38.389275 33.910526h28.152135a37.109632 37.109632 0 0 0 37.109632-39.029096v-166.353525l185.548163 184.26852a51.1857 51.1857 0 0 0 72.939622 0 52.465342 52.465342 0 0 0 0-73.579444l-183.628698-183.628699h161.874776A42.228202 42.228202 0 0 0 1023.714 704.089375v-26.872492a40.308739 40.308739 0 0 0-38.389275-39.029097h-309.673485a35.190169 35.190169 0 0 0-26.232671 10.876962 35.82999 35.82999 0 0 0-8.957498 26.872492v19.194638z" fill="#666666" ></path></symbol><symbol id="edui-for-brush" viewBox="0 0 1024 1024"><path d="M986.878764 284.789854L739.847564 35.198746a122.875623 122.875623 0 0 0-172.153867 0L92.830614 511.981761a87.676877 87.676877 0 0 0-32.638837 56.317993L0.03392 915.807374a119.675737 119.675737 0 0 0 28.158997 79.99715 94.076649 94.076649 0 0 0 69.757515 28.158997h14.079498l344.307734-63.99772a86.396922 86.396922 0 0 0 55.678017-30.078928l474.863083-475.50306a115.195896 115.195896 0 0 0 0-169.593959zM448.017961 868.449062l-348.787575 63.99772 60.797834-348.147598 347.50762-351.347483 288.629718 287.349763z m474.863083-479.982901l-63.997721 70.397492-291.189626-286.709786 63.99772-63.99772a34.558769 34.558769 0 0 1 41.598518 0l246.391223 249.591108a35.838723 35.838723 0 0 1 9.599658 18.559339c1.919932 2.559909-3.199886 7.679726-7.679727 12.159567z" fill="#666666" ></path></symbol><symbol id="edui-for-background" viewBox="0 0 1024 1024"><path d="M988.16 448H419.84a35.84 35.84 0 0 0-35.84 35.84v504.32a35.84 35.84 0 0 0 35.84 35.84h568.96a35.84 35.84 0 0 0 35.84-35.84V483.84a35.84 35.84 0 0 0-36.48-35.84z m-323.84 164.48a80 80 0 1 1-80-81.92 81.28 81.28 0 0 1 80 81.92zM929.28 960H461.44l131.2-205.44 85.12 133.12 177.28-298.24L960 768v163.2a30.72 30.72 0 0 1-30.72 28.8z" fill="#666666" ></path><path d="M320 832H224a32 32 0 0 0 0 64H320zM320 640H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h640a64 64 0 0 1 64 64v256h64V64a64 64 0 0 0-64-64H64a64 64 0 0 0-64 64v576a64 64 0 0 0 64 64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-strikethrough" viewBox="0 0 1024 1024"><path d="M994.56 672a128 128 0 0 1-98.56 48.64c-74.24 0-122.88-57.6-128-150.4h236.8v-52.48H768c7.68-92.8 58.24-150.4 132.48-150.4a115.84 115.84 0 0 1 87.04 40.96l28.8-35.2A156.8 156.8 0 0 0 896 320c-100.48 0-176.64 74.24-186.88 197.76H608.64a96.64 96.64 0 0 0 44.16-83.84c0-76.16-59.52-105.6-146.56-105.6h-128v192H267.52l-64-192h-58.88l-64 192H22.4v52.48H64l-64 192h54.4l41.6-136.32h155.52l40.32 131.84h56.96l-64-192h95.36v192h135.68c95.36 0 161.28-41.6 161.28-128a103.04 103.04 0 0 0-19.84-64h52.48C719.36 694.4 794.24 768 896 768a163.84 163.84 0 0 0 128-64zM433.92 371.2h64c64 0 100.48 18.56 100.48 69.76S570.24 512 497.28 512h-64z m-261.76 0c14.08 49.92 26.88 96.64 42.88 145.28H128c17.28-47.36 31.36-93.44 44.16-144z m64 212.48h-128l4.48-14.72h120.96z m384 47.36c0 58.24-42.88 85.12-115.84 85.12h-70.4V570.24H588.8a64 64 0 0 1 35.2 61.44z" fill="#666666" ></path></symbol><symbol id="edui-for-spechars" viewBox="0 0 1024 1024"><path d="M954.24 1024l-158.72-160A434.56 434.56 0 0 1 512 965.76a421.12 421.12 0 0 1-283.52-101.76L69.76 1024 0 951.68l160.64-155.52A477.44 477.44 0 0 1 64 512a426.88 426.88 0 0 1 96.64-282.24L0 72.32 69.76 0l158.72 160A464 464 0 0 1 512 60.16a432 432 0 0 1 281.6 99.84L954.24 0 1024 72.32l-161.92 157.44A430.08 430.08 0 0 1 960 512a448 448 0 0 1-99.2 283.52L1024 951.68zM512 160a337.28 337.28 0 0 0-250.24 103.68A342.4 342.4 0 0 0 160.64 512a343.04 343.04 0 0 0 104.96 249.6 339.84 339.84 0 0 0 492.16 0A344.32 344.32 0 0 0 862.08 512a332.8 332.8 0 0 0-105.6-250.24A339.84 339.84 0 0 0 512 160z" fill="#666666" ></path></symbol><symbol id="edui-for-clearboard" viewBox="0 0 1024 1024"><path d="M704 128V0H320v128H0v64h64v832h896V192h64V128zM384 64h256v64H384zM320 960H128V384h192z m320 0H384V384h256z m256 0h-192V384h192z m0-640H128V192h768z" fill="#666666" ></path></symbol><symbol id="edui-for-bold" viewBox="0 0 1024 1024"><path d="M876.8 710.4c-6.4-51.2-25.6-102.4-57.6-140.8-32-38.4-83.2-70.4-128-76.8 44.8-12.8 76.8-38.4 102.4-76.8 32-38.4 38.4-83.2 38.4-134.4 0-57.6-25.6-121.6-70.4-166.4C710.4 76.8 640 64 576 64H192v896h384c76.8 6.4 140.8-12.8 211.2-51.2 57.6-44.8 96-121.6 89.6-198.4zM288 153.6h262.4c44.8 0 96 6.4 134.4 38.4 32 25.6 51.2 57.6 44.8 96 0 44.8-12.8 83.2-44.8 115.2-38.4 32-89.6 44.8-134.4 38.4H288V153.6zM768 704c0 51.2-25.6 102.4-70.4 134.4-44.8 25.6-89.6 38.4-140.8 38.4H288V544h275.2c51.2 0 102.4 6.4 147.2 38.4 44.8 25.6 64 76.8 57.6 121.6z" fill="#666666" ></path></symbol><symbol id="edui-for-fullscreen" viewBox="0 0 1024 1024"><path d="M960 0H64a64 64 0 0 0-64 64v704a64 64 0 0 0 64 64h320v128H288a32 32 0 0 0 0 64h448a32 32 0 0 0 0-64H640v-128h320a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64zM576 960H448v-128h128z m384-256a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-formatmatch" viewBox="0 0 1024 1024"><path d="M128 448v448l108.8-300.8L396.8 896H896V448zM128 256h768v64H128zM384 128h256v128H384z" fill="#666666" ></path></symbol><symbol id="edui-for-underline" viewBox="0 0 1024 1024"><path d="M192 896h640v64H192zM704 64v384c0 102.4-83.2 192-192 192-102.4 0-192-83.2-192-192V64H192v384c0 179.2 147.2 320 320 320s320-147.2 320-320V64h-128z" fill="#666666" ></path></symbol><symbol id="edui-for-removeformat" viewBox="0 0 1024 1024"><path d="M682.88 64L0 768l170.88 192h398.08L1024 448zM528 832h-288L192 775.04l192-227.2 192 227.84z" fill="#666666" ></path></symbol><symbol id="edui-for-blockquote" viewBox="0 0 1024 1024"><path d="M401.92 894.272v-292.48H248.064c-7.36-187.392 65.92-344.96 219.648-472.448L401.856 61.888C218.88 189.44 127.36 384.384 127.36 646.72v247.552h274.56z m428.16 0v-292.48h-153.728c-7.36-187.392 65.92-344.96 219.648-472.448L830.08 61.888c-182.976 127.616-274.432 322.496-274.432 584.832v247.552h274.496z" fill="#666666" ></path></symbol><symbol id="edui-for-anchor" viewBox="0 0 1024 1024"><path d="M722.56 668.16l76.8 72.32A438.4 438.4 0 0 1 576 837.76V436.48a192 192 0 1 0-128 0v400a448 448 0 0 1-231.68-90.88l82.56-77.44L0 625.28l45.44 280.96L124.8 832a618.88 618.88 0 0 0 384 128 597.12 597.12 0 0 0 384-133.12l87.04 81.92 44.16-283.52zM384 256a128 128 0 1 1 128 128 128 128 0 0 1-128-128z" fill="#666666" ></path></symbol><symbol id="edui-for-help" viewBox="0 0 1024 1024"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m0 960a448 448 0 1 1 448-448 448 448 0 0 1-448 448z" fill="#666666" ></path><path d="M512 640H448v-27.52a151.68 151.68 0 0 1 75.52-117.76q64-47.36 64-90.24a64 64 0 0 0-64-57.6q-76.8 0-95.36 87.68L320 414.08A192 192 0 0 1 536.96 256q153.6 7.68 167.04 135.68a156.16 156.16 0 0 1-90.24 140.8A544 544 0 0 0 512 620.16zM448 704h128v128H448z" fill="#666666" ></path></symbol><symbol id="edui-for-horizontal" viewBox="0 0 1024 1024"><path d="M0 448h1024v128H0z" fill="#666666" ></path></symbol><symbol id="edui-for-simpleupload" viewBox="0 0 1024 1024"><path d="M128 832l160-320L448 832H128zM514.56 832l254.72-512L1024 832H514.56z" fill="#666666" ></path><path d="M960 64H64a64 64 0 0 0-64 64v768a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V128a64 64 0 0 0-64-64z m0 768a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V192a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-indent" viewBox="0 0 1024 1024"><path d="M896 416L768 320v384l128-96L1024 512zM32 128h960c19.2 0 32-12.8 32-32s-12.8-32-32-32H32c-19.2 0-32 12.8-32 32s12.8 32 32 32zM32 960h960c19.2 0 32-12.8 32-32s-12.8-32-32-32H32c-19.2 0-32 12.8-32 32s12.8 32 32 32zM64 448h512c32 0 64-25.6 64-64 0-32-25.6-64-64-64H64c-38.4 0-64 25.6-64 64s25.6 64 64 64zM64 704h512c32 0 64-25.6 64-64 0-32-25.6-64-64-64H64c-32 0-64 25.6-64 64s25.6 64 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-justifycenter" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 256h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 640h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 1024h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 640h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-justifyleft" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM608 256h-576C12.8 256 0 243.2 0 224S12.8 192 32 192h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM608 1024h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM608 640h-576c-19.2 0-32-12.8-32-32S12.8 576 32 576h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-justifyjustify" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 256H32C12.8 256 0 243.2 0 224S12.8 192 32 192h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 1024H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 640H32c-19.2 0-32-12.8-32-32S12.8 576 32 576h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-justifyright" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 256h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 1024h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 640h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-link" viewBox="0 0 1024 1024"><path d="M759.04 768v-124.16a132.48 132.48 0 1 0 0-264.96H608.64A135.04 135.04 0 0 0 472.32 512h-128a261.12 261.12 0 0 1 264.32-256h150.4A261.12 261.12 0 0 1 1024 512a261.12 261.12 0 0 1-264.96 256z" fill="#666666" ></path><path d="M415.36 768H264.96A261.12 261.12 0 0 1 0 512a261.12 261.12 0 0 1 264.96-256v124.16a132.48 132.48 0 1 0 0 264.96h150.4A135.04 135.04 0 0 0 552.32 512h128a261.12 261.12 0 0 1-264.96 256z" fill="#666666" ></path></symbol><symbol id="edui-for-cleardoc" viewBox="0 0 1024 1024"><path d="M895.909541 256.060626h-191.95477V56.427664A63.984924 63.984924 0 0 0 639.969847 0.120932H137.688197A69.743567 69.743567 0 0 0 64.105535 64.105855v895.78893a69.743567 69.743567 0 0 0 73.582662 63.984923h748.623606A69.743567 69.743567 0 0 0 959.894465 959.894785V313.007208A63.984924 63.984924 0 0 0 895.909541 256.060626z m0 695.516119a8.31804 8.31804 0 0 1-8.31804 8.31804H137.688197a9.597739 9.597739 0 0 1-9.597738-9.597739V72.423895A8.31804 8.31804 0 0 1 136.408499 64.105855h491.404213a11.517286 11.517286 0 0 1 12.157135 10.877437v191.954771A60.145828 60.145828 0 0 0 703.954771 320.045549h180.437484a11.517286 11.517286 0 0 1 12.157136 10.877437v620.653759z" fill="#666666" ></path></symbol><symbol id="edui-for-drafts" viewBox="0 0 1024 1024"><path d="M832 320V160a32 32 0 0 0-32-32H576V64a64 64 0 0 0-64-64H384a64 64 0 0 0-64 64v64H96a32 32 0 0 0-32 32v640a32 32 0 0 0 32 32H384v192h448l192-192V320zM384 64h128v64H384zM192 192h512v64H192z m640 741.76V832h101.76zM960 768h-192v192H448V384h512z" fill="#666666" ></path></symbol><symbol id="edui-for-subscript" viewBox="0 0 1024 1024"><path d="M716.8 819.2v-29.696c0-99.328 160.256-135.68 160.256-179.2 0-16.896-10.752-27.136-32.768-27.136a116.736 116.736 0 0 0-74.24 35.84l-47.104-51.2A170.496 170.496 0 0 1 852.992 512c76.288 0 119.808 40.448 119.808 93.184 0 74.752-95.232 94.72-142.848 141.312H972.8V819.2zM72.192 720.384l494.592-494.592a56.832 56.832 0 0 1 78.848-8.704l7.68 7.68a56.832 56.832 0 0 1-8.704 78.848l-494.592 494.592a56.832 56.832 0 0 1-78.848 8.704l-7.68-7.68a56.832 56.832 0 0 1 8.704-78.848z" fill="#666666" ></path><path d="M566.784 798.208L72.192 303.616a56.832 56.832 0 0 1-8.704-78.848l7.68-7.68a56.832 56.832 0 0 1 78.848 8.704l494.592 494.592a56.832 56.832 0 0 1 8.704 78.848l-7.68 7.68a56.832 56.832 0 0 1-78.848-8.704z" fill="#666666" ></path></symbol><symbol id="edui-for-unlink" viewBox="0 0 1024 1024"><path d="M539.416837 448.012238V320.036713A95.341766 95.341766 0 0 0 639.877623 233.653234v-19.196329A95.341766 95.341766 0 0 0 539.416837 128.073426H228.436312A95.341766 95.341766 0 0 0 127.975525 214.456905v18.556451A95.341766 95.341766 0 0 0 228.436312 320.036713v127.975525A222.037535 222.037535 0 0 1 0 233.653234v-19.196329A222.037535 222.037535 0 0 1 228.436312 0.097901h310.980525A222.037535 222.037535 0 0 1 767.853148 214.456905v18.556451A222.037535 222.037535 0 0 1 539.416837 448.012238zM795.367886 1023.902099H484.387361A222.037535 222.037535 0 0 1 255.951049 809.543095v-18.556451A222.037535 222.037535 0 0 1 484.387361 575.987762v127.975525A95.341766 95.341766 0 0 0 383.926574 790.346766v18.556451A95.341766 95.341766 0 0 0 484.387361 895.926574h311.620403A95.341766 95.341766 0 0 0 895.828673 809.543095v-18.556451A95.341766 95.341766 0 0 0 795.367886 703.963287V575.987762A222.037535 222.037535 0 0 1 1023.804197 790.346766v18.556451A222.037535 222.037535 0 0 1 795.367886 1023.902099z" fill="#666666" ></path></symbol><symbol id="edui-for-superscript" viewBox="0 0 1024 1024"><path d="M716.8 512v-29.696c0-99.328 160.256-135.68 160.256-179.2 0-16.896-10.752-27.136-32.768-27.136a116.736 116.736 0 0 0-74.24 35.84l-47.104-51.2A170.496 170.496 0 0 1 852.992 204.8C929.28 204.8 972.8 245.248 972.8 297.984c0 74.752-95.232 94.72-142.848 141.312H972.8V512zM72.192 720.384l494.592-494.592a56.832 56.832 0 0 1 78.848-8.704l7.68 7.68a56.832 56.832 0 0 1-8.704 78.848l-494.592 494.592a56.832 56.832 0 0 1-78.848 8.704l-7.68-7.68a56.832 56.832 0 0 1 8.704-78.848z" fill="#666666" ></path><path d="M566.784 798.208L72.192 303.616a56.832 56.832 0 0 1-8.704-78.848l7.68-7.68a56.832 56.832 0 0 1 78.848 8.704l494.592 494.592a56.832 56.832 0 0 1 8.704 78.848l-7.68 7.68a56.832 56.832 0 0 1-78.848-8.704z" fill="#666666" ></path></symbol><symbol id="edui-for-forecolor" viewBox="0 0 1024 1024"><path d="M588.8 64H428.8L192 768h108.8l57.6-166.4h275.2l57.6 166.4H832L588.8 64zM390.4 499.2l102.4-313.6 102.4 313.6H390.4zM192 896h640v64H192z" fill="#666666" ></path></symbol><symbol id="edui-for-backcolor" viewBox="0 0 1024 1024"><path d="M910.593777 663.461622s-105.39199 190.467451-105.39199 246.972795a105.39199 105.39199 0 1 0 210.149088 0c0.634892-59.04491-104.757098-246.972795-104.757098-246.972795zM412.838838 100.947749L388.712961 126.978301 266.813792 0 169.675392 100.312858l121.899168 126.978301L0.15936 526.325057 412.838838 952.337256 825.518316 526.325057z m-274.27313 425.377308l275.542913-283.796502 274.908021 283.796502z" fill="#666666" ></path></symbol><symbol id="edui-for-touppercase" viewBox="0 0 1024 1024"><path d="M295.68 128L0 896h113.28l74.24-192h328.96l71.04 192H704L408.32 128z m-53.12 448l92.16-250.88A245.76 245.76 0 0 0 353.28 256a225.92 225.92 0 0 0 16 69.12L461.44 576zM996.48 812.16v-115.84Q998.4 576 865.28 576t-152.32 92.16l67.84 17.92q8.32-55.68 82.56-51.84t64 53.76a224.64 224.64 0 0 1-97.28 19.84q-122.88 12.16-128 101.76T820.48 896a139.52 139.52 0 0 0 114.56-44.16 48.64 48.64 0 0 0 19.2 37.76H1024a102.4 102.4 0 0 1-27.52-77.44zM926.72 768q-6.4 64-95.36 71.68-56.96 0-55.04-32t67.84-44.16a149.76 149.76 0 0 0 82.56-23.68zM949.76 384H1024c-15.36-106.88-232.32-128-311.04-128V128L512 288 712.32 448V327.04a488.96 488.96 0 0 1 237.44 56.96z" fill="#666666" ></path></symbol><symbol id="edui-for-tolowercase" viewBox="0 0 1024 1024"><path d="M295.68 128L0 896h113.28l74.24-192h328.96l71.04 192H704L408.32 128z m-53.12 448l92.16-250.88A245.76 245.76 0 0 0 353.28 256a225.92 225.92 0 0 0 16 69.12L461.44 576zM996.48 812.16v-115.84Q998.4 576 865.28 576t-152.32 92.16l67.84 17.92q8.32-55.68 82.56-51.84t64 53.76a224.64 224.64 0 0 1-97.28 19.84q-122.88 12.16-128 101.76T820.48 896a139.52 139.52 0 0 0 114.56-44.16 48.64 48.64 0 0 0 19.2 37.76H1024a102.4 102.4 0 0 1-27.52-77.44zM926.72 768q-6.4 64-95.36 71.68-56.96 0-55.04-32t67.84-44.16a149.76 149.76 0 0 0 82.56-23.68zM586.24 384H512c15.36-106.88 232.32-128 311.04-128V128L1024 288 823.04 448V327.04a488.96 488.96 0 0 0-236.8 56.96z" fill="#666666" ></path></symbol><symbol id="edui-for-insertvideo" viewBox="0 0 1024 1024"><path d="M384 768l256-256-256-256v512z" fill="#666666" ></path><path d="M960 64H64a64 64 0 0 0-64 64v768a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V128a64 64 0 0 0-64-64z m0 832H64V128h896z" fill="#666666" ></path></symbol><symbol id="edui-for-emotion" viewBox="0 0 1024 1024"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m0 960a448 448 0 1 1 448-448 448 448 0 0 1-448 448z" fill="#666666" ></path><path d="M320 384m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#666666" ></path><path d="M704 384m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#666666" ></path><path d="M512 832a256 256 0 0 0 256-256H256a256 256 0 0 0 256 256z" fill="#666666" ></path></symbol><symbol id="edui-for-pasteplain" viewBox="0 0 1024 1024"><path d="M640 256V128H576V64a64 64 0 0 0-64-64H320a64 64 0 0 0-64 64v64H192v128zM320 64h192v64H320z" fill="#666666" ></path><path d="M832 384V160a33.28 33.28 0 0 0-33.92-32H704v64h64v64h-64v64H128V128H33.92a33.28 33.28 0 0 0-33.92 32V896h384v128h640V384z m-384 576V448h512v512z" fill="#666666" ></path><path d="M576 576h320v64H576zM704 640h64v256h-64zM704 192h64v128h-64z" fill="#666666" ></path></symbol><symbol id="edui-for-preview" viewBox="0 0 1024 1024"><path d="M895.909541 256.060626h-191.95477V56.427664A63.984924 63.984924 0 0 0 639.969847 0.120932H137.688197A69.743567 69.743567 0 0 0 64.105535 64.105855v895.78893a69.743567 69.743567 0 0 0 73.582662 63.984923h748.623606A69.743567 69.743567 0 0 0 959.894465 959.894785V313.007208A63.984924 63.984924 0 0 0 895.909541 256.060626z m0 695.516119a8.31804 8.31804 0 0 1-8.31804 8.31804H137.688197a9.597739 9.597739 0 0 1-9.597738-9.597739V72.423895A8.31804 8.31804 0 0 1 136.408499 64.105855h491.404213a11.517286 11.517286 0 0 1 12.157135 10.877437v191.954771A60.145828 60.145828 0 0 0 703.954771 320.045549h180.437484a11.517286 11.517286 0 0 1 12.157136 10.877437v620.653759z" fill="#666666" ></path><path d="M767.939694 850.480566l-173.399143-172.759294a225.86678 225.86678 0 1 0-45.429295 45.429296l173.399142 172.759293zM256.060306 543.992782A159.962309 159.962309 0 1 1 416.022615 703.955091 159.962309 159.962309 0 0 1 256.060306 543.992782z" fill="#666666" ></path></symbol><symbol id="edui-for-print" viewBox="0 0 1024 1024"><path d="M320.00576 448h384v64H320.00576zM320.00576 576h384v64H320.00576z" fill="#666666" ></path><path d="M988.80576 179.2H832.00576V0H192.00576v179.2H35.20576a35.2 35.2 0 0 0-35.2 35.84v443.52h192V704l256 256h384v-301.44h192V346.88a36.48 36.48 0 0 0 0-3.84v-128a35.2 35.2 0 0 0-35.2-35.84zM256.00576 64h512v115.2H256.00576z m640 512h-56.96V455.68H768.00576V896H471.04576v-199.04H256.00576V455.68H187.52576V576H128.00576V384h768z m32-274.56a32.64 32.64 0 1 1 32-32.64 32 32 0 0 1-32 32.64z" fill="#666666" ></path></symbol><symbol id="edui-for-searchreplace" viewBox="0 0 1024 1024"><path d="M855.04 0H0v1024h1024V343.04zM512 128h128v256H512z m256 832H256v-320h512z m192-512v512h-128V576H192v384H64V64h128v384h512V64h64l192 320z" fill="#666666" ></path></symbol><symbol id="edui-for-selectall" viewBox="0 0 1024 1024"><path d="M184.32 113.92L298.24 0h-40.32L144 113.92h40.32zM113.92 144L0 257.92v40.32l113.92-113.92v-40.32zM144 0L0 144v40.32L184.32 0h-40.32zM30.72 0L0 30.72v40.32L71.04 0H30.72zM527.36 113.92L641.28 0h-40.32L487.68 113.92h39.68zM113.92 487.68L0 600.96v40.32l113.92-113.92v-39.68zM113.92 373.76L0 487.68v39.68l113.92-113.28v-40.32zM414.08 113.92L527.36 0h-39.68L373.76 113.92h40.32zM300.16 113.92L414.08 0h-40.32L259.84 113.92h40.32zM113.92 259.84L0 373.76v40.32l113.92-113.92v-40.32zM113.92 835.2L0 948.48v40.32l113.92-113.28v-40.32zM875.52 113.92L988.8 0h-40.32l-113.28 113.92h40.32zM113.92 721.28L0 835.2v40.32l113.92-113.92v-40.32zM761.6 113.92L875.52 0h-40.32l-113.92 113.92h40.32zM113.92 607.36L0 721.28v40.32l113.92-113.92v-40.32zM647.68 113.92L761.6 0h-40.32L607.36 113.92h40.32zM910.08 419.2L1024 305.28v-40.32l-113.92 113.92v40.32zM378.88 910.08L264.96 1024h40.32l113.92-113.92h-40.32zM910.08 305.28L1024 192v-40.32l-113.92 113.28v40.32zM264.96 910.08L151.68 1024H192l113.28-113.92h-40.32zM151.68 910.08L37.76 1024h40.32L192 910.08h-40.32zM910.08 151.68V192L1024 78.08V37.76l-113.92 113.92zM910.08 759.04L1024 645.12v-40.32l-113.92 113.92v40.32zM718.72 910.08L604.8 1024h40.32l113.92-113.92h-40.32zM910.08 645.12L1024 531.2v-40.32l-113.92 113.92v40.32zM604.8 910.08L490.88 1024h40.32l113.92-113.92h-40.32zM490.88 910.08L376.96 1024h40.32l113.92-113.92h-40.32zM910.08 531.2L1024 417.28v-40.32l-113.92 113.92v40.32zM988.16 1024l35.84-35.84v-40.32L947.84 1024h40.32zM874.24 1024L1024 874.24v-40.32L833.92 1024h40.32zM833.92 910.08L720.64 1024h39.68l113.92-113.92h-40.32zM910.08 874.24L1024 760.32v-39.68l-113.92 113.28v40.32zM256 630.4Q263.04 768 442.24 768a223.36 223.36 0 0 0 183.04-70.4 77.44 77.44 0 0 0 30.72 60.8H768a163.84 163.84 0 0 1-44.16-124.8V448Q727.04 256 512 256T269.44 403.2l108.8 28.8q13.44-89.6 133.76-83.2 112-6.4 101.76 86.4a359.68 359.68 0 0 1-156.16 32Q259.2 486.4 256 630.4zM611.84 518.4v44.8q-10.24 105.6-152.32 115.2-91.52 0-88.32-51.2-6.4-60.8 108.8-70.4a240 240 0 0 0 131.84-38.4z" fill="#666666" ></path></symbol><symbol id="edui-for-mergecells" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m0-320H64V64h256z m64-256h256v256H384z m576 896H384V384h576z m0-640h-256V64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-deletecol" viewBox="0 0 1024 1024"><path d="M1024 307.84V0h-256v576h256zM832 256V64h128v192z m0 256V320h128v192zM448 307.84V0H0v576h448zM64 256V64h128v192z m192 0V64h128v192zM64 512V320h128v192z m192 0V320h128v192zM640 704V635.52L570.24 704H640zM593.28 708.48z" fill="#666666" ></path><path d="M640 512v136.32l64-34.56V256H512v352l64 32V512zM576 448V320h64v128z" fill="#666666" ></path><path d="M734.72 1024l96.64-92.8L704 808.96l128-122.88-96-92.16-32 19.84V768H512V608l-32-14.08L384 686.08l128 122.88-127.36 122.24L480.64 1024l127.36-122.24L734.72 1024z" fill="#666666" ></path><path d="M512 704h76.8L512 629.76V704z" fill="#666666" ></path></symbol><symbol id="edui-for-deleterow" viewBox="0 0 1024 1024"><path d="M307.84 0H0v256h576V0zM256 192H64V64h192z m256 0H320V64h192zM307.84 576H0v448h576V576zM256 960H64v-128h192z m0-192H64v-128h192z m256 192H320v-128h192z m0-192H320v-128h192zM716.8 360.32h-68.48l68.48 70.4v-70.4zM708.48 430.72zM520.96 344.96h128l-34.56-35.84H256v219.52h352l32-35.84H520.96zM448 448H316.16V384H448z" fill="#666666" ></path><path d="M1024 288.64l-92.8-96L808.96 320l-122.88-128-92.16 96 19.84 21.12h137.6V528.64H608l-14.08 15.36 92.16 96 122.88-128 122.24 127.36L1024 542.72 901.76 416 1024 288.64z" fill="#666666" ></path><path d="M716.8 492.8V416l-74.24 76.8h74.24z" fill="#666666" ></path></symbol><symbol id="edui-for-attachment" viewBox="0 0 1024 1024"><path d="M972.16 372.48l-520.32 512a222.72 222.72 0 0 1-312.32 0A216.32 216.32 0 0 1 138.88 576l468.48-460.8a148.48 148.48 0 0 1 208 0 144.64 144.64 0 0 1 0 206.08l-467.84 463.36a74.24 74.24 0 0 1-104.32 0 72.32 72.32 0 0 1 0-103.04l416.64-411.52-51.84-51.2L192 630.4a144.64 144.64 0 0 0 0 206.08 148.48 148.48 0 0 0 208 0l468.48-463.36a216.96 216.96 0 0 0 0-308.48A222.72 222.72 0 0 0 555.52 64L64 552.96a291.2 291.2 0 0 0 26.24 384 296.96 296.96 0 0 0 385.28 23.04L1024 424.32l-51.84-51.2z" fill="#666666" ></path></symbol><symbol id="edui-for-music" viewBox="0 0 1024 1024"><path d="M991.140186 0.88755h-7.673343a36.448381 36.448381 0 0 0-15.986133 0L219.969177 135.810504a31.972264 31.972264 0 0 0-28.135593 30.693374 30.053928 30.053928 0 0 0 0 3.197226v616.425251A127.889056 127.889056 0 0 0 127.889056 768.221888a127.889056 127.889056 0 1 0 127.889056 127.889056V384.554719a36.448381 36.448381 0 0 0 17.904468 0L959.167922 260.502334v457.203376a127.889056 127.889056 0 0 0-63.944528-17.904468A127.889056 127.889056 0 1 0 1023.11245 832.166416V32.859814a31.972264 31.972264 0 0 0-31.972264-31.972264z" fill="#666666" ></path></symbol><symbol id="edui-for-gmap" viewBox="0 0 1024 1024"><path d="M543.36 572.16h128v144.64a170.24 170.24 0 0 1-103.68 30.08c-135.68 0-208-89.6-208-236.8s83.84-233.6 206.08-233.6a183.04 183.04 0 0 1 138.24 55.68l56.32-64A270.72 270.72 0 0 0 562.56 192 298.24 298.24 0 0 0 256 512c0 202.24 128 320 304 320A306.56 306.56 0 0 0 768 759.68V492.16H543.36z" fill="#1C7C59" ></path><path d="M896 0H128a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h768a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H192a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h640a64 64 0 0 1 64 64z" fill="#1C7C59" ></path></symbol><symbol id="edui-for-insertframe" viewBox="0 0 1024 1024"><path d="M448 384a256 256 0 1 0 256 256 256 256 0 0 0-256-256z m195.84 170.88a213.76 213.76 0 0 1 0 170.88H547.2a504.32 504.32 0 0 0 0-170.88zM384 640a527.36 527.36 0 0 1 6.4-85.12h115.2A527.36 527.36 0 0 1 512 640a527.36 527.36 0 0 1-6.4 85.12H390.4A527.36 527.36 0 0 1 384 640z m234.88-128H537.6a218.88 218.88 0 0 0-39.68-79.36A213.76 213.76 0 0 1 618.88 512zM448 448c19.2 0 35.84 24.96 48 64h-96c12.16-39.04 28.8-64 48-64z m-49.92-15.36A218.88 218.88 0 0 0 358.4 512H277.12a213.76 213.76 0 0 1 120.96-79.36zM252.16 554.88h96a504.32 504.32 0 0 0 0 170.88h-96a213.76 213.76 0 0 1 0-170.88zM277.12 768H358.4a218.88 218.88 0 0 0 39.68 79.36A213.76 213.76 0 0 1 277.12 768zM448 832c-19.2 0-35.84-24.96-48-64h96c-12.16 39.04-28.8 64-48 64z m49.92 15.36A218.88 218.88 0 0 0 537.6 768h81.28a213.76 213.76 0 0 1-120.96 79.36z" fill="#666666" ></path><path d="M597.76 0H64v1024h896V330.24zM896 355.84V960H128V64h448v256h320z" fill="#666666" ></path></symbol><symbol id="edui-for-pdfformat" viewBox="0 0 1024 1024"><path d="M597.76 0H64v1024h896V330.24zM896 960H128V64h448v291.2h320z" fill="#EF4848" ></path><path d="M213.76 615.68H166.4v133.12h49.28c58.24 0 85.76-21.76 85.76-69.76s-30.72-63.36-87.68-63.36zM486.4 622.08h-32.64v268.8h32.64c77.44 0 119.04-45.44 119.04-135.68S564.48 622.08 486.4 622.08z" fill="#EF4848" ></path><path d="M64 448v576h874.24V448z m175.36 352.64h-54.4v136.96H128V576h109.44c82.56 0 138.24 27.52 138.24 108.8S320 800.64 239.36 800.64z m256 136.96H396.8V576h93.44a159.36 159.36 0 0 1 174.72 179.2 160.64 160.64 0 0 1-171.52 182.4z m411.52-313.6h-158.72v110.72h133.76v48h-133.76v155.52h-56.96V576h214.4z" fill="#EF4848" ></path></symbol><symbol id="edui-for-word" viewBox="0 0 1024 1024"><path d="M718.08 545.92c-12.16 60.16-21.12 117.76-32 177.28h-3.84c-12.8-58.88-23.68-117.12-36.48-177.28L567.68 208H461.44L384 545.92c-12.8 58.88-23.68 117.76-35.84 177.28H345.6c-9.6-58.88-18.56-117.12-29.44-177.28L243.2 208H128L275.84 832h131.84l64-307.2c14.08-58.88 23.68-117.12 34.56-181.76H512c12.16 64 21.76 121.6 34.56 180.48L618.24 832h136.96L896 208h-106.88z" fill="#4972AD" ></path><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#4972AD" ></path></symbol><symbol id="edui-for-excel" viewBox="0 0 1024 1024"><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#60BF6B" ></path><path d="M816.64 128h-155.52L586.24 282.88c-19.2 41.6-40.32 85.12-59.52 128h-5.12c-23.04-43.52-46.72-86.4-67.2-128L369.28 128H208.64L422.4 495.36 192 896h156.16l82.56-161.92c21.76-47.36 44.16-93.44 64-136.96h6.4c25.6 43.52 50.56 90.88 73.6 136.96l96 161.92H832L602.88 512z" fill="#60BF6B" ></path></symbol><symbol id="edui-for-time" viewBox="0 0 1024 1024"><path d="M839.710352 230.607611l21.719276-21.719277 43.438553 43.438553 54.298191-53.659389-127.760449-127.760449-54.936993 54.298191 43.438552 43.438553-21.719276 21.719276A477.82408 477.82408 0 0 0 556.720957 74.739863a76.656269 76.656269 0 0 0-152.673737 0 472.713662 472.713662 0 0 0-87.515907 23.635683l51.104179 79.211478a383.281347 383.281347 0 0 1 112.429196-17.24766 383.281347 383.281347 0 1 1-383.281348 383.281347 383.281347 383.281347 0 0 1 47.271366-184.613849L64.843228 304.708671a472.07486 472.07486 0 0 0-63.880225 240.189645 479.101684 479.101684 0 0 0 958.203369 0 473.352464 473.352464 0 0 0-119.45602-314.290705z" fill="#666666" ></path><path d="M480.064688 255.520898a46.632564 46.632564 0 0 0-46.632564 45.993762v182.05864a76.017467 76.017467 0 0 0 0 122.650031v63.880225a46.632564 46.632564 0 0 0 92.626325 0v-63.880225a76.017467 76.017467 0 0 0 0-122.650031V298.959451A46.632564 46.632564 0 0 0 480.064688 255.520898zM252.651088 0L143.415904 251.049283l274.684966 5.110418-50.465378-77.933874-51.104179-79.850281-63.880225-98.375546z" fill="#666666" ></path></symbol><symbol id="edui-for-snapscreen" viewBox="0 0 1024 1024"><path d="M665.6 392.96L460.8 548.48 256 314.88V704h512V548.48l-102.4-155.52z" fill="#666666" ></path><path d="M1024 832h-128V128H192V0H128v128H0v64h128v704h704v128h64v-128h128zM192 832V192h640v640z" fill="#666666" ></path></symbol><symbol id="edui-for-wordimage" viewBox="0 0 1024 1024"><path d="M988.16 448H419.84a35.84 35.84 0 0 0-35.84 35.84v504.32a35.84 35.84 0 0 0 35.84 35.84h568.96a35.84 35.84 0 0 0 35.84-35.84V483.84a35.84 35.84 0 0 0-36.48-35.84z m-323.84 164.48a80 80 0 1 1-80-81.92 81.28 81.28 0 0 1 80 81.92zM929.28 960H461.44l131.2-205.44 85.12 133.12 177.28-298.24L960 768v163.2a30.72 30.72 0 0 1-30.72 28.8z" fill="#666666" ></path><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h256v-64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64v256h64V64a64 64 0 0 0-64-64z" fill="#4972AD" ></path><path d="M320 554.24L241.28 192H122.88l151.68 640H320V565.76zM858.88 384l43.52-192h-116.48l-40.32 192h113.28zM501.76 384c0-26.88 4.48-40.32 7.04-64H512c0 23.68 7.68 64 7.68 64h97.28l-44.8-192H456.32l-42.88 192z" fill="#4972AD" ></path></symbol><symbol id="edui-for-edittd" viewBox="0 0 1024 1024"><path d="M768 768m-192 0a192 192 0 1 0 384 0 192 192 0 1 0-384 0Z" fill="#666666" ></path><path d="M448 768a320 320 0 0 1 448-293.12V128H128v768h346.88A320 320 0 0 1 448 768z" fill="#666666" ></path><path d="M0 0v1024h576a320 320 0 0 1-64-64H64V64h896v448a320 320 0 0 1 64 64V0z" fill="#666666" ></path></symbol><symbol id="edui-for-lineheight" viewBox="0 0 1024 1024"><path d="M380.8 768H0l190.72 254.72L380.8 768z" fill="#666666" ></path><path d="M512 768l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M512 576l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M512 384l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M512 192l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M2.56 256h380.8L193.28 1.28 2.56 256z" fill="#666666" ></path></symbol><symbol id="edui-for-rowspacingbottom" viewBox="0 0 1024 1024"><path d="M704 768H320l192 256zM672 640H32c-19.2 0-32-12.8-32-32S12.8 576 32 576h640c19.2 0 32 12.8 32 32s-12.8 32-32 32zM864 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h832c19.2 0 32 12.8 32 32s-12.8 32-32 32zM480 256h-448C12.8 256 0 243.2 0 224S12.8 192 32 192h448c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-rowspacingtop" viewBox="0 0 1024 1024"><path d="M320 256h384L512 0zM352 384h640c19.2 0 32 12.8 32 32s-12.8 32-32 32h-640c-19.2 0-32-12.8-32-32s12.8-32 32-32zM160 576h832c19.2 0 32 12.8 32 32s-12.8 32-32 32h-832c-19.2 0-32-12.8-32-32s12.8-32 32-32zM544 768h448c19.2 0 32 12.8 32 32s-12.8 32-32 32h-448c-19.2 0-32-12.8-32-32s12.8-32 32-32zM32 960h960c19.2 0 32 12.8 32 32s-12.8 32-32 32H32c-19.2 0-32-12.8-32-32s12.8-32 32-32z" fill="#666666" ></path></symbol><symbol id="edui-for-scrawl" viewBox="0 0 1024 1024"><path d="M1018.28352 277.12a20.48 20.48 0 0 0-15.36-6.4 68.48 68.48 0 0 0-40.96 23.68l-390.4 389.12a1234.56 1234.56 0 0 0-69.12 105.6l-8.32 14.08 14.08-8.96c3.84 0 90.24-56.96 104.96-71.04l390.4-389.12c16.64-14.08 29.44-41.6 14.72-56.96z m-243.84 120.96a56.96 56.96 0 1 1-56.96-58.88 58.24 58.24 0 0 1 56.96 58.88zM173.48352 603.52a58.88 58.88 0 1 1 56.96-58.88 58.24 58.24 0 0 1-56.96 58.88zM256.68352 398.08a56.96 56.96 0 1 1 56.96 58.88 58.24 58.24 0 0 1-56.96-58.88z m202.88-58.88a56.96 56.96 0 1 1 56.96 58.88 58.24 58.24 0 0 1-56.96-58.88z m442.88 199.04a415.36 415.36 0 0 1-402.56 352.64 335.36 335.36 0 0 1-122.88-23.68c-38.4-16-55.68-34.56-59.52-46.72s-3.84-13.44-5.12-20.48a250.24 250.24 0 0 0-23.04-64 81.28 81.28 0 0 0-72.96-43.52 114.56 114.56 0 0 0-26.24 0 187.52 187.52 0 0 1-42.24 5.12c-28.8 0-77.44-7.68-78.72-60.16-8.32-266.88 206.08-412.16 421.76-437.76a419.2 419.2 0 0 1 48.64 0 500.48 500.48 0 0 1 174.72 30.72c10.88 4.48 16.64 7.04 44.8 21.12a260.48 260.48 0 0 1 73.6 53.76l34.56-64a314.88 314.88 0 0 0-76.8-55.68c-28.8-14.08-36.48-17.92-49.92-23.68A570.24 570.24 0 0 0 539.56352 128a485.12 485.12 0 0 0-56.32 0 592 592 0 0 0-339.2 151.68A462.08 462.08 0 0 0 0.68352 640a122.88 122.88 0 0 0 46.72 97.28 159.36 159.36 0 0 0 99.84 30.72 256 256 0 0 0 57.6-7.04h10.88c13.44 0 19.2 11.52 30.72 57.6 0 7.68 3.84 15.36 5.76 23.04a154.88 154.88 0 0 0 99.2 91.52A403.84 403.84 0 0 0 499.88352 960a460.16 460.16 0 0 0 177.92-35.2A471.04 471.04 0 0 0 821.80352 832a496 496 0 0 0 100.48-135.04 476.8 476.8 0 0 0 48.64-158.72V519.04z" fill="#666666" ></path></symbol><symbol id="edui-for-redo" viewBox="0 0 1024 1024"><path d="M900.608 474.112c-51.2-51.2-260.608-261.632-291.84-292.352a68.096 68.096 0 0 0-91.648 3.072 73.216 73.216 0 0 0-14.336 76.288c12.288 18.432 187.904 199.68 187.904 199.68H169.984A61.952 61.952 0 0 0 102.4 525.312a71.168 71.168 0 0 0 68.096 67.584h517.632l-173.056 172.032a68.096 68.096 0 0 0 0 93.184 65.536 65.536 0 0 0 90.624 7.168c25.088-23.04 256-252.928 297.984-296.448s-3.072-94.72-3.072-94.72z" fill="#666666" ></path></symbol><symbol id="edui-for-undo" viewBox="0 0 1024 1024"><path d="M128.512 476.16c51.2-51.2 260.608-261.632 291.84-292.352a68.096 68.096 0 0 1 91.648 3.072 73.216 73.216 0 0 1 13.824 76.288C512 281.6 338.432 460.8 338.432 460.8h520.192a61.952 61.952 0 0 1 65.536 66.56 71.168 71.168 0 0 1-68.096 67.584H338.432L512 768a68.096 68.096 0 0 1 0 93.184 65.536 65.536 0 0 1-90.624 7.168c-25.088-23.04-256-252.928-297.984-296.448s5.12-95.744 5.12-95.744z" fill="#666666" ></path></symbol><symbol id="edui-for-inserttitle" viewBox="0 0 1024 1024"><path d="M512 516.096v-153.6H460.8v102.4H358.4v51.2H204.8v-51.2H102.4v-102.4H51.2v614.4h921.6v-460.8z m-173.056 409.6h-240.64V757.76h238.592z m0-219.136h-240.64v-139.264h238.592z m297.472 219.136H388.096V757.76h246.272z m0-219.136H388.096v-139.264h246.272z m283.136 219.136h-233.984V757.76h231.936z m0-219.136h-233.984v-139.264h231.936z" fill="#666666" ></path><path d="M512 465.408v51.2h460.8V51.2h-460.8v307.2z m51.2-204.8h153.6v-153.6h51.2v153.6h153.6v51.2h-153.6v153.6h-51.2v-153.6h-153.6z" fill="#1C7C59" ></path><path d="M99.328 108.032h102.4v-51.2h-153.6v153.6h51.2v-102.4zM512.512 104.96v-51.2h-153.6v51.2h102.4v102.4h51.2v-102.4z" fill="#666666" ></path></symbol><symbol id="edui-for-insertparagraphtrue" viewBox="0 0 1024 1024"><path d="M997.12 448H0v576h1024V448zM60.16 960v-256H320v256z m481.92 0H384v-256h256v256z m421.76 0H704v-256h259.84zM448 0H0v64h192v384h64V64h192V0z" fill="#666666" ></path></symbol><symbol id="edui-for-aligntable" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32C12.8 256 0 243.2 0 224S12.8 192 32 192h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 384H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32c-19.2 0-32-12.8-32-32S12.8 576 32 576h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-table" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m320 320H384v-256h256z m0-320H384V384h256z m320 320h-256v-256h256z m0-320h-256V384h256z m0-320H64V64h896z" fill="#666666" ></path></symbol><symbol id="edui-for-tablealignment-left" viewBox="0 0 1024 1024"><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 256l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 563.2l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 870.4l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-tablealignment-center" viewBox="0 0 1024 1024"><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 256l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 563.2l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 870.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-tablealignment-right" viewBox="0 0 1024 1024"><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M358.4 256l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M358.4 563.2l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M358.4 870.4l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-paste" viewBox="0 0 1024 1024"><path d="M832 320V160a32 32 0 0 0-32-32H576V64a64 64 0 0 0-64-64H384a64 64 0 0 0-64 64v64H96a32 32 0 0 0-32 32v640a32 32 0 0 0 32 32H384v192h448l192-192V320zM384 64h128v64H384zM192 192h512v64H192z m640 741.76V832h101.76zM960 768h-192v192H448V384h512z" fill="#666666" ></path></symbol><symbol id="edui-for-map" viewBox="0 0 1024 1024"><path d="M375.424 331.824c-2.432 6.96-7.856 24.704-3.152 40.208 9.232 34.672 39.424 36.24 39.424 36.24h43.264V302.368h-46.4c-20.864 6.24-30.944 22.432-33.136 29.456z m129.072 119.072H397.008c-46.448-9.28-64.896-40.992-67.28-46.368-2.288-5.456-15.504-30.944-8.464-74.256 20.032-64.976 77.28-69.616 77.28-69.616h57.248v-70.368l48.704 0.8v259.808z m200.272-0.768H581.04c-47.92-12.368-50.176-46.496-50.176-46.496V266.816L581.04 266v123.024c3.008 13.024 19.376 15.44 19.376 15.44h50.912V266.768h53.456v183.36h-0.016z" fill="" ></path><path d="M512 1021.45c-11.203 0-21.563-6-27.172-15.688L208.375 527.726c-30.803-53.1-47.11-113.662-47.11-175.084 0-193.047 157.35-350.094 350.75-350.094 193.391 0 350.72 157.047 350.72 350.094 0 61.421-16.298 121.975-47.126 175.115l-276.437 478.007c-5.61 9.687-15.953 15.687-27.172 15.687z m0.016-956.138c-158.788 0-287.985 128.907-287.985 287.329 0 50.375 13.375 100.037 38.663 143.615l249.303 431.1 249.297-431.062c25.297-43.616 38.656-93.281 38.656-143.656 0-158.42-129.172-287.325-287.934-287.325z" fill="" ></path></symbol><symbol id="edui-for-directionalityrtl" viewBox="0 0 1024 1024"><path d="M960 833.92l-384-320 384-320.64v640.64zM64 192V128h448v64H320v640h192v64H64v-64h192V192H64z" fill="#666666" ></path></symbol><symbol id="edui-for-imagecenter" viewBox="0 0 1024 1024"><path d="M0 0h1024v64H0z" fill="#666666" ></path><path d="M128 192l768 0 0 448-768 0 0-448Z" fill="#66BBBF" ></path><path d="M0 768h1024v64H0zM0 960h1024v64H0z" fill="#666666" ></path></symbol><symbol id="edui-for-imagenone" viewBox="0 0 1024 1024"><path d="M52.736 107.008l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M52.736 260.608l409.6 0 0 512-409.6 0 0-512Z" fill="#66BBBF" ></path><path d="M564.736 721.408l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M54.784 875.008l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M564.736 567.808l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-fontborder" viewBox="0 0 1024 1024"><path d="M345.6 832l44.8-153.6h224l44.8 153.6H768L576 192H448L256 832h89.6z m153.6-531.2l83.2 288H416l83.2-288z" fill="#666666" ></path><path d="M896 64H64v896h896V64h-64z m0 832H128V128h768v768z" fill="#666666" ></path></symbol><symbol id="edui-for-edittable" viewBox="0 0 1024 1024"><path d="M993.92 848.64L849.92 704a240 240 0 0 0-320-300.8L512 410.24v2.56a12.16 12.16 0 0 0 0 17.28l134.4 134.4-81.92 80.64L432.64 512a14.08 14.08 0 0 0-23.68 5.12l-4.48 10.24a240 240 0 0 0 300.8 320l144 144a102.4 102.4 0 0 0 72.96 30.08 103.04 103.04 0 0 0 72.96-175.36zM960 960a56.96 56.96 0 0 1-40.32 16.64 56.96 56.96 0 0 1-40.32-16.64l-165.12-165.12-14.08 6.4a192 192 0 0 1-265.6-220.8L555.52 704a14.08 14.08 0 0 0 17.28 0l128-128a14.08 14.08 0 0 0 0-18.56L580.48 434.56A192 192 0 0 1 802.56 704l-6.4 14.08L960 880.64A56.96 56.96 0 0 1 960 960z" fill="#666666" ></path><path d="M832 0H0v832h320V320h512zM256 768H64V576h192z m0-256H64V320h192z m0-256H64V64h192z m256 0H320V64h192z m64 0V64h192v192z" fill="#666666" ></path></symbol><symbol id="edui-for-imageleft" viewBox="0 0 1024 1024"><path d="M50.688 101.376l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M50.688 254.976l409.6 0 0 512-409.6 0 0-512Z" fill="#66BBBF" ></path><path d="M562.688 715.776l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M52.736 869.376l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M562.688 562.176l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M562.688 408.576l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M562.688 254.976l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-imageright" viewBox="0 0 1024 1024"><path d="M0 0h1024v64H0z" fill="#666666" ></path><path d="M512 192l512 0 0 640-512 0 0-640Z" fill="#66BBBF" ></path><path d="M0 768h448v64H0zM0 960h1024v64H0zM0 576h448v64H0zM0 384h448v64H0zM0 192h448v64H0z" fill="#666666" ></path></symbol><symbol id="edui-for-insertcol" viewBox="0 0 1024 1024"><path d="M256 256L0 512l256 256V256zM1024 1024V0H384v1024zM768 64h192v256h-192z m0 320h192v256h-192z m0 320h192v256h-192zM448 64h192v256H448z m0 320h192v256H448z m0 320h192v256H448z" fill="#666666" ></path></symbol><symbol id="edui-for-insertcolnext" viewBox="0 0 1024 1024"><path d="M768 768l256-256-256-256v512zM0 0v1024h640V0z m256 960H64v-256h192z m0-320H64V384h192z m0-320H64V64h192z m320 640H384v-256h192z m0-320H384V384h192z m0-320H384V64h192z" fill="#666666" ></path></symbol><symbol id="edui-for-insertorderedlist" viewBox="0 0 1024 1024"><path d="M319.955606 63.991121l703.902334 0 0 127.982243-703.902334 0 0-127.982243Z" fill="#666666" ></path><path d="M319.955606 447.937849l703.902334 0 0 127.982242-703.902334 0 0-127.982242Z" fill="#666666" ></path><path d="M319.955606 831.884576l703.902334 0 0 127.982242-703.902334 0 0-127.982242Z" fill="#666666" ></path><path d="M191.973364 0v255.964485H63.991121V0zM0 639.911212v-30.715738C0 505.529858 159.977803 467.775096 159.977803 422.3414c0-17.917514-10.878491-28.156093-33.275383-28.156093a114.544107 114.544107 0 0 0-74.229701 37.11485l-46.713518-54.392453a167.656738 167.656738 0 0 1 127.982242-56.952098C212.450522 319.955606 255.964485 362.189746 255.964485 417.22211c0 78.069168-95.346771 98.546327-142.7002 147.179579H255.964485V639.911212zM127.982242 1023.85794a165.737004 165.737004 0 0 1-127.982242-52.47272l48.633252-49.273163a106.865172 106.865172 0 0 0 69.750322 30.075827c28.156093 0 41.594229-14.078047 41.594229-33.275383 0-17.277603-12.158313-26.23636-36.474939-26.23636h-24.316626v-52.472719h24.956537c23.036804 0 36.474939-6.399112 36.474939-26.876271 0-19.837248-12.798224-31.355649-38.394672-31.35565a85.748102 85.748102 0 0 0-63.991122 31.35565l-47.993341-48.633252a158.058069 158.058069 0 0 1 127.982243-55.032365C211.1707 703.902334 255.964485 745.496562 255.964485 792.210081v5.11929a63.991121 63.991121 0 0 1-67.830589 63.991121c50.552986 7.039023 70.390233 33.275383 70.390234 67.190677v3.839467C255.964485 985.463267 204.131677 1023.85794 127.982242 1023.85794z" fill="#666666" ></path></symbol><symbol id="edui-for-insertparagraphbeforetable" viewBox="0 0 1024 1024"><path d="M256 384v640h768V384z m256 576H320V448h192z m448 0H576v-128h384z m0-192H576v-128h384z m0-192H576V448h384z" fill="#666666" ></path><path d="M384 576h64v256H384zM0 0v64h128v384h64V64h128V0H0z" fill="#666666" ></path></symbol><symbol id="edui-for-insertrow" viewBox="0 0 1024 1024"><path d="M768 256L512 0 256 256h512zM0 1024h1024V384H0z m960-256v192h-256v-192z m-320 0v192H384v-192z m-320 0v192H64v-192z m640-320v192h-256V448z m-320 0v192H384V448zM320 448v192H64V448z" fill="#666666" ></path></symbol><symbol id="edui-for-insertrownext" viewBox="0 0 1024 1024"><path d="M256 768l256 256 256-256H256zM1024 0H0v640h1024zM64 256V64h256v192z m320 0V64h256v192z m320 0V64h256v192zM64 576V384h256v192z m320 0V384h256v192z m320 0V384h256v192z" fill="#666666" ></path></symbol><symbol id="edui-for-insertunorderedlist" viewBox="0 0 1024 1024"><path d="M960 192H256c-38.4 0-64-25.6-64-64s25.6-64 64-64h704c38.4 0 64 25.6 64 64s-25.6 64-64 64zM64 192c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64zM960 576H256c-38.4 0-64-25.6-64-64s25.6-64 64-64h704c38.4 0 64 25.6 64 64s-25.6 64-64 64zM64 576c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64zM960 960H256c-38.4 0-64-25.6-64-64s25.6-64 64-64h704c38.4 0 64 25.6 64 64s-25.6 64-64 64zM64 960c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-mergeright" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m384 64h256v256H384z m0 384h320V384l192 128-192 128V576H384z m-64 512H64v-256h256z m0-320H64V384h256z m0-320H64V64h256z m320 640H384v-256h256z m320 0h-256v-256h256z m0-640h-256V64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-mergedown" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m0-320H64V64h256z m192 576l-128-192h64V384h128v320h64z m128-576H384V64h256z m320 640h-256v-256h256z m0-320h-256V384h256z m0-320h-256V64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-inserttable" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m320 320H384v-256h256z m0-320H384V384h256z m320 320h-256v-256h256z m0-320h-256V384h256z m0-320H64V64h896z" fill="#666666" ></path></symbol><symbol id="edui-for-pagebreak" viewBox="0 0 1024 1024"><path d="M384 960h512v64H384zM0 320v384l256-192-256-192zM320 128h576v64H320zM384 832h256v64H384z" fill="#666666" ></path><path d="M192 704v320h64v-256h704v256h64v-320H192zM1022.72 0H960v256H256V0H192v320h832V0h-1.28z" fill="#666666" ></path></symbol><symbol id="edui-for-source" viewBox="0 0 1024 1024"><path d="M170.88 512H56.96V384H0v320h56.96V576h113.92v128h56.96V384h-56.96v128zM284.16 448h56.96v256h56.96V448h56.96V384H284.16v64zM738.56 385.28l-84.48 250.24L569.6 384l-2.56 1.28H512v316.8h56.96V561.92l47.36 140.8h72.96l2.56 1.28 48-140.8v139.52h56.32V385.92h-55.04l-2.56-0.64zM910.08 640V384h-56.96v320H1024v-64h-113.92z" fill="#666666" ></path></symbol><symbol id="edui-for-splittorows" viewBox="0 0 1024 1024"><path d="M0 0h1024v64H0z" fill="#666666" ></path><path d="M960 0v320h-128V0h-64v320H256V0H192v320H64V0H0v1024h1024V0z m-192 384v256H256V384zM64 384h128v256H64z m0 576v-256h128v256z m192 0v-256h512v256z m704 0h-128v-256h128z m0-320h-128V384h128z" fill="#666666" ></path></symbol><symbol id="edui-for-splittocols" viewBox="0 0 1024 1024"><path d="M1024 0H0v1024h1024z m-64 384v256h-128V384z m0-320v256h-128V64zM64 320V64h128v256z m0 320V384h128v256z m0 320v-256h128v256z m192 0V64h128v896z m192 0V64h128v896z m192 0V64h128v896z m192 0v-256h128v256z" fill="#666666" ></path></symbol><symbol id="edui-for-splittocells" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64V384h256z m320 0H384v-256h256z m0-320H384V384h256z m320 320h-256v-256h256z m0-320h-256V384h256z m0-320H384V64h576z" fill="#666666" ></path></symbol><symbol id="edui-for-arrow" viewBox="0 0 1024 1024"><path d="M513.024 665.6l204.8-204.8h-409.6l204.8 204.8z" fill="" ></path></symbol><symbol id="edui-for-aligntd" viewBox="0 0 1024 1024"><path d="M256.061265 767.939055l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M256.061265 575.985004l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M256.061265 384.030953l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M256.061265 192.076902l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M863.91576 1023.877789h-703.83152A91.498098 91.498098 0 0 1 64.107214 938.77816V85.22248A91.498098 91.498098 0 0 1 160.08424 0.122851h703.83152A91.498098 91.498098 0 0 1 959.892786 85.22248v853.55568A91.498098 91.498098 0 0 1 863.91576 1023.877789zM160.08424 64.107534a30.072801 30.072801 0 0 0-31.992342 28.153261v839.47905a30.072801 30.072801 0 0 0 31.992342 28.153261h703.83152a30.072801 30.072801 0 0 0 31.992342-28.153261V92.260795a30.072801 30.072801 0 0 0-31.992342-28.153261z" fill="#666666" ></path></symbol><symbol id="edui-for-autotypeset" viewBox="0 0 1024 1024"><path d="M192 192l384 0 0 320-384 0 0-320Z" fill="#66BBBF" ></path><path d="M640 192l192 0 0 64-192 0 0-64Z" fill="#666666" ></path><path d="M640 384l192 0 0 64-192 0 0-64Z" fill="#666666" ></path><path d="M192 576l640 0 0 64-640 0 0-64Z" fill="#666666" ></path><path d="M192 768l640 0 0 64-640 0 0-64Z" fill="#666666" ></path><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-charts" viewBox="0 0 1024 1024"><path d="M0 64v896h1024V64z m960 832H64V128h896z" fill="#666666" ></path><path d="M704 256h128v512h-128zM448 576h128v192H448zM192 384h128v384H192z" fill="#666666" ></path></symbol><symbol id="edui-for-closeerror" viewBox="0 0 1024 1024"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m284.16 670.08l-128 128L512 640l-158.08 156.16-128-128L384 512 227.84 353.92l128-128L512 384l158.08-158.08 128 128L640 512z" fill="#EF4848" ></path></symbol><symbol id="edui-for-copy" viewBox="0 0 1024 1024"><path d="M256.060306 384.030473l511.879388 0 0 63.984923-511.879388 0 0-63.984923Z" fill="#666666" ></path><path d="M256.060306 575.985243l511.879388 0 0 63.984924-511.879388 0 0-63.984924Z" fill="#666666" ></path><path d="M256.060306 767.940014l511.879388 0 0 63.984924-511.879388 0 0-63.984924Z" fill="#666666" ></path><path d="M256.060306 192.075702l255.939694 0 0 63.984924-255.939694 0 0-63.984924Z" fill="#666666" ></path><path d="M895.909541 256.060626h-191.95477V56.427664A63.984924 63.984924 0 0 0 639.969847 0.120932H137.688197A69.743567 69.743567 0 0 0 64.105535 64.105855v895.78893a69.743567 69.743567 0 0 0 73.582662 63.984923h748.623606A69.743567 69.743567 0 0 0 959.894465 959.894785V313.007208A63.984924 63.984924 0 0 0 895.909541 256.060626z m0 695.516119a8.31804 8.31804 0 0 1-8.31804 8.31804H137.688197a9.597739 9.597739 0 0 1-9.597738-9.597739V72.423895A8.31804 8.31804 0 0 1 136.408499 64.105855h491.404213a11.517286 11.517286 0 0 1 12.157135 10.877437v191.954771A60.145828 60.145828 0 0 0 703.954771 320.045549h180.437484a11.517286 11.517286 0 0 1 12.157136 10.877437v620.653759z" fill="#666666" ></path></symbol><symbol id="edui-for-date" viewBox="0 0 1024 1024"><path d="M896 128v64h64v704H64V192h64V128H0v832h1024V128h-128z" fill="#666666" ></path><path d="M832 64h-192v255.36L832 320V64z" fill="#EF4848" ></path><path d="M576 704h256v64H576zM576 512h256v64H576zM448 128h128v64H448zM192 704h256v64H192zM192 512h256v64H192z" fill="#666666" ></path><path d="M384 64H192v256l192-0.64V64z" fill="#EF4848" ></path></symbol><symbol id="edui-for-deletetable" viewBox="0 0 1024 1024"><path d="M576 0v448h448V0z m427.52 337.28l-90.24 90.24-113.28-113.28-113.28 113.28-90.24-90.24 113.28-113.28-113.28-113.28L686.72 20.48l113.28 113.28L913.28 20.48l90.88 90.88-113.92 112.64z" fill="#EF4848" ></path><path d="M960 640h-256V448h-64v192H384V384h192V320H64V64h512V0H0v1024h1024V448h-64zM320 960H64v-256h256z m0-320H64V384h256z m320 320H384v-256h256z m320 0h-256v-256h256z" fill="#666666" ></path></symbol><symbol id="edui-for-directionalityltr" viewBox="0 0 1024 1024"><path d="M64 832l384-320-384-320v640zM960 192V128H512v64h192v640H512v64h448v-64h-192V192h192z" fill="#666666" ></path></symbol><symbol id="edui-for-arrowright" viewBox="0 0 1024 1024"><path d="M615.424 512l-204.8-204.8v409.6l204.8-204.8z" fill="" ></path></symbol><symbol id="edui-for-tableleft" viewBox="0 0 1024 1024"><path d="M960 64v896H64V64h896m64-64H0v1024h1024V0z" fill="" ></path><path d="M192 192h640v64H192zM192 384h640v64H192zM192 576h256v64H192z" fill="" ></path></symbol><symbol id="edui-for-tableright" viewBox="0 0 1024 1024"><path d="M960 64v896H64V64h896m64-64H0v1024h1024V0z" fill="" ></path><path d="M188.8 191.36h640v64h-640zM188.8 383.36h640v64h-640zM576 575.36h256v64H576z" fill="" ></path></symbol><symbol id="edui-for-tablecenter" viewBox="0 0 1024 1024"><path d="M960 64v896H64V64h896m64-64H0v1024h1024V0z" fill="" ></path><path d="M188.8 192.64h640v64h-640zM188.8 384.64h640v64h-640zM383.36 576.64h256v64h-256z" fill="" ></path></symbol><symbol id="edui-for-videoleft" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 704l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 608l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 512l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 416l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 320l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M256 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M640 320H128a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L544 448l-162.24 208.64L304 563.2 186.56 704H160a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-videocenter" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 704l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 608l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 512l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 416l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 320l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 608l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 704l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 512l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 416l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 320l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M384 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M768 320H256a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L672 448l-162.24 208.64-77.76-93.44L314.56 704H288a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-videonone" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 704l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 608l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M256 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M640 320H128a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L544 448l-162.24 208.64L304 563.2 186.56 704H160a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-videoright" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 704l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 608l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 512l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 416l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 320l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M512 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M896 320H384a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L800 448l-162.24 208.64-77.76-93.44-117.44 140.8H416a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-template" viewBox="0 0 1024 1024"><path d="M0 64v896h1024V64z m960 832H64V128h896z" fill="#666666" ></path><path d="M192 256h320v192H192zM640 256h192v512h-192zM192 576h320v192H192z" fill="#666666" ></path></symbol><symbol id="edui-for-addfile" viewBox="0 0 1024 1024"><path d="M1024 480H544V0h-64v480H0v64h480v480h64V544h480v-64z" fill="#E5E5E5" ></path></symbol><symbol id="edui-for-selected" viewBox="0 0 1024 1024"><path d="M914.24 617.28a32 32 0 0 0-45.12 0l-221.44 221.12-112.96-112.96a32 32 0 1 0-45.12 45.12l135.68 135.68a32 32 0 0 0 45.44 0l243.52-243.52a32 32 0 0 0 0-45.44z" fill="#FFFFFF" ></path><path d="M0 1024h1024V0z m914.24-361.28L672 906.24a32 32 0 0 1-45.44 0l-135.68-135.68a32 32 0 1 1 45.12-45.12l112.96 112.96 221.12-221.12a32 32 0 1 1 45.12 45.12z" fill="#1094FA" ></path></symbol><symbol id="edui-for-pickarea" viewBox="0 0 1024 1024"><path d="M977.454545 93.090909h-46.545454v791.272727a46.545455 46.545455 0 0 1-46.545455 46.545455H93.090909v46.545454a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V139.636364a46.545455 46.545455 0 0 0-46.545455-46.545455z" fill="#E5E5E5" ></path><path d="M46.545455 46.545455l837.818181 0 0 837.818181-837.818181 0 0-837.818181Z" fill="#FFFFFF" ></path><path d="M884.363636 0H46.545455a46.545455 46.545455 0 0 0-46.545455 46.545455v837.818181a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V46.545455a46.545455 46.545455 0 0 0-46.545455-46.545455z m0 837.818182a46.545455 46.545455 0 0 1-46.545454 46.545454H93.090909a46.545455 46.545455 0 0 1-46.545454-46.545454V93.090909a46.545455 46.545455 0 0 1 46.545454-46.545454h744.727273a46.545455 46.545455 0 0 1 46.545454 46.545454z" fill="#CCCCCC" ></path></symbol><symbol id="edui-for-overlay" viewBox="0 0 1024 1024"><path d="M977.454545 93.090909h-46.545454v791.272727a46.545455 46.545455 0 0 1-46.545455 46.545455H93.090909v46.545454a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V139.636364a46.545455 46.545455 0 0 0-46.545455-46.545455z" fill="#E3F6FF" ></path><path d="M46.545455 46.545455l837.818181 0 0 837.818181-837.818181 0 0-837.818181Z" fill="#E3F6FF" ></path><path d="M884.363636 0H46.545455a46.545455 46.545455 0 0 0-46.545455 46.545455v837.818181a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V46.545455a46.545455 46.545455 0 0 0-46.545455-46.545455z m0 837.818182a46.545455 46.545455 0 0 1-46.545454 46.545454H93.090909a46.545455 46.545455 0 0 1-46.545454-46.545454V93.090909a46.545455 46.545455 0 0 1 46.545454-46.545454h744.727273a46.545455 46.545455 0 0 1 46.545454 46.545454z" fill="#45A7EF" ></path></symbol><symbol id="edui-for-preitem" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M175.542857 131.657143h497.371429v58.514286H175.542857zM175.542857 512h438.857143v29.257143H175.542857zM175.542857 394.971429h906.971429v29.257142H175.542857zM175.542857 277.942857h234.057143v29.257143H175.542857zM175.542857 629.028571h1111.771429v29.257143H175.542857zM175.542857 746.057143h292.571429v29.257143H175.542857zM175.542857 863.085714h760.685714v29.257143H175.542857z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem1" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M117.028571 175.542857h351.085715v29.257143H117.028571z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem2" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M175.542857 117.028571h497.371429v58.514286H175.542857zM848.457143 555.885714h438.857143v29.257143H848.457143zM848.457143 438.857143h438.857143v29.257143H848.457143zM848.457143 321.828571h438.857143v29.257143H848.457143zM175.542857 672.914286h1111.771429v29.257143H175.542857zM175.542857 789.942857h702.171429v29.257143H175.542857zM175.542857 906.971429h702.171429v29.257142H175.542857zM731.428571 351.085714v204.8H204.8V351.085714h526.628571m29.257143-29.257143H175.542857v263.314286h585.142857V321.828571zM1258.057143 789.942857v117.028572H994.742857v-117.028572h263.314286m29.257143-29.257143H965.485714v175.542857h321.828572V760.685714z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem3" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M482.742857 175.542857h497.371429v58.514286H482.742857zM643.657143 292.571429h175.542857v29.257142H643.657143zM175.542857 468.114286h1111.771429v29.257143H175.542857zM175.542857 585.142857h1111.771429v29.257143H175.542857zM175.542857 702.171429h1111.771429v29.257142H175.542857zM175.542857 819.2h1111.771429v29.257143H175.542857z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem4" viewBox="0 0 1462 1024"><path d="M1258.057143 263.314286v204.8H204.8V263.314286h1053.257143m29.257143-29.257143H175.542857v263.314286h1111.771429V234.057143z" fill="#666666" ></path><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M175.542857 117.028571h497.371429v58.514286H175.542857zM175.542857 555.885714h351.085714v29.257143H175.542857zM175.542857 672.914286h1111.771429v29.257143H175.542857zM175.542857 789.942857h702.171429v29.257143H175.542857zM175.542857 906.971429h1111.771429v29.257142H175.542857z" fill="#666666" ></path></symbol></svg>';
  29390. var script = function () {
  29391. var scripts = document.getElementsByTagName("script");
  29392. return scripts[scripts.length - 1]
  29393. }();
  29394. var shouldInjectCss = script.getAttribute("data-injectcss");
  29395. var ready = function (fn) {
  29396. if (document.addEventListener) {
  29397. if (~["complete", "loaded", "interactive"].indexOf(document.readyState)) {
  29398. setTimeout(fn, 0)
  29399. } else {
  29400. var loadFn = function () {
  29401. document.removeEventListener("DOMContentLoaded", loadFn, false);
  29402. fn()
  29403. };
  29404. document.addEventListener("DOMContentLoaded", loadFn, false)
  29405. }
  29406. } else if (document.attachEvent) {
  29407. IEContentLoaded(window, fn)
  29408. }
  29409. function IEContentLoaded(w, fn) {
  29410. var d = w.document, done = false, init = function () {
  29411. if (!done) {
  29412. done = true;
  29413. fn()
  29414. }
  29415. };
  29416. var polling = function () {
  29417. try {
  29418. d.documentElement.doScroll("left")
  29419. } catch (e) {
  29420. setTimeout(polling, 50);
  29421. return
  29422. }
  29423. init()
  29424. };
  29425. polling();
  29426. d.onreadystatechange = function () {
  29427. if (d.readyState == "complete") {
  29428. d.onreadystatechange = null;
  29429. init()
  29430. }
  29431. }
  29432. }
  29433. };
  29434. var before = function (el, target) {
  29435. target.parentNode.insertBefore(el, target)
  29436. };
  29437. var prepend = function (el, target) {
  29438. if (target.firstChild) {
  29439. before(el, target.firstChild)
  29440. } else {
  29441. target.appendChild(el)
  29442. }
  29443. };
  29444. function appendSvg() {
  29445. var div, svg;
  29446. div = document.createElement("div");
  29447. div.innerHTML = svgSprite;
  29448. svgSprite = null;
  29449. svg = div.getElementsByTagName("svg")[0];
  29450. if (svg) {
  29451. svg.setAttribute("aria-hidden", "true");
  29452. svg.style.position = "absolute";
  29453. svg.style.width = 0;
  29454. svg.style.height = 0;
  29455. svg.style.overflow = "hidden";
  29456. prepend(svg, document.body)
  29457. }
  29458. }
  29459. if (shouldInjectCss && !window.__iconfont__svg__cssinject__) {
  29460. window.__iconfont__svg__cssinject__ = true;
  29461. try {
  29462. document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")
  29463. } catch (e) {
  29464. console && console.log(e)
  29465. }
  29466. }
  29467. ready(appendSvg)
  29468. })(window)
  29469. // adapter/editorui.js
  29470. //ui跟编辑器的适配層
  29471. //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
  29472. //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据neditor.config中的toolbars找到相应的进行实例化
  29473. ;(function () {
  29474. var utils = baidu.editor.utils;
  29475. var editorui = baidu.editor.ui;
  29476. var _Dialog = editorui.Dialog;
  29477. editorui.buttons = {};
  29478. editorui.Dialog = function (options) {
  29479. var dialog = new _Dialog(options);
  29480. dialog.addListener("hide", function () {
  29481. if (dialog.editor) {
  29482. var editor = dialog.editor;
  29483. try {
  29484. if (browser.gecko) {
  29485. var y = editor.window.scrollY,
  29486. x = editor.window.scrollX;
  29487. editor.body.focus();
  29488. editor.window.scrollTo(x, y);
  29489. } else {
  29490. editor.focus();
  29491. }
  29492. } catch (ex) {
  29493. }
  29494. }
  29495. });
  29496. return dialog;
  29497. };
  29498. var iframeUrlMap = {
  29499. anchor: "~/dialogs/anchor/anchor.html",
  29500. insertimage: "~/dialogs/image/image.html",
  29501. link: "~/dialogs/link/link.html",
  29502. spechars: "~/dialogs/spechars/spechars.html",
  29503. searchreplace: "~/dialogs/searchreplace/searchreplace.html",
  29504. map: "~/dialogs/map/map.html",
  29505. gmap: "~/dialogs/gmap/gmap.html",
  29506. insertvideo: "~/dialogs/video/video.html",
  29507. help: "~/dialogs/help/help.html",
  29508. preview: "~/dialogs/preview/preview.html",
  29509. emotion: "~/dialogs/emotion/emotion.html",
  29510. wordimage: "~/dialogs/wordimage/wordimage.html",
  29511. attachment: "~/dialogs/attachment/attachment.html",
  29512. insertframe: "~/dialogs/insertframe/insertframe.html",
  29513. edittip: "~/dialogs/table/edittip.html",
  29514. edittable: "~/dialogs/table/edittable.html",
  29515. edittd: "~/dialogs/table/edittd.html",
  29516. webapp: "~/dialogs/webapp/webapp.html",
  29517. snapscreen: "~/dialogs/snapscreen/snapscreen.html",
  29518. scrawl: "~/dialogs/scrawl/scrawl.html",
  29519. music: "~/dialogs/music/music.html",
  29520. template: "~/dialogs/template/template.html",
  29521. background: "~/dialogs/background/background.html",
  29522. charts: "~/dialogs/charts/charts.html"
  29523. };
  29524. //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  29525. var btnCmds = [
  29526. "undo",
  29527. "redo",
  29528. "formatmatch",
  29529. "bold",
  29530. "italic",
  29531. "underline",
  29532. "fontborder",
  29533. "touppercase",
  29534. "tolowercase",
  29535. "strikethrough",
  29536. "subscript",
  29537. "superscript",
  29538. "source",
  29539. "indent",
  29540. "outdent",
  29541. "blockquote",
  29542. "pasteplain",
  29543. "pagebreak",
  29544. "selectall",
  29545. "print",
  29546. "horizontal",
  29547. "removeformat",
  29548. "time",
  29549. "date",
  29550. "unlink",
  29551. "insertparagraphbeforetable",
  29552. "insertrow",
  29553. "insertcol",
  29554. "mergeright",
  29555. "mergedown",
  29556. "deleterow",
  29557. "deletecol",
  29558. "splittorows",
  29559. "splittocols",
  29560. "splittocells",
  29561. "mergecells",
  29562. "deletetable",
  29563. "drafts"
  29564. ];
  29565. for (var i = 0, ci; (ci = btnCmds[i++]);) {
  29566. ci = ci.toLowerCase();
  29567. editorui[ci] = (function (cmd) {
  29568. return function (editor) {
  29569. var ui = new editorui.Button({
  29570. className: "edui-for-" + cmd,
  29571. title:
  29572. editor.options.labelMap[cmd] ||
  29573. editor.getLang("labelMap." + cmd) ||
  29574. "",
  29575. onclick: function () {
  29576. editor.execCommand(cmd);
  29577. },
  29578. theme: editor.options.theme,
  29579. showText: false
  29580. });
  29581. editorui.buttons[cmd] = ui;
  29582. editor.addListener("selectionchange", function (
  29583. type,
  29584. causeByUi,
  29585. uiReady
  29586. ) {
  29587. var state = editor.queryCommandState(cmd);
  29588. if (state == -1) {
  29589. ui.setDisabled(true);
  29590. ui.setChecked(false);
  29591. } else {
  29592. if (!uiReady) {
  29593. ui.setDisabled(false);
  29594. ui.setChecked(state);
  29595. }
  29596. }
  29597. });
  29598. return ui;
  29599. };
  29600. })(ci);
  29601. }
  29602. //清除文档
  29603. editorui.cleardoc = function (editor) {
  29604. var ui = new editorui.Button({
  29605. className: "edui-for-cleardoc",
  29606. title:
  29607. editor.options.labelMap.cleardoc ||
  29608. editor.getLang("labelMap.cleardoc") ||
  29609. "",
  29610. theme: editor.options.theme,
  29611. onclick: function () {
  29612. if (confirm(editor.getLang("confirmClear"))) {
  29613. editor.execCommand("cleardoc");
  29614. }
  29615. }
  29616. });
  29617. editorui.buttons["cleardoc"] = ui;
  29618. editor.addListener("selectionchange", function () {
  29619. ui.setDisabled(editor.queryCommandState("cleardoc") == -1);
  29620. });
  29621. return ui;
  29622. };
  29623. //排版,图片排版,文字方向
  29624. var typeset = {
  29625. justify: ["left", "right", "center", "justify"],
  29626. imagefloat: ["none", "left", "center", "right"],
  29627. directionality: ["ltr", "rtl"]
  29628. };
  29629. for (var p in typeset) {
  29630. (function (cmd, val) {
  29631. for (var i = 0, ci; (ci = val[i++]);) {
  29632. (function (cmd2) {
  29633. editorui[cmd.replace("float", "") + cmd2] = function (editor) {
  29634. var ui = new editorui.Button({
  29635. className: "edui-for-" + cmd.replace("float", "") + cmd2,
  29636. title:
  29637. editor.options.labelMap[cmd.replace("float", "") + cmd2] ||
  29638. editor.getLang(
  29639. "labelMap." + cmd.replace("float", "") + cmd2
  29640. ) ||
  29641. "",
  29642. theme: editor.options.theme,
  29643. onclick: function () {
  29644. editor.execCommand(cmd, cmd2);
  29645. }
  29646. });
  29647. editorui.buttons[cmd] = ui;
  29648. editor.addListener("selectionchange", function (
  29649. type,
  29650. causeByUi,
  29651. uiReady
  29652. ) {
  29653. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  29654. ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady);
  29655. });
  29656. return ui;
  29657. };
  29658. })(ci);
  29659. }
  29660. })(p, typeset[p]);
  29661. }
  29662. //字体颜色和背景颜色
  29663. for (var i = 0, ci; (ci = ["backcolor", "forecolor"][i++]);) {
  29664. editorui[ci] = (function (cmd) {
  29665. return function (editor) {
  29666. var ui = new editorui.ColorButton({
  29667. className: "edui-for-" + cmd,
  29668. color: "default",
  29669. title:
  29670. editor.options.labelMap[cmd] ||
  29671. editor.getLang("labelMap." + cmd) ||
  29672. "",
  29673. editor: editor,
  29674. onpickcolor: function (t, color) {
  29675. editor.execCommand(cmd, color);
  29676. },
  29677. onpicknocolor: function () {
  29678. editor.execCommand(cmd, "default");
  29679. this.setColor("transparent");
  29680. this.color = "default";
  29681. },
  29682. onbuttonclick: function () {
  29683. editor.execCommand(cmd, this.color);
  29684. }
  29685. });
  29686. editorui.buttons[cmd] = ui;
  29687. editor.addListener("selectionchange", function () {
  29688. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  29689. });
  29690. return ui;
  29691. };
  29692. })(ci);
  29693. }
  29694. var dialogBtns = {
  29695. noOk: ["searchreplace", "help", "spechars", "webapp", "preview"],
  29696. ok: [
  29697. "attachment",
  29698. "anchor",
  29699. "link",
  29700. "insertimage",
  29701. "map",
  29702. "gmap",
  29703. "insertframe",
  29704. "wordimage",
  29705. "insertvideo",
  29706. "insertframe",
  29707. "edittip",
  29708. "edittable",
  29709. "edittd",
  29710. "scrawl",
  29711. "template",
  29712. "music",
  29713. "background",
  29714. "charts"
  29715. ]
  29716. };
  29717. for (var p in dialogBtns) {
  29718. (function (type, vals) {
  29719. for (var i = 0, ci; (ci = vals[i++]);) {
  29720. //todo opera下存在问题
  29721. if (browser.opera && ci === "searchreplace") {
  29722. continue;
  29723. }
  29724. (function (cmd) {
  29725. editorui[cmd] = function (editor, iframeUrl, title) {
  29726. iframeUrl =
  29727. iframeUrl ||
  29728. (editor.options.iframeUrlMap || {})[cmd] ||
  29729. iframeUrlMap[cmd];
  29730. title =
  29731. editor.options.labelMap[cmd] ||
  29732. editor.getLang("labelMap." + cmd) ||
  29733. "";
  29734. var dialog;
  29735. //没有iframeUrl不创建dialog
  29736. if (iframeUrl) {
  29737. dialog = new editorui.Dialog(
  29738. utils.extend(
  29739. {
  29740. iframeUrl: editor.ui.mapUrl(iframeUrl),
  29741. editor: editor,
  29742. className: "edui-for-" + cmd,
  29743. title: title,
  29744. holdScroll: cmd === "insertimage",
  29745. fullscreen: /charts|preview/.test(cmd),
  29746. closeDialog: editor.getLang("closeDialog")
  29747. },
  29748. type == "ok"
  29749. ? {
  29750. buttons: [
  29751. {
  29752. className: "edui-okbutton",
  29753. label: editor.getLang("ok"),
  29754. editor: editor,
  29755. onclick: function () {
  29756. dialog.close(true);
  29757. }
  29758. },
  29759. {
  29760. className: "edui-cancelbutton",
  29761. label: editor.getLang("cancel"),
  29762. editor: editor,
  29763. onclick: function () {
  29764. dialog.close(false);
  29765. }
  29766. }
  29767. ]
  29768. }
  29769. : {}
  29770. )
  29771. );
  29772. editor.ui._dialogs[cmd + "Dialog"] = dialog;
  29773. }
  29774. var ui = new editorui.Button({
  29775. className: "edui-for-" + cmd,
  29776. title: title,
  29777. onclick: function () {
  29778. if (dialog) {
  29779. switch (cmd) {
  29780. case "wordimage":
  29781. var images = editor.execCommand("wordimage");
  29782. if (images && images.length) {
  29783. dialog.render();
  29784. dialog.open();
  29785. }
  29786. break;
  29787. case "scrawl":
  29788. if (editor.queryCommandState("scrawl") != -1) {
  29789. dialog.render();
  29790. dialog.open();
  29791. }
  29792. break;
  29793. default:
  29794. dialog.render();
  29795. dialog.open();
  29796. }
  29797. }
  29798. },
  29799. theme: editor.options.theme,
  29800. disabled:
  29801. (cmd == "scrawl" && editor.queryCommandState("scrawl") == -1) ||
  29802. cmd == "charts"
  29803. });
  29804. editorui.buttons[cmd] = ui;
  29805. editor.addListener("selectionchange", function () {
  29806. //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
  29807. var unNeedCheckState = {edittable: 1};
  29808. if (cmd in unNeedCheckState) return;
  29809. var state = editor.queryCommandState(cmd);
  29810. if (ui.getDom()) {
  29811. ui.setDisabled(state == -1);
  29812. ui.setChecked(state);
  29813. }
  29814. });
  29815. return ui;
  29816. };
  29817. })(ci.toLowerCase());
  29818. }
  29819. })(p, dialogBtns[p]);
  29820. }
  29821. editorui.snapscreen = function (editor, iframeUrl, title) {
  29822. title =
  29823. editor.options.labelMap["snapscreen"] ||
  29824. editor.getLang("labelMap.snapscreen") ||
  29825. "";
  29826. var ui = new editorui.Button({
  29827. className: "edui-for-snapscreen",
  29828. title: title,
  29829. onclick: function () {
  29830. editor.execCommand("snapscreen");
  29831. },
  29832. theme: editor.options.theme
  29833. });
  29834. editorui.buttons["snapscreen"] = ui;
  29835. iframeUrl =
  29836. iframeUrl ||
  29837. (editor.options.iframeUrlMap || {})["snapscreen"] ||
  29838. iframeUrlMap["snapscreen"];
  29839. if (iframeUrl) {
  29840. var dialog = new editorui.Dialog({
  29841. iframeUrl: editor.ui.mapUrl(iframeUrl),
  29842. editor: editor,
  29843. className: "edui-for-snapscreen",
  29844. title: title,
  29845. buttons: [
  29846. {
  29847. className: "edui-okbutton",
  29848. label: editor.getLang("ok"),
  29849. editor: editor,
  29850. onclick: function () {
  29851. dialog.close(true);
  29852. }
  29853. },
  29854. {
  29855. className: "edui-cancelbutton",
  29856. label: editor.getLang("cancel"),
  29857. editor: editor,
  29858. onclick: function () {
  29859. dialog.close(false);
  29860. }
  29861. }
  29862. ]
  29863. });
  29864. dialog.render();
  29865. editor.ui._dialogs["snapscreenDialog"] = dialog;
  29866. }
  29867. editor.addListener("selectionchange", function () {
  29868. ui.setDisabled(editor.queryCommandState("snapscreen") == -1);
  29869. });
  29870. return ui;
  29871. };
  29872. editorui.insertcode = function (editor, list, title) {
  29873. list = editor.options["insertcode"] || [];
  29874. title =
  29875. editor.options.labelMap["insertcode"] ||
  29876. editor.getLang("labelMap.insertcode") ||
  29877. "";
  29878. // if (!list.length) return;
  29879. var items = [];
  29880. utils.each(list, function (key, val) {
  29881. items.push({
  29882. label: key,
  29883. value: val,
  29884. theme: editor.options.theme,
  29885. renderLabelHtml: function () {
  29886. return (
  29887. '<div class="edui-label %%-label" >' + (this.label || "") + "</div>"
  29888. );
  29889. }
  29890. });
  29891. });
  29892. var ui = new editorui.Combox({
  29893. editor: editor,
  29894. items: items,
  29895. onselect: function (t, index) {
  29896. editor.execCommand("insertcode", this.items[index].value);
  29897. },
  29898. onbuttonclick: function () {
  29899. this.showPopup();
  29900. },
  29901. title: title,
  29902. initValue: title,
  29903. className: "edui-for-insertcode",
  29904. indexByValue: function (value) {
  29905. if (value) {
  29906. for (var i = 0, ci; (ci = this.items[i]); i++) {
  29907. if (ci.value.indexOf(value) != -1) return i;
  29908. }
  29909. }
  29910. return -1;
  29911. }
  29912. });
  29913. editorui.buttons["insertcode"] = ui;
  29914. editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
  29915. if (!uiReady) {
  29916. var state = editor.queryCommandState("insertcode");
  29917. if (state == -1) {
  29918. ui.setDisabled(true);
  29919. } else {
  29920. ui.setDisabled(false);
  29921. var value = editor.queryCommandValue("insertcode");
  29922. if (!value) {
  29923. ui.setValue(title);
  29924. return;
  29925. }
  29926. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  29927. value && (value = value.replace(/['"]/g, "").split(",")[0]);
  29928. ui.setValue(value);
  29929. }
  29930. }
  29931. });
  29932. return ui;
  29933. };
  29934. editorui.fontfamily = function (editor, list, title) {
  29935. list = editor.options["fontfamily"] || [];
  29936. title =
  29937. editor.options.labelMap["fontfamily"] ||
  29938. editor.getLang("labelMap.fontfamily") ||
  29939. "";
  29940. if (!list.length) return;
  29941. for (var i = 0, ci, items = []; (ci = list[i]); i++) {
  29942. var langLabel = editor.getLang("fontfamily")[ci.name] || "";
  29943. (function (key, val) {
  29944. items.push({
  29945. label: key,
  29946. value: val,
  29947. theme: editor.options.theme,
  29948. renderLabelHtml: function () {
  29949. return (
  29950. '<div class="edui-label %%-label" style="font-family:' +
  29951. utils.unhtml(this.value) +
  29952. '">' +
  29953. (this.label || "") +
  29954. "</div>"
  29955. );
  29956. }
  29957. });
  29958. })(ci.label || langLabel, ci.val);
  29959. }
  29960. var ui = new editorui.Combox({
  29961. editor: editor,
  29962. items: items,
  29963. onselect: function (t, index) {
  29964. editor.execCommand("FontFamily", this.items[index].value);
  29965. },
  29966. onbuttonclick: function () {
  29967. this.showPopup();
  29968. },
  29969. title: title,
  29970. initValue: title,
  29971. className: "edui-for-fontfamily",
  29972. indexByValue: function (value) {
  29973. if (value) {
  29974. for (var i = 0, ci; (ci = this.items[i]); i++) {
  29975. if (ci.value.indexOf(value) != -1) return i;
  29976. }
  29977. }
  29978. return -1;
  29979. }
  29980. });
  29981. editorui.buttons["fontfamily"] = ui;
  29982. editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
  29983. if (!uiReady) {
  29984. var state = editor.queryCommandState("FontFamily");
  29985. if (state == -1) {
  29986. ui.setDisabled(true);
  29987. } else {
  29988. ui.setDisabled(false);
  29989. var value = editor.queryCommandValue("FontFamily");
  29990. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  29991. value && (value = value.replace(/['"]/g, "").split(",")[0]);
  29992. ui.setValue(value);
  29993. }
  29994. }
  29995. });
  29996. return ui;
  29997. };
  29998. editorui.fontsize = function (editor, list, title) {
  29999. title =
  30000. editor.options.labelMap["fontsize"] ||
  30001. editor.getLang("labelMap.fontsize") ||
  30002. "";
  30003. list = list || editor.options["fontsize"] || [];
  30004. if (!list.length) return;
  30005. var items = [];
  30006. for (var i = 0; i < list.length; i++) {
  30007. var size = list[i] + "px";
  30008. items.push({
  30009. label: size,
  30010. value: size,
  30011. theme: editor.options.theme,
  30012. renderLabelHtml: function () {
  30013. return (
  30014. '<div class="edui-label %%-label" style="line-height:1;font-size:' +
  30015. this.value +
  30016. '">' +
  30017. (this.label || "") +
  30018. "</div>"
  30019. );
  30020. }
  30021. });
  30022. }
  30023. var ui = new editorui.Combox({
  30024. editor: editor,
  30025. items: items,
  30026. title: title,
  30027. initValue: title,
  30028. onselect: function (t, index) {
  30029. editor.execCommand("FontSize", this.items[index].value);
  30030. },
  30031. onbuttonclick: function () {
  30032. this.showPopup();
  30033. },
  30034. className: "edui-for-fontsize"
  30035. });
  30036. editorui.buttons["fontsize"] = ui;
  30037. editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
  30038. if (!uiReady) {
  30039. var state = editor.queryCommandState("FontSize");
  30040. if (state == -1) {
  30041. ui.setDisabled(true);
  30042. } else {
  30043. ui.setDisabled(false);
  30044. ui.setValue(editor.queryCommandValue("FontSize"));
  30045. }
  30046. }
  30047. });
  30048. return ui;
  30049. };
  30050. editorui.paragraph = function (editor, list, title) {
  30051. title =
  30052. editor.options.labelMap["paragraph"] ||
  30053. editor.getLang("labelMap.paragraph") ||
  30054. "";
  30055. list = editor.options["paragraph"] || [];
  30056. if (utils.isEmptyObject(list)) return;
  30057. var items = [];
  30058. for (var i in list) {
  30059. items.push({
  30060. value: i,
  30061. label: list[i] || editor.getLang("paragraph")[i],
  30062. theme: editor.options.theme,
  30063. renderLabelHtml: function () {
  30064. return (
  30065. '<div class="edui-label %%-label"><span class="edui-for-' +
  30066. this.value +
  30067. '">' +
  30068. (this.label || "") +
  30069. "</span></div>"
  30070. );
  30071. }
  30072. });
  30073. }
  30074. var ui = new editorui.Combox({
  30075. editor: editor,
  30076. items: items,
  30077. title: title,
  30078. initValue: title,
  30079. className: "edui-for-paragraph",
  30080. onselect: function (t, index) {
  30081. editor.execCommand("Paragraph", this.items[index].value);
  30082. },
  30083. onbuttonclick: function () {
  30084. this.showPopup();
  30085. }
  30086. });
  30087. editorui.buttons["paragraph"] = ui;
  30088. editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
  30089. if (!uiReady) {
  30090. var state = editor.queryCommandState("Paragraph");
  30091. if (state == -1) {
  30092. ui.setDisabled(true);
  30093. } else {
  30094. ui.setDisabled(false);
  30095. var value = editor.queryCommandValue("Paragraph");
  30096. var index = ui.indexByValue(value);
  30097. if (index != -1) {
  30098. ui.setValue(value);
  30099. } else {
  30100. ui.setValue(ui.initValue);
  30101. }
  30102. }
  30103. }
  30104. });
  30105. return ui;
  30106. };
  30107. //自定义标题
  30108. editorui.customstyle = function (editor) {
  30109. var list = editor.options["customstyle"] || [],
  30110. title =
  30111. editor.options.labelMap["customstyle"] ||
  30112. editor.getLang("labelMap.customstyle") ||
  30113. "";
  30114. if (!list.length) return;
  30115. var langCs = editor.getLang("customstyle");
  30116. for (var i = 0, items = [], t; (t = list[i++]);) {
  30117. (function (t) {
  30118. var ck = {};
  30119. ck.label = t.label ? t.label : langCs[t.name];
  30120. ck.style = t.style;
  30121. ck.className = t.className;
  30122. ck.tag = t.tag;
  30123. items.push({
  30124. label: ck.label,
  30125. value: ck,
  30126. theme: editor.options.theme,
  30127. renderLabelHtml: function () {
  30128. return (
  30129. '<div class="edui-label %%-label">' +
  30130. "<" +
  30131. ck.tag +
  30132. " " +
  30133. (ck.className ? ' class="' + ck.className + '"' : "") +
  30134. (ck.style ? ' style="' + ck.style + '"' : "") +
  30135. ">" +
  30136. ck.label +
  30137. "</" +
  30138. ck.tag +
  30139. ">" +
  30140. "</div>"
  30141. );
  30142. }
  30143. });
  30144. })(t);
  30145. }
  30146. var ui = new editorui.Combox({
  30147. editor: editor,
  30148. items: items,
  30149. title: title,
  30150. initValue: title,
  30151. className: "edui-for-customstyle",
  30152. onselect: function (t, index) {
  30153. editor.execCommand("customstyle", this.items[index].value);
  30154. },
  30155. onbuttonclick: function () {
  30156. this.showPopup();
  30157. },
  30158. indexByValue: function (value) {
  30159. for (var i = 0, ti; (ti = this.items[i++]);) {
  30160. if (ti.label == value) {
  30161. return i - 1;
  30162. }
  30163. }
  30164. return -1;
  30165. }
  30166. });
  30167. editorui.buttons["customstyle"] = ui;
  30168. editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
  30169. if (!uiReady) {
  30170. var state = editor.queryCommandState("customstyle");
  30171. if (state == -1) {
  30172. ui.setDisabled(true);
  30173. } else {
  30174. ui.setDisabled(false);
  30175. var value = editor.queryCommandValue("customstyle");
  30176. var index = ui.indexByValue(value);
  30177. if (index != -1) {
  30178. ui.setValue(value);
  30179. } else {
  30180. ui.setValue(ui.initValue);
  30181. }
  30182. }
  30183. }
  30184. });
  30185. return ui;
  30186. };
  30187. editorui.inserttable = function (editor, iframeUrl, title) {
  30188. title =
  30189. editor.options.labelMap["inserttable"] ||
  30190. editor.getLang("labelMap.inserttable") ||
  30191. "";
  30192. var ui = new editorui.TableButton({
  30193. editor: editor,
  30194. title: title,
  30195. className: "edui-for-inserttable",
  30196. onpicktable: function (t, numCols, numRows) {
  30197. editor.execCommand("InsertTable", {
  30198. numRows: numRows,
  30199. numCols: numCols,
  30200. border: 1
  30201. });
  30202. },
  30203. onbuttonclick: function () {
  30204. this.showPopup();
  30205. }
  30206. });
  30207. editorui.buttons["inserttable"] = ui;
  30208. editor.addListener("selectionchange", function () {
  30209. ui.setDisabled(editor.queryCommandState("inserttable") == -1);
  30210. });
  30211. return ui;
  30212. };
  30213. editorui.lineheight = function (editor) {
  30214. var val = editor.options.lineheight || [];
  30215. if (!val.length) return;
  30216. for (var i = 0, ci, items = []; (ci = val[i++]);) {
  30217. items.push({
  30218. //todo:写死了
  30219. label: ci,
  30220. value: ci,
  30221. theme: editor.options.theme,
  30222. onclick: function () {
  30223. editor.execCommand("lineheight", this.value);
  30224. }
  30225. });
  30226. }
  30227. var ui = new editorui.MenuButton({
  30228. editor: editor,
  30229. className: "edui-for-lineheight",
  30230. title:
  30231. editor.options.labelMap["lineheight"] ||
  30232. editor.getLang("labelMap.lineheight") ||
  30233. "",
  30234. items: items,
  30235. onbuttonclick: function () {
  30236. var value = editor.queryCommandValue("LineHeight") || this.value;
  30237. editor.execCommand("LineHeight", value);
  30238. }
  30239. });
  30240. editorui.buttons["lineheight"] = ui;
  30241. editor.addListener("selectionchange", function () {
  30242. var state = editor.queryCommandState("LineHeight");
  30243. if (state == -1) {
  30244. ui.setDisabled(true);
  30245. } else {
  30246. ui.setDisabled(false);
  30247. var value = editor.queryCommandValue("LineHeight");
  30248. value && ui.setValue((value + "").replace(/cm/, ""));
  30249. ui.setChecked(state);
  30250. }
  30251. });
  30252. return ui;
  30253. };
  30254. var rowspacings = ["top", "bottom"];
  30255. for (var r = 0, ri; (ri = rowspacings[r++]);) {
  30256. (function (cmd) {
  30257. editorui["rowspacing" + cmd] = function (editor) {
  30258. var val = editor.options["rowspacing" + cmd] || [];
  30259. if (!val.length) return null;
  30260. for (var i = 0, ci, items = []; (ci = val[i++]);) {
  30261. items.push({
  30262. label: ci,
  30263. value: ci,
  30264. theme: editor.options.theme,
  30265. onclick: function () {
  30266. editor.execCommand("rowspacing", this.value, cmd);
  30267. }
  30268. });
  30269. }
  30270. var ui = new editorui.MenuButton({
  30271. editor: editor,
  30272. className: "edui-for-rowspacing" + cmd,
  30273. title:
  30274. editor.options.labelMap["rowspacing" + cmd] ||
  30275. editor.getLang("labelMap.rowspacing" + cmd) ||
  30276. "",
  30277. items: items,
  30278. onbuttonclick: function () {
  30279. var value =
  30280. editor.queryCommandValue("rowspacing", cmd) || this.value;
  30281. editor.execCommand("rowspacing", value, cmd);
  30282. }
  30283. });
  30284. editorui.buttons[cmd] = ui;
  30285. editor.addListener("selectionchange", function () {
  30286. var state = editor.queryCommandState("rowspacing", cmd);
  30287. if (state == -1) {
  30288. ui.setDisabled(true);
  30289. } else {
  30290. ui.setDisabled(false);
  30291. var value = editor.queryCommandValue("rowspacing", cmd);
  30292. value && ui.setValue((value + "").replace(/%/, ""));
  30293. ui.setChecked(state);
  30294. }
  30295. });
  30296. return ui;
  30297. };
  30298. })(ri);
  30299. }
  30300. //有序,无序列表
  30301. var lists = ["insertorderedlist", "insertunorderedlist"];
  30302. for (var l = 0, cl; (cl = lists[l++]);) {
  30303. (function (cmd) {
  30304. editorui[cmd] = function (editor) {
  30305. var vals = editor.options[cmd],
  30306. _onMenuClick = function () {
  30307. editor.execCommand(cmd, this.value);
  30308. },
  30309. items = [];
  30310. for (var i in vals) {
  30311. items.push({
  30312. label: vals[i] || editor.getLang()[cmd][i] || "",
  30313. value: i,
  30314. theme: editor.options.theme,
  30315. onclick: _onMenuClick
  30316. });
  30317. }
  30318. var ui = new editorui.MenuButton({
  30319. editor: editor,
  30320. className: "edui-for-" + cmd,
  30321. title: editor.getLang("labelMap." + cmd) || "",
  30322. items: items,
  30323. onbuttonclick: function () {
  30324. var value = editor.queryCommandValue(cmd) || this.value;
  30325. editor.execCommand(cmd, value);
  30326. }
  30327. });
  30328. editorui.buttons[cmd] = ui;
  30329. editor.addListener("selectionchange", function () {
  30330. var state = editor.queryCommandState(cmd);
  30331. if (state == -1) {
  30332. ui.setDisabled(true);
  30333. } else {
  30334. ui.setDisabled(false);
  30335. var value = editor.queryCommandValue(cmd);
  30336. ui.setValue(value);
  30337. ui.setChecked(state);
  30338. }
  30339. });
  30340. return ui;
  30341. };
  30342. })(cl);
  30343. }
  30344. editorui.fullscreen = function (editor, title) {
  30345. title =
  30346. editor.options.labelMap["fullscreen"] ||
  30347. editor.getLang("labelMap.fullscreen") ||
  30348. "";
  30349. var ui = new editorui.Button({
  30350. className: "edui-for-fullscreen",
  30351. title: title,
  30352. theme: editor.options.theme,
  30353. onclick: function () {
  30354. if (editor.ui) {
  30355. editor.ui.setFullScreen(!editor.ui.isFullScreen());
  30356. }
  30357. this.setChecked(editor.ui.isFullScreen());
  30358. }
  30359. });
  30360. editorui.buttons["fullscreen"] = ui;
  30361. editor.addListener("selectionchange", function () {
  30362. var state = editor.queryCommandState("fullscreen");
  30363. ui.setDisabled(state == -1);
  30364. ui.setChecked(editor.ui.isFullScreen());
  30365. });
  30366. return ui;
  30367. };
  30368. // 表情
  30369. editorui["emotion"] = function (editor, iframeUrl) {
  30370. var cmd = "emotion";
  30371. var ui = new editorui.MultiMenuPop({
  30372. title:
  30373. editor.options.labelMap[cmd] ||
  30374. editor.getLang("labelMap." + cmd + "") ||
  30375. "",
  30376. editor: editor,
  30377. className: "edui-for-" + cmd,
  30378. iframeUrl: editor.ui.mapUrl(
  30379. iframeUrl ||
  30380. (editor.options.iframeUrlMap || {})[cmd] ||
  30381. iframeUrlMap[cmd]
  30382. )
  30383. });
  30384. editorui.buttons[cmd] = ui;
  30385. editor.addListener("selectionchange", function () {
  30386. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  30387. });
  30388. return ui;
  30389. };
  30390. editorui.autotypeset = function (editor) {
  30391. var ui = new editorui.AutoTypeSetButton({
  30392. editor: editor,
  30393. title:
  30394. editor.options.labelMap["autotypeset"] ||
  30395. editor.getLang("labelMap.autotypeset") ||
  30396. "",
  30397. className: "edui-for-autotypeset",
  30398. onbuttonclick: function () {
  30399. editor.execCommand("autotypeset");
  30400. }
  30401. });
  30402. editorui.buttons["autotypeset"] = ui;
  30403. editor.addListener("selectionchange", function () {
  30404. ui.setDisabled(editor.queryCommandState("autotypeset") == -1);
  30405. });
  30406. return ui;
  30407. };
  30408. /* 简单上传插件 */
  30409. editorui["simpleupload"] = function (editor) {
  30410. var name = "simpleupload",
  30411. ui = new editorui.Button({
  30412. className: "edui-for-" + name,
  30413. title:
  30414. editor.options.labelMap[name] ||
  30415. editor.getLang("labelMap." + name) ||
  30416. "",
  30417. onclick: function () {
  30418. },
  30419. theme: editor.options.theme,
  30420. showText: false
  30421. });
  30422. editorui.buttons[name] = ui;
  30423. editor.addListener("ready", function () {
  30424. var b = ui.getDom("body"),
  30425. iconSpan = b.children[0];
  30426. editor.fireEvent("simpleuploadbtnready", iconSpan);
  30427. });
  30428. editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
  30429. var state = editor.queryCommandState(name);
  30430. if (state == -1) {
  30431. ui.setDisabled(true);
  30432. ui.setChecked(false);
  30433. } else {
  30434. if (!uiReady) {
  30435. ui.setDisabled(false);
  30436. ui.setChecked(state);
  30437. }
  30438. }
  30439. });
  30440. return ui;
  30441. };
  30442. })();
  30443. // adapter/editor.js
  30444. ///import core
  30445. ///commands 全屏
  30446. ///commandsName FullScreen
  30447. ///commandsTitle 全屏
  30448. ;(function () {
  30449. var utils = baidu.editor.utils,
  30450. uiUtils = baidu.editor.ui.uiUtils,
  30451. UIBase = baidu.editor.ui.UIBase,
  30452. domUtils = baidu.editor.dom.domUtils;
  30453. var nodeStack = [];
  30454. function EditorUI(options) {
  30455. this.initOptions(options);
  30456. this.initEditorUI();
  30457. }
  30458. EditorUI.prototype = {
  30459. uiName: "editor",
  30460. initEditorUI: function () {
  30461. this.editor.ui = this;
  30462. this._dialogs = {};
  30463. this.initUIBase();
  30464. this._initToolbars();
  30465. var editor = this.editor,
  30466. me = this;
  30467. editor.addListener("ready", function () {
  30468. //提供getDialog方法
  30469. editor.getDialog = function (name) {
  30470. return editor.ui._dialogs[name + "Dialog"];
  30471. };
  30472. domUtils.on(editor.window, "scroll", function (evt) {
  30473. baidu.editor.ui.Popup.postHide(evt);
  30474. });
  30475. //提供编辑器实时宽高(全屏时宽高不变化)
  30476. editor.ui._actualFrameWidth = editor.options.initialFrameWidth;
  30477. UE.browser.ie &&
  30478. UE.browser.version === 6 &&
  30479. editor.container.ownerDocument.execCommand(
  30480. "BackgroundImageCache",
  30481. false,
  30482. true
  30483. );
  30484. //display bottom-bar label based on config
  30485. if (editor.options.elementPathEnabled) {
  30486. editor.ui.getDom("elementpath").innerHTML =
  30487. '<div class="edui-editor-breadcrumb">' +
  30488. editor.getLang("elementPathTip") +
  30489. ":</div>";
  30490. }
  30491. if (editor.options.wordCount) {
  30492. function countFn() {
  30493. setCount(editor, me);
  30494. domUtils.un(editor.document, "click", arguments.callee);
  30495. }
  30496. domUtils.on(editor.document, "click", countFn);
  30497. editor.ui.getDom("wordcount").innerHTML = editor.getLang(
  30498. "wordCountTip"
  30499. );
  30500. }
  30501. editor.ui._scale();
  30502. if (editor.options.scaleEnabled) {
  30503. if (editor.autoHeightEnabled) {
  30504. editor.disableAutoHeight();
  30505. }
  30506. me.enableScale();
  30507. } else {
  30508. me.disableScale();
  30509. }
  30510. if (
  30511. !editor.options.elementPathEnabled &&
  30512. !editor.options.wordCount &&
  30513. !editor.options.scaleEnabled
  30514. ) {
  30515. editor.ui.getDom("elementpath").style.display = "none";
  30516. editor.ui.getDom("wordcount").style.display = "none";
  30517. editor.ui.getDom("scale").style.display = "none";
  30518. }
  30519. if (!editor.selection.isFocus()) return;
  30520. editor.fireEvent("selectionchange", false, true);
  30521. });
  30522. editor.addListener("mousedown", function (t, evt) {
  30523. var el = evt.target || evt.srcElement;
  30524. baidu.editor.ui.Popup.postHide(evt, el);
  30525. baidu.editor.ui.ShortCutMenu.postHide(evt);
  30526. });
  30527. editor.addListener("delcells", function () {
  30528. if (UE.ui["edittip"]) {
  30529. new UE.ui["edittip"](editor);
  30530. }
  30531. editor.getDialog("edittip").open();
  30532. });
  30533. var pastePop,
  30534. isPaste = false,
  30535. timer;
  30536. editor.addListener("afterpaste", function () {
  30537. if (editor.queryCommandState("pasteplain")) return;
  30538. if (baidu.editor.ui.PastePicker) {
  30539. pastePop = new baidu.editor.ui.Popup({
  30540. content: new baidu.editor.ui.PastePicker({editor: editor}),
  30541. editor: editor,
  30542. className: "edui-wordpastepop"
  30543. });
  30544. pastePop.render();
  30545. }
  30546. isPaste = true;
  30547. });
  30548. editor.addListener("afterinserthtml", function () {
  30549. clearTimeout(timer);
  30550. timer = setTimeout(function () {
  30551. if (pastePop && (isPaste || editor.ui._isTransfer)) {
  30552. if (pastePop.isHidden()) {
  30553. var span = domUtils.createElement(editor.document, "span", {
  30554. style: "line-height:0px;",
  30555. innerHTML: "\ufeff"
  30556. }),
  30557. range = editor.selection.getRange();
  30558. range.insertNode(span);
  30559. var tmp = getDomNode(span, "firstChild", "previousSibling");
  30560. tmp &&
  30561. pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp);
  30562. domUtils.remove(span);
  30563. } else {
  30564. pastePop.show();
  30565. }
  30566. delete editor.ui._isTransfer;
  30567. isPaste = false;
  30568. }
  30569. }, 200);
  30570. });
  30571. editor.addListener("contextmenu", function (t, evt) {
  30572. baidu.editor.ui.Popup.postHide(evt);
  30573. });
  30574. editor.addListener("keydown", function (t, evt) {
  30575. if (pastePop) pastePop.dispose(evt);
  30576. var keyCode = evt.keyCode || evt.which;
  30577. if (evt.altKey && keyCode == 90) {
  30578. UE.ui.buttons["fullscreen"].onclick();
  30579. }
  30580. });
  30581. editor.addListener("wordcount", function (type) {
  30582. setCount(this, me);
  30583. });
  30584. function setCount(editor, ui) {
  30585. editor.setOpt({
  30586. wordCount: true,
  30587. maximumWords: 10000,
  30588. wordCountMsg:
  30589. editor.options.wordCountMsg || editor.getLang("wordCountMsg"),
  30590. wordOverFlowMsg:
  30591. editor.options.wordOverFlowMsg || editor.getLang("wordOverFlowMsg")
  30592. });
  30593. var opt = editor.options,
  30594. max = opt.maximumWords,
  30595. msg = opt.wordCountMsg,
  30596. errMsg = opt.wordOverFlowMsg,
  30597. countDom = ui.getDom("wordcount");
  30598. if (!opt.wordCount) {
  30599. return;
  30600. }
  30601. var count = editor.getContentLength(true);
  30602. if (count > max) {
  30603. countDom.innerHTML = errMsg;
  30604. editor.fireEvent("wordcountoverflow");
  30605. } else {
  30606. countDom.innerHTML = msg
  30607. .replace("{#leave}", max - count)
  30608. .replace("{#count}", count);
  30609. }
  30610. }
  30611. editor.addListener("selectionchange", function () {
  30612. if (editor.options.elementPathEnabled) {
  30613. me[
  30614. (editor.queryCommandState("elementpath") == -1 ? "dis" : "en") +
  30615. "ableElementPath"
  30616. ]();
  30617. }
  30618. if (editor.options.scaleEnabled) {
  30619. me[
  30620. (editor.queryCommandState("scale") == -1 ? "dis" : "en") +
  30621. "ableScale"
  30622. ]();
  30623. }
  30624. });
  30625. var popup = new baidu.editor.ui.Popup({
  30626. editor: editor,
  30627. content: "",
  30628. className: "edui-bubble",
  30629. _onEditButtonClick: function () {
  30630. this.hide();
  30631. editor.ui._dialogs.linkDialog.open();
  30632. },
  30633. _onImgEditButtonClick: function (name) {
  30634. this.hide();
  30635. editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
  30636. },
  30637. _onImgSetFloat: function (value) {
  30638. this.hide();
  30639. editor.execCommand("imagefloat", value);
  30640. },
  30641. _setIframeAlign: function (value) {
  30642. var frame = popup.anchorEl;
  30643. var newFrame = frame.cloneNode(true);
  30644. switch (value) {
  30645. case -2:
  30646. newFrame.setAttribute("align", "");
  30647. break;
  30648. case -1:
  30649. newFrame.setAttribute("align", "left");
  30650. break;
  30651. case 1:
  30652. newFrame.setAttribute("align", "right");
  30653. break;
  30654. }
  30655. frame.parentNode.insertBefore(newFrame, frame);
  30656. domUtils.remove(frame);
  30657. popup.anchorEl = newFrame;
  30658. popup.showAnchor(popup.anchorEl);
  30659. },
  30660. _updateIframe: function () {
  30661. var frame = (editor._iframe = popup.anchorEl);
  30662. if (domUtils.hasClass(frame, "ueditor_baidumap")) {
  30663. editor.selection.getRange().selectNode(frame).select();
  30664. editor.ui._dialogs.mapDialog.open();
  30665. popup.hide();
  30666. } else {
  30667. editor.ui._dialogs.insertframeDialog.open();
  30668. popup.hide();
  30669. }
  30670. },
  30671. _onRemoveButtonClick: function (cmdName) {
  30672. editor.execCommand(cmdName);
  30673. this.hide();
  30674. },
  30675. queryAutoHide: function (el) {
  30676. if (el && el.ownerDocument == editor.document) {
  30677. if (
  30678. el.tagName.toLowerCase() == "img" ||
  30679. domUtils.findParentByTagName(el, "a", true)
  30680. ) {
  30681. return el !== popup.anchorEl;
  30682. }
  30683. }
  30684. return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el);
  30685. }
  30686. });
  30687. popup.render();
  30688. if (editor.options.imagePopup) {
  30689. editor.addListener("mouseover", function (t, evt) {
  30690. evt = evt || window.event;
  30691. var el = evt.target || evt.srcElement;
  30692. if (
  30693. editor.ui._dialogs.insertframeDialog &&
  30694. /iframe/gi.test(el.tagName)
  30695. ) {
  30696. var html = popup.formatHtml(
  30697. "<nobr>" +
  30698. editor.getLang("property") +
  30699. ': <span onclick=$$._setIframeAlign(-2) class="edui-clickable">' +
  30700. editor.getLang("default") +
  30701. '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(-1) class="edui-clickable">' +
  30702. editor.getLang("justifyleft") +
  30703. '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(1) class="edui-clickable">' +
  30704. editor.getLang("justifyright") +
  30705. "</span>&nbsp;&nbsp;" +
  30706. ' <span onclick="$$._updateIframe( this);" class="edui-clickable">' +
  30707. editor.getLang("modify") +
  30708. "</span></nobr>"
  30709. );
  30710. if (html) {
  30711. popup.getDom("content").innerHTML = html;
  30712. popup.anchorEl = el;
  30713. popup.showAnchor(popup.anchorEl);
  30714. } else {
  30715. popup.hide();
  30716. }
  30717. }
  30718. });
  30719. editor.addListener("selectionchange", function (t, causeByUi) {
  30720. if (!causeByUi) return;
  30721. var html = "",
  30722. str = "",
  30723. img = editor.selection.getRange().getClosedNode(),
  30724. dialogs = editor.ui._dialogs;
  30725. if (img && img.tagName == "IMG") {
  30726. var dialogName = "insertimageDialog";
  30727. if (
  30728. img.className.indexOf("edui-faked-video") != -1 ||
  30729. img.className.indexOf("edui-upload-video") != -1
  30730. ) {
  30731. dialogName = "insertvideoDialog";
  30732. }
  30733. if (img.className.indexOf("edui-faked-webapp") != -1) {
  30734. dialogName = "webappDialog";
  30735. }
  30736. if (img.src.indexOf("https://api.map.baidu.com") != -1) {
  30737. dialogName = "mapDialog";
  30738. }
  30739. if (img.className.indexOf("edui-faked-music") != -1) {
  30740. dialogName = "musicDialog";
  30741. }
  30742. if (
  30743. img.src.indexOf("http://maps.google.com/maps/api/staticmap") != -1
  30744. ) {
  30745. dialogName = "gmapDialog";
  30746. }
  30747. if (img.getAttribute("anchorname")) {
  30748. dialogName = "anchorDialog";
  30749. html = popup.formatHtml(
  30750. "<nobr>" +
  30751. editor.getLang("property") +
  30752. ': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' +
  30753. editor.getLang("modify") +
  30754. "</span>&nbsp;&nbsp;" +
  30755. "<span onclick=$$._onRemoveButtonClick('anchor') class=\"edui-clickable\">" +
  30756. editor.getLang("delete") +
  30757. "</span></nobr>"
  30758. );
  30759. }
  30760. if (img.getAttribute("word_img")) {
  30761. //todo 放到dialog去做查询
  30762. editor.word_img = [img.getAttribute("word_img")];
  30763. dialogName = "wordimageDialog";
  30764. }
  30765. if (
  30766. domUtils.hasClass(img, "loadingclass") ||
  30767. domUtils.hasClass(img, "loaderrorclass")
  30768. ) {
  30769. dialogName = "";
  30770. }
  30771. if (!dialogs[dialogName]) {
  30772. return;
  30773. }
  30774. str =
  30775. "<nobr>" +
  30776. editor.getLang("property") +
  30777. ": " +
  30778. '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' +
  30779. editor.getLang("default") +
  30780. "</span>&nbsp;&nbsp;" +
  30781. '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' +
  30782. editor.getLang("justifyleft") +
  30783. "</span>&nbsp;&nbsp;" +
  30784. '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' +
  30785. editor.getLang("justifyright") +
  30786. "</span>&nbsp;&nbsp;" +
  30787. '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' +
  30788. editor.getLang("justifycenter") +
  30789. "</span>&nbsp;&nbsp;" +
  30790. "<span onclick=\"$$._onImgEditButtonClick('" +
  30791. dialogName +
  30792. '\');" class="edui-clickable">' +
  30793. editor.getLang("modify") +
  30794. "</span></nobr>";
  30795. !html && (html = popup.formatHtml(str));
  30796. }
  30797. if (editor.ui._dialogs.linkDialog) {
  30798. var link = editor.queryCommandValue("link");
  30799. var url;
  30800. if (
  30801. link &&
  30802. (url = link.getAttribute("_href") || link.getAttribute("href", 2))
  30803. ) {
  30804. var txt = url;
  30805. if (url.length > 30) {
  30806. txt = url.substring(0, 20) + "...";
  30807. }
  30808. if (html) {
  30809. html += '<div style="height:5px;"></div>';
  30810. }
  30811. html += popup.formatHtml(
  30812. "<nobr>" +
  30813. editor.getLang("anthorMsg") +
  30814. ': <a target="_blank" href="' +
  30815. url +
  30816. '" title="' +
  30817. url +
  30818. '" >' +
  30819. txt +
  30820. "</a>" +
  30821. ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' +
  30822. editor.getLang("modify") +
  30823. "</span>" +
  30824. ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' +
  30825. editor.getLang("clear") +
  30826. "</span></nobr>"
  30827. );
  30828. popup.showAnchor(link);
  30829. }
  30830. }
  30831. if (html) {
  30832. popup.getDom("content").innerHTML = html;
  30833. popup.anchorEl = img || link;
  30834. popup.showAnchor(popup.anchorEl);
  30835. } else {
  30836. popup.hide();
  30837. }
  30838. });
  30839. }
  30840. },
  30841. _initToolbars: function () {
  30842. var editor = this.editor;
  30843. var toolbars = this.toolbars || [];
  30844. var toolbarUis = [];
  30845. var extraUIs = [];
  30846. for (var i = 0; i < toolbars.length; i++) {
  30847. var toolbar = toolbars[i];
  30848. var toolbarUi = new baidu.editor.ui.Toolbar({
  30849. theme: editor.options.theme
  30850. });
  30851. for (var j = 0; j < toolbar.length; j++) {
  30852. var toolbarItem = toolbar[j];
  30853. var toolbarItemUi = null;
  30854. if (typeof toolbarItem == "string") {
  30855. toolbarItem = toolbarItem.toLowerCase();
  30856. if (toolbarItem == "|") {
  30857. toolbarItem = "Separator";
  30858. }
  30859. if (toolbarItem == "||") {
  30860. toolbarItem = "Breakline";
  30861. }
  30862. var ui = baidu.editor.ui[toolbarItem];
  30863. if (ui) {
  30864. if (utils.isFunction(ui)) {
  30865. toolbarItemUi = new baidu.editor.ui[toolbarItem](editor);
  30866. } else {
  30867. if (ui.id && ui.id != editor.key) {
  30868. continue;
  30869. }
  30870. var itemUI = ui.execFn.call(editor, editor, toolbarItem);
  30871. if (itemUI) {
  30872. if (ui.index === undefined) {
  30873. toolbarUi.add(itemUI);
  30874. continue;
  30875. } else {
  30876. extraUIs.push({
  30877. index: ui.index,
  30878. itemUI: itemUI
  30879. });
  30880. }
  30881. }
  30882. }
  30883. }
  30884. //fullscreen这里单独处理一下,放到首行去
  30885. if (toolbarItem == "fullscreen") {
  30886. if (toolbarUis && toolbarUis[0]) {
  30887. toolbarUis[0].items.splice(0, 0, toolbarItemUi);
  30888. } else {
  30889. toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi);
  30890. }
  30891. continue;
  30892. }
  30893. } else {
  30894. toolbarItemUi = toolbarItem;
  30895. }
  30896. if (toolbarItemUi && toolbarItemUi.id) {
  30897. toolbarUi.add(toolbarItemUi);
  30898. }
  30899. }
  30900. toolbarUis[i] = toolbarUi;
  30901. }
  30902. //接受外部定制的UI
  30903. utils.each(extraUIs, function (obj) {
  30904. toolbarUi.add(obj.itemUI, obj.index);
  30905. });
  30906. this.toolbars = toolbarUis;
  30907. },
  30908. getHtmlTpl: function () {
  30909. return (
  30910. '<div id="##" class="%%">' +
  30911. '<div id="##_toolbarbox" class="%%-toolbarbox">' +
  30912. (this.toolbars.length
  30913. ? '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
  30914. this.renderToolbarBoxHtml() +
  30915. "</div></div>"
  30916. : "") +
  30917. '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
  30918. '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' +
  30919. this.editor.getLang("clickToUpload") +
  30920. "</div>" +
  30921. '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
  30922. '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
  30923. '<div style="height:0;overflow:hidden;clear:both;"></div>' +
  30924. "</div>" +
  30925. '<div id="##_message_holder" class="%%-messageholder"></div>' +
  30926. "</div>" +
  30927. '<div id="##_iframeholder" class="%%-iframeholder">' +
  30928. "</div>" +
  30929. //modify wdcount by matao
  30930. '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
  30931. '<td id="##_elementpath" class="%%-bottombar"></td>' +
  30932. '<td id="##_wordcount" class="%%-wordcount"></td>' +
  30933. '<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
  30934. "</tr></table></div>" +
  30935. '<div id="##_scalelayer"></div>' +
  30936. "</div>"
  30937. );
  30938. },
  30939. showWordImageDialog: function () {
  30940. this._dialogs["wordimageDialog"].open();
  30941. },
  30942. renderToolbarBoxHtml: function () {
  30943. var buff = [];
  30944. for (var i = 0; i < this.toolbars.length; i++) {
  30945. buff.push(this.toolbars[i].renderHtml());
  30946. }
  30947. return buff.join("");
  30948. },
  30949. setFullScreen: function (fullscreen) {
  30950. var editor = this.editor,
  30951. container = editor.container.parentNode.parentNode;
  30952. if (this._fullscreen != fullscreen) {
  30953. this._fullscreen = fullscreen;
  30954. this.editor.fireEvent("beforefullscreenchange", fullscreen);
  30955. if (baidu.editor.browser.gecko) {
  30956. var bk = editor.selection.getRange().createBookmark();
  30957. }
  30958. if (fullscreen) {
  30959. while (container.tagName != "BODY") {
  30960. var position = baidu.editor.dom.domUtils.getComputedStyle(
  30961. container,
  30962. "position"
  30963. );
  30964. nodeStack.push(position);
  30965. container.style.position = "static";
  30966. container = container.parentNode;
  30967. }
  30968. this._bakHtmlOverflow = document.documentElement.style.overflow;
  30969. this._bakBodyOverflow = document.body.style.overflow;
  30970. this._bakAutoHeight = this.editor.autoHeightEnabled;
  30971. this._bakScrollTop = Math.max(
  30972. document.documentElement.scrollTop,
  30973. document.body.scrollTop
  30974. );
  30975. this._bakEditorContaninerWidth = editor.iframe.parentNode.offsetWidth;
  30976. if (this._bakAutoHeight) {
  30977. //当全屏时不能执行自动长高
  30978. editor.autoHeightEnabled = false;
  30979. this.editor.disableAutoHeight();
  30980. }
  30981. document.documentElement.style.overflow = "hidden";
  30982. //修复,滚动条不收起的问题
  30983. window.scrollTo(0, window.scrollY);
  30984. this._bakCssText = this.getDom().style.cssText;
  30985. this._bakCssText1 = this.getDom("iframeholder").style.cssText;
  30986. editor.iframe.parentNode.style.width = "";
  30987. this._updateFullScreen();
  30988. } else {
  30989. while (container.tagName != "BODY") {
  30990. container.style.position = nodeStack.shift();
  30991. container = container.parentNode;
  30992. }
  30993. this.getDom().style.cssText = this._bakCssText;
  30994. this.getDom("iframeholder").style.cssText = this._bakCssText1;
  30995. if (this._bakAutoHeight) {
  30996. editor.autoHeightEnabled = true;
  30997. this.editor.enableAutoHeight();
  30998. }
  30999. document.documentElement.style.overflow = this._bakHtmlOverflow;
  31000. document.body.style.overflow = this._bakBodyOverflow;
  31001. editor.iframe.parentNode.style.width =
  31002. this._bakEditorContaninerWidth + "px";
  31003. window.scrollTo(0, this._bakScrollTop);
  31004. }
  31005. if (browser.gecko && editor.body.contentEditable === "true") {
  31006. var input = document.createElement("input");
  31007. document.body.appendChild(input);
  31008. editor.body.contentEditable = false;
  31009. setTimeout(function () {
  31010. input.focus();
  31011. setTimeout(function () {
  31012. editor.body.contentEditable = true;
  31013. editor.fireEvent("fullscreenchanged", fullscreen);
  31014. editor.selection.getRange().moveToBookmark(bk).select(true);
  31015. baidu.editor.dom.domUtils.remove(input);
  31016. fullscreen && window.scroll(0, 0);
  31017. }, 0);
  31018. }, 0);
  31019. }
  31020. if (editor.body.contentEditable === "true") {
  31021. this.editor.fireEvent("fullscreenchanged", fullscreen);
  31022. this.triggerLayout();
  31023. }
  31024. }
  31025. },
  31026. _updateFullScreen: function () {
  31027. if (this._fullscreen) {
  31028. var vpRect = uiUtils.getViewportRect();
  31029. this.getDom().style.cssText =
  31030. "border:0;position:absolute;left:0;top:" +
  31031. (this.editor.options.topOffset || 0) +
  31032. "px;width:" +
  31033. vpRect.width +
  31034. "px;height:" +
  31035. vpRect.height +
  31036. "px;z-index:" +
  31037. (this.getDom().style.zIndex * 1 + 100);
  31038. uiUtils.setViewportOffset(this.getDom(), {
  31039. left: 0,
  31040. top: this.editor.options.topOffset || 0
  31041. });
  31042. this.editor.setHeight(
  31043. vpRect.height -
  31044. this.getDom("toolbarbox").offsetHeight -
  31045. this.getDom("bottombar").offsetHeight -
  31046. (this.editor.options.topOffset || 0),
  31047. true
  31048. );
  31049. //不手动调一下,会导致全屏失效
  31050. if (browser.gecko) {
  31051. try {
  31052. window.onresize();
  31053. } catch (e) {
  31054. }
  31055. }
  31056. }
  31057. },
  31058. _updateElementPath: function () {
  31059. var bottom = this.getDom("elementpath"),
  31060. list;
  31061. if (
  31062. this.elementPathEnabled &&
  31063. (list = this.editor.queryCommandValue("elementpath"))
  31064. ) {
  31065. var buff = [];
  31066. for (var i = 0, ci; (ci = list[i]); i++) {
  31067. buff[i] = this.formatHtml(
  31068. '<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' +
  31069. i +
  31070. '&quot;);">' +
  31071. ci +
  31072. "</span>"
  31073. );
  31074. }
  31075. bottom.innerHTML =
  31076. '<div class="edui-editor-breadcrumb" onmousedown="return false;">' +
  31077. this.editor.getLang("elementPathTip") +
  31078. ": " +
  31079. buff.join(" &gt; ") +
  31080. "</div>";
  31081. } else {
  31082. bottom.style.display = "none";
  31083. }
  31084. },
  31085. disableElementPath: function () {
  31086. var bottom = this.getDom("elementpath");
  31087. bottom.innerHTML = "";
  31088. bottom.style.display = "none";
  31089. this.elementPathEnabled = false;
  31090. },
  31091. enableElementPath: function () {
  31092. var bottom = this.getDom("elementpath");
  31093. bottom.style.display = "";
  31094. this.elementPathEnabled = true;
  31095. this._updateElementPath();
  31096. },
  31097. _scale: function () {
  31098. var doc = document,
  31099. editor = this.editor,
  31100. editorHolder = editor.container,
  31101. editorDocument = editor.document,
  31102. toolbarBox = this.getDom("toolbarbox"),
  31103. bottombar = this.getDom("bottombar"),
  31104. scale = this.getDom("scale"),
  31105. scalelayer = this.getDom("scalelayer");
  31106. var isMouseMove = false,
  31107. position = null,
  31108. minEditorHeight = 0,
  31109. minEditorWidth = editor.options.minFrameWidth,
  31110. pageX = 0,
  31111. pageY = 0,
  31112. scaleWidth = 0,
  31113. scaleHeight = 0;
  31114. function down() {
  31115. position = domUtils.getXY(editorHolder);
  31116. if (!minEditorHeight) {
  31117. minEditorHeight =
  31118. editor.options.minFrameHeight +
  31119. toolbarBox.offsetHeight +
  31120. bottombar.offsetHeight;
  31121. }
  31122. scalelayer.style.cssText =
  31123. "position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:" +
  31124. editorHolder.offsetWidth +
  31125. "px;height:" +
  31126. editorHolder.offsetHeight +
  31127. "px;z-index:" +
  31128. (editor.options.zIndex + 1);
  31129. domUtils.on(doc, "mousemove", move);
  31130. domUtils.on(editorDocument, "mouseup", up);
  31131. domUtils.on(doc, "mouseup", up);
  31132. }
  31133. var me = this;
  31134. //by xuheng 全屏时关掉缩放
  31135. this.editor.addListener("fullscreenchanged", function (e, fullScreen) {
  31136. if (fullScreen) {
  31137. me.disableScale();
  31138. } else {
  31139. if (me.editor.options.scaleEnabled) {
  31140. me.enableScale();
  31141. var tmpNode = me.editor.document.createElement("span");
  31142. me.editor.body.appendChild(tmpNode);
  31143. me.editor.body.style.height =
  31144. Math.max(
  31145. domUtils.getXY(tmpNode).y,
  31146. me.editor.iframe.offsetHeight - 20
  31147. ) + "px";
  31148. domUtils.remove(tmpNode);
  31149. }
  31150. }
  31151. });
  31152. function move(event) {
  31153. clearSelection();
  31154. var e = event || window.event;
  31155. pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX;
  31156. pageY = e.pageY || doc.documentElement.scrollTop + e.clientY;
  31157. scaleWidth = pageX - position.x;
  31158. scaleHeight = pageY - position.y;
  31159. if (scaleWidth >= minEditorWidth) {
  31160. isMouseMove = true;
  31161. scalelayer.style.width = scaleWidth + "px";
  31162. }
  31163. if (scaleHeight >= minEditorHeight) {
  31164. isMouseMove = true;
  31165. scalelayer.style.height = scaleHeight + "px";
  31166. }
  31167. }
  31168. function up() {
  31169. if (isMouseMove) {
  31170. isMouseMove = false;
  31171. editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
  31172. editorHolder.style.width = editor.ui._actualFrameWidth + "px";
  31173. editor.setHeight(
  31174. scalelayer.offsetHeight -
  31175. bottombar.offsetHeight -
  31176. toolbarBox.offsetHeight -
  31177. 2,
  31178. true
  31179. );
  31180. }
  31181. if (scalelayer) {
  31182. scalelayer.style.display = "none";
  31183. }
  31184. clearSelection();
  31185. domUtils.un(doc, "mousemove", move);
  31186. domUtils.un(editorDocument, "mouseup", up);
  31187. domUtils.un(doc, "mouseup", up);
  31188. }
  31189. function clearSelection() {
  31190. if (browser.ie) doc.selection.clear();
  31191. else window.getSelection().removeAllRanges();
  31192. }
  31193. this.enableScale = function () {
  31194. //trace:2868
  31195. if (editor.queryCommandState("source") == 1) return;
  31196. scale.style.display = "";
  31197. this.scaleEnabled = true;
  31198. domUtils.on(scale, "mousedown", down);
  31199. };
  31200. this.disableScale = function () {
  31201. scale.style.display = "none";
  31202. this.scaleEnabled = false;
  31203. domUtils.un(scale, "mousedown", down);
  31204. };
  31205. },
  31206. isFullScreen: function () {
  31207. return this._fullscreen;
  31208. },
  31209. postRender: function () {
  31210. UIBase.prototype.postRender.call(this);
  31211. for (var i = 0; i < this.toolbars.length; i++) {
  31212. this.toolbars[i].postRender();
  31213. }
  31214. var me = this;
  31215. var timerId,
  31216. domUtils = baidu.editor.dom.domUtils,
  31217. updateFullScreenTime = function () {
  31218. clearTimeout(timerId);
  31219. timerId = setTimeout(function () {
  31220. me._updateFullScreen();
  31221. });
  31222. };
  31223. domUtils.on(window, "resize", updateFullScreenTime);
  31224. me.addListener("destroy", function () {
  31225. domUtils.un(window, "resize", updateFullScreenTime);
  31226. clearTimeout(timerId);
  31227. });
  31228. },
  31229. showToolbarMsg: function (msg, flag) {
  31230. this.getDom("toolbarmsg_label").innerHTML = msg;
  31231. this.getDom("toolbarmsg").style.display = "";
  31232. //
  31233. if (!flag) {
  31234. var w = this.getDom("upload_dialog");
  31235. w.style.display = "none";
  31236. }
  31237. },
  31238. hideToolbarMsg: function () {
  31239. this.getDom("toolbarmsg").style.display = "none";
  31240. },
  31241. mapUrl: function (url) {
  31242. return url
  31243. ? url.replace("~/", this.editor.options.UEDITOR_HOME_URL || "")
  31244. : "";
  31245. },
  31246. triggerLayout: function () {
  31247. var dom = this.getDom();
  31248. if (dom.style.zoom == "1") {
  31249. dom.style.zoom = "100%";
  31250. } else {
  31251. dom.style.zoom = "1";
  31252. }
  31253. }
  31254. };
  31255. utils.inherits(EditorUI, baidu.editor.ui.UIBase);
  31256. var instances = {};
  31257. UE.ui.Editor = function (options) {
  31258. var editor = new UE.Editor(options);
  31259. editor.options.editor = editor;
  31260. utils.loadFile(document, {
  31261. href:
  31262. editor.options.themePath + editor.options.theme + "/css/neditor.css",
  31263. tag: "link",
  31264. type: "text/css",
  31265. rel: "stylesheet"
  31266. });
  31267. var oldRender = editor.render;
  31268. editor.render = function (holder) {
  31269. if (holder.constructor === String) {
  31270. editor.key = holder;
  31271. instances[holder] = editor;
  31272. }
  31273. utils.domReady(function () {
  31274. editor.langIsReady
  31275. ? renderUI()
  31276. : editor.addListener("langReady", renderUI);
  31277. function renderUI() {
  31278. editor.setOpt({
  31279. labelMap: editor.options.labelMap || editor.getLang("labelMap")
  31280. });
  31281. new EditorUI(editor.options);
  31282. if (holder) {
  31283. if (holder.constructor === String) {
  31284. holder = document.getElementById(holder);
  31285. }
  31286. holder &&
  31287. holder.getAttribute("name") &&
  31288. (editor.options.textarea = holder.getAttribute("name"));
  31289. if (holder && /script|textarea/gi.test(holder.tagName)) {
  31290. var newDiv = document.createElement("div");
  31291. holder.parentNode.insertBefore(newDiv, holder);
  31292. var cont = holder.value || holder.innerHTML;
  31293. editor.options.initialContent = /^[\t\r\n ]*$/.test(cont)
  31294. ? editor.options.initialContent
  31295. : cont
  31296. .replace(/>[\n\r\t]+([ ]{4})+/g, ">")
  31297. .replace(/[\n\r\t]+([ ]{4})+</g, "<")
  31298. .replace(/>[\n\r\t]+</g, "><");
  31299. holder.className && (newDiv.className = holder.className);
  31300. holder.style.cssText &&
  31301. (newDiv.style.cssText = holder.style.cssText);
  31302. if (/textarea/i.test(holder.tagName)) {
  31303. editor.textarea = holder;
  31304. editor.textarea.style.display = "none";
  31305. } else {
  31306. holder.parentNode.removeChild(holder);
  31307. }
  31308. if (holder.id) {
  31309. newDiv.id = holder.id;
  31310. domUtils.removeAttributes(holder, "id");
  31311. }
  31312. holder = newDiv;
  31313. holder.innerHTML = "";
  31314. }
  31315. }
  31316. domUtils.addClass(holder, "edui-" + editor.options.theme);
  31317. editor.ui.render(holder);
  31318. var opt = editor.options;
  31319. //给实例添加一个编辑器的容器引用
  31320. editor.container = editor.ui.getDom();
  31321. var parents = domUtils.findParents(holder, true);
  31322. var displays = [];
  31323. for (var i = 0, ci; (ci = parents[i]); i++) {
  31324. displays[i] = ci.style.display;
  31325. ci.style.display = "block";
  31326. }
  31327. if (opt.initialFrameWidth) {
  31328. opt.minFrameWidth = opt.initialFrameWidth;
  31329. } else {
  31330. opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth;
  31331. var styleWidth = holder.style.width;
  31332. if (/%$/.test(styleWidth)) {
  31333. opt.initialFrameWidth = styleWidth;
  31334. }
  31335. }
  31336. if (opt.initialFrameHeight) {
  31337. opt.minFrameHeight = opt.initialFrameHeight;
  31338. } else {
  31339. opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight;
  31340. }
  31341. for (var i = 0, ci; (ci = parents[i]); i++) {
  31342. ci.style.display = displays[i];
  31343. }
  31344. //编辑器最外容器设置了高度,会导致,编辑器不占位
  31345. //todo 先去掉,没有找到原因
  31346. if (holder.style.height) {
  31347. holder.style.height = "";
  31348. }
  31349. editor.container.style.width =
  31350. opt.initialFrameWidth +
  31351. (/%$/.test(opt.initialFrameWidth) ? "" : "px");
  31352. editor.container.style.zIndex = opt.zIndex;
  31353. oldRender.call(editor, editor.ui.getDom("iframeholder"));
  31354. editor.fireEvent("afteruiready");
  31355. }
  31356. });
  31357. };
  31358. return editor;
  31359. };
  31360. /**
  31361. * @file
  31362. * @name UE
  31363. * @short UE
  31364. * @desc UEditor的顶部命名空间
  31365. */
  31366. /**
  31367. * @name getEditor
  31368. * @since 1.2.4+
  31369. * @grammar UE.getEditor(id,[opt]) => Editor实例
  31370. * @desc 提供一个全局的方法得到编辑器实例
  31371. *
  31372. * * ''id'' 放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
  31373. * * ''opt'' 编辑器的可选参数
  31374. * @example
  31375. * UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
  31376. * this.setContent('hello')
  31377. * }});
  31378. * UE.getEditor('containerId'); //返回刚创建的实例
  31379. *
  31380. */
  31381. UE.getEditor = function (id, opt) {
  31382. var editor = instances[id];
  31383. if (!editor) {
  31384. editor = instances[id] = new UE.ui.Editor(opt);
  31385. editor.render(id);
  31386. }
  31387. return editor;
  31388. };
  31389. UE.delEditor = function (id) {
  31390. var editor;
  31391. if ((editor = instances[id])) {
  31392. editor.key && editor.destroy();
  31393. delete instances[id];
  31394. }
  31395. };
  31396. UE.registerUI = function (uiName, fn, index, editorId) {
  31397. utils.each(uiName.split(/\s+/), function (name) {
  31398. baidu.editor.ui[name] = {
  31399. id: editorId,
  31400. execFn: fn,
  31401. index: index
  31402. };
  31403. });
  31404. };
  31405. })();
  31406. // adapter/message.js
  31407. UE.registerUI("message", function (editor) {
  31408. var editorui = baidu.editor.ui;
  31409. var Message = editorui.Message;
  31410. var holder;
  31411. var _messageItems = [];
  31412. var me = editor;
  31413. me.setOpt("enableMessageShow", true);
  31414. if (me.getOpt("enableMessageShow") === false) {
  31415. return;
  31416. }
  31417. me.addListener("ready", function () {
  31418. holder = document.getElementById(me.ui.id + "_message_holder");
  31419. updateHolderPos();
  31420. setTimeout(function () {
  31421. updateHolderPos();
  31422. }, 500);
  31423. });
  31424. me.addListener("showmessage", function (type, opt) {
  31425. opt = utils.isString(opt)
  31426. ? {
  31427. content: opt
  31428. }
  31429. : opt;
  31430. var message = new Message({
  31431. timeout: opt.timeout,
  31432. type: opt.type,
  31433. content: opt.content,
  31434. keepshow: opt.keepshow,
  31435. editor: me
  31436. }),
  31437. mid = opt.id || "msg_" + (+new Date()).toString(36);
  31438. message.render(holder);
  31439. _messageItems[mid] = message;
  31440. message.reset(opt);
  31441. updateHolderPos();
  31442. return mid;
  31443. });
  31444. me.addListener("updatemessage", function (type, id, opt) {
  31445. opt = utils.isString(opt)
  31446. ? {
  31447. content: opt
  31448. }
  31449. : opt;
  31450. var message = _messageItems[id];
  31451. message.render(holder);
  31452. message && message.reset(opt);
  31453. });
  31454. me.addListener("hidemessage", function (type, id) {
  31455. var message = _messageItems[id];
  31456. message && message.hide();
  31457. });
  31458. function updateHolderPos() {
  31459. if (!holder || !me.ui) return;
  31460. var toolbarbox = me.ui.getDom("toolbarbox");
  31461. if (toolbarbox) {
  31462. holder.style.top = toolbarbox.offsetHeight + 3 + "px";
  31463. }
  31464. holder.style.zIndex =
  31465. Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1;
  31466. }
  31467. });
  31468. // adapter/autosave.js
  31469. UE.registerUI("autosave", function (editor) {
  31470. var timer = null,
  31471. uid = null;
  31472. editor.on("afterautosave", function () {
  31473. clearTimeout(timer);
  31474. timer = setTimeout(function () {
  31475. if (uid) {
  31476. editor.trigger("hidemessage", uid);
  31477. }
  31478. uid = editor.trigger("showmessage", {
  31479. content: editor.getLang("autosave.success"),
  31480. timeout: 2000
  31481. });
  31482. }, 2000);
  31483. });
  31484. });
  31485. })();