neditor.all.js 1.0 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067
  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. return function(onready, win) {
  1105. win = win || window;
  1106. var doc = win.document;
  1107. onready && fnArr.push(onready);
  1108. if (doc.readyState === "complete") {
  1109. doReady(doc);
  1110. } else {
  1111. doc.isReady && doReady(doc);
  1112. if (browser.ie && browser.version != 11) {
  1113. (function() {
  1114. if (doc.isReady) return;
  1115. try {
  1116. doc.documentElement.doScroll("left");
  1117. } catch (error) {
  1118. setTimeout(arguments.callee, 0);
  1119. return;
  1120. }
  1121. doReady(doc);
  1122. })();
  1123. win.attachEvent("onload", function() {
  1124. doReady(doc);
  1125. });
  1126. } else {
  1127. doc.addEventListener(
  1128. "DOMContentLoaded",
  1129. function() {
  1130. doc.removeEventListener(
  1131. "DOMContentLoaded",
  1132. arguments.callee,
  1133. false
  1134. );
  1135. doReady(doc);
  1136. },
  1137. false
  1138. );
  1139. win.addEventListener(
  1140. "load",
  1141. function() {
  1142. doReady(doc);
  1143. },
  1144. false
  1145. );
  1146. }
  1147. }
  1148. };
  1149. })(),
  1150. /**
  1151. * 动态添加css样式
  1152. * @method cssRule
  1153. * @param { String } 节点名称
  1154. * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  1155. * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  1156. * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  1157. * @grammar UE.utils.cssRule('body',document) => 返回指定key的样式,并且指定是哪个document
  1158. * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  1159. */
  1160. cssRule: browser.ie && browser.version != 11
  1161. ? function(key, style, doc) {
  1162. var indexList, index;
  1163. if (
  1164. style === undefined ||
  1165. (style && style.nodeType && style.nodeType == 9)
  1166. ) {
  1167. //获取样式
  1168. doc = style && style.nodeType && style.nodeType == 9
  1169. ? style
  1170. : doc || document;
  1171. indexList = doc.indexList || (doc.indexList = {});
  1172. index = indexList[key];
  1173. if (index !== undefined) {
  1174. return doc.styleSheets[index].cssText;
  1175. }
  1176. return undefined;
  1177. }
  1178. doc = doc || document;
  1179. indexList = doc.indexList || (doc.indexList = {});
  1180. index = indexList[key];
  1181. //清除样式
  1182. if (style === "") {
  1183. if (index !== undefined) {
  1184. doc.styleSheets[index].cssText = "";
  1185. delete indexList[key];
  1186. return true;
  1187. }
  1188. return false;
  1189. }
  1190. //添加样式
  1191. if (index !== undefined) {
  1192. sheetStyle = doc.styleSheets[index];
  1193. } else {
  1194. sheetStyle = doc.createStyleSheet(
  1195. "",
  1196. (index = doc.styleSheets.length)
  1197. );
  1198. indexList[key] = index;
  1199. }
  1200. sheetStyle.cssText = style;
  1201. }
  1202. : function(key, style, doc) {
  1203. var head, node;
  1204. if (
  1205. style === undefined ||
  1206. (style && style.nodeType && style.nodeType == 9)
  1207. ) {
  1208. //获取样式
  1209. doc = style && style.nodeType && style.nodeType == 9
  1210. ? style
  1211. : doc || document;
  1212. node = doc.getElementById(key);
  1213. return node ? node.innerHTML : undefined;
  1214. }
  1215. doc = doc || document;
  1216. node = doc.getElementById(key);
  1217. //清除样式
  1218. if (style === "") {
  1219. if (node) {
  1220. node.parentNode.removeChild(node);
  1221. return true;
  1222. }
  1223. return false;
  1224. }
  1225. //添加样式
  1226. if (node) {
  1227. node.innerHTML = style;
  1228. } else {
  1229. node = doc.createElement("style");
  1230. node.id = key;
  1231. node.innerHTML = style;
  1232. doc.getElementsByTagName("head")[0].appendChild(node);
  1233. }
  1234. },
  1235. sort: function(array, compareFn) {
  1236. compareFn =
  1237. compareFn ||
  1238. function(item1, item2) {
  1239. return item1.localeCompare(item2);
  1240. };
  1241. for (var i = 0, len = array.length; i < len; i++) {
  1242. for (var j = i, length = array.length; j < length; j++) {
  1243. if (compareFn(array[i], array[j]) > 0) {
  1244. var t = array[i];
  1245. array[i] = array[j];
  1246. array[j] = t;
  1247. }
  1248. }
  1249. }
  1250. return array;
  1251. },
  1252. serializeParam: function(json) {
  1253. var strArr = [];
  1254. for (var i in json) {
  1255. //忽略默认的几个参数
  1256. if (i == "method" || i == "timeout" || i == "async") continue;
  1257. //传递过来的对象和函数不在提交之列
  1258. if (
  1259. !(
  1260. (typeof json[i]).toLowerCase() == "function" ||
  1261. (typeof json[i]).toLowerCase() == "object"
  1262. )
  1263. ) {
  1264. strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]));
  1265. } else if (utils.isArray(json[i])) {
  1266. //支持传数组内容
  1267. for (var j = 0; j < json[i].length; j++) {
  1268. strArr.push(
  1269. encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])
  1270. );
  1271. }
  1272. }
  1273. }
  1274. return strArr.join("&");
  1275. },
  1276. formatUrl: function(url) {
  1277. var u = url.replace(/&&/g, "&");
  1278. u = u.replace(/\?&/g, "?");
  1279. u = u.replace(/&$/g, "");
  1280. u = u.replace(/&#/g, "#");
  1281. u = u.replace(/&+/g, "&");
  1282. return u;
  1283. },
  1284. isCrossDomainUrl: function(url) {
  1285. var a = document.createElement("a");
  1286. a.href = url;
  1287. if (browser.ie) {
  1288. a.href = a.href;
  1289. }
  1290. return !(
  1291. a.protocol == location.protocol &&
  1292. a.hostname == location.hostname &&
  1293. (a.port == location.port ||
  1294. (a.port == "80" && location.port == "") ||
  1295. (a.port == "" && location.port == "80"))
  1296. );
  1297. },
  1298. clearEmptyAttrs: function(obj) {
  1299. for (var p in obj) {
  1300. if (obj[p] === "") {
  1301. delete obj[p];
  1302. }
  1303. }
  1304. return obj;
  1305. },
  1306. str2json: function(s) {
  1307. if (!utils.isString(s)) return null;
  1308. if (window.JSON) {
  1309. return JSON.parse(s);
  1310. } else {
  1311. return new Function("return " + utils.trim(s || ""))();
  1312. }
  1313. },
  1314. json2str: (function() {
  1315. if (window.JSON) {
  1316. return JSON.stringify;
  1317. } else {
  1318. var escapeMap = {
  1319. "\b": "\\b",
  1320. "\t": "\\t",
  1321. "\n": "\\n",
  1322. "\f": "\\f",
  1323. "\r": "\\r",
  1324. '"': '\\"',
  1325. "\\": "\\\\"
  1326. };
  1327. function encodeString(source) {
  1328. if (/["\\\x00-\x1f]/.test(source)) {
  1329. source = source.replace(/["\\\x00-\x1f]/g, function(match) {
  1330. var c = escapeMap[match];
  1331. if (c) {
  1332. return c;
  1333. }
  1334. c = match.charCodeAt();
  1335. return (
  1336. "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16)
  1337. );
  1338. });
  1339. }
  1340. return '"' + source + '"';
  1341. }
  1342. function encodeArray(source) {
  1343. var result = ["["],
  1344. l = source.length,
  1345. preComma,
  1346. i,
  1347. item;
  1348. for (i = 0; i < l; i++) {
  1349. item = source[i];
  1350. switch (typeof item) {
  1351. case "undefined":
  1352. case "function":
  1353. case "unknown":
  1354. break;
  1355. default:
  1356. if (preComma) {
  1357. result.push(",");
  1358. }
  1359. result.push(utils.json2str(item));
  1360. preComma = 1;
  1361. }
  1362. }
  1363. result.push("]");
  1364. return result.join("");
  1365. }
  1366. function pad(source) {
  1367. return source < 10 ? "0" + source : source;
  1368. }
  1369. function encodeDate(source) {
  1370. return (
  1371. '"' +
  1372. source.getFullYear() +
  1373. "-" +
  1374. pad(source.getMonth() + 1) +
  1375. "-" +
  1376. pad(source.getDate()) +
  1377. "T" +
  1378. pad(source.getHours()) +
  1379. ":" +
  1380. pad(source.getMinutes()) +
  1381. ":" +
  1382. pad(source.getSeconds()) +
  1383. '"'
  1384. );
  1385. }
  1386. return function(value) {
  1387. switch (typeof value) {
  1388. case "undefined":
  1389. return "undefined";
  1390. case "number":
  1391. return isFinite(value) ? String(value) : "null";
  1392. case "string":
  1393. return encodeString(value);
  1394. case "boolean":
  1395. return String(value);
  1396. default:
  1397. if (value === null) {
  1398. return "null";
  1399. } else if (utils.isArray(value)) {
  1400. return encodeArray(value);
  1401. } else if (utils.isDate(value)) {
  1402. return encodeDate(value);
  1403. } else {
  1404. var result = ["{"],
  1405. encode = utils.json2str,
  1406. preComma,
  1407. item;
  1408. for (var key in value) {
  1409. if (Object.prototype.hasOwnProperty.call(value, key)) {
  1410. item = value[key];
  1411. switch (typeof item) {
  1412. case "undefined":
  1413. case "unknown":
  1414. case "function":
  1415. break;
  1416. default:
  1417. if (preComma) {
  1418. result.push(",");
  1419. }
  1420. preComma = 1;
  1421. result.push(encode(key) + ":" + encode(item));
  1422. }
  1423. }
  1424. }
  1425. result.push("}");
  1426. return result.join("");
  1427. }
  1428. }
  1429. };
  1430. }
  1431. })()
  1432. });
  1433. /**
  1434. * 判断给定的对象是否是字符串
  1435. * @method isString
  1436. * @param { * } object 需要判断的对象
  1437. * @return { Boolean } 给定的对象是否是字符串
  1438. */
  1439. /**
  1440. * 判断给定的对象是否是数组
  1441. * @method isArray
  1442. * @param { * } object 需要判断的对象
  1443. * @return { Boolean } 给定的对象是否是数组
  1444. */
  1445. /**
  1446. * 判断给定的对象是否是一个Function
  1447. * @method isFunction
  1448. * @param { * } object 需要判断的对象
  1449. * @return { Boolean } 给定的对象是否是Function
  1450. */
  1451. /**
  1452. * 判断给定的对象是否是Number
  1453. * @method isNumber
  1454. * @param { * } object 需要判断的对象
  1455. * @return { Boolean } 给定的对象是否是Number
  1456. */
  1457. /**
  1458. * 判断给定的对象是否是一个正则表达式
  1459. * @method isRegExp
  1460. * @param { * } object 需要判断的对象
  1461. * @return { Boolean } 给定的对象是否是正则表达式
  1462. */
  1463. /**
  1464. * 判断给定的对象是否是一个普通对象
  1465. * @method isObject
  1466. * @param { * } object 需要判断的对象
  1467. * @return { Boolean } 给定的对象是否是普通对象
  1468. */
  1469. utils.each(
  1470. ["String", "Function", "Array", "Number", "RegExp", "Object", "Date"],
  1471. function(v) {
  1472. UE.utils["is" + v] = function(obj) {
  1473. return Object.prototype.toString.apply(obj) == "[object " + v + "]";
  1474. };
  1475. }
  1476. );
  1477. // core/EventBase.js
  1478. /**
  1479. * UE采用的事件基类
  1480. * @file
  1481. * @module UE
  1482. * @class EventBase
  1483. * @since 1.2.6.1
  1484. */
  1485. /**
  1486. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  1487. * @unfile
  1488. * @module UE
  1489. */
  1490. /**
  1491. * UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
  1492. * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
  1493. * @unfile
  1494. * @module UE
  1495. * @class EventBase
  1496. */
  1497. /**
  1498. * 通过此构造器,子类可以继承EventBase获取事件监听的方法
  1499. * @constructor
  1500. * @example
  1501. * ```javascript
  1502. * UE.EventBase.call(editor);
  1503. * ```
  1504. */
  1505. var EventBase = (UE.EventBase = function() {});
  1506. EventBase.prototype = {
  1507. /**
  1508. * 注册事件监听器
  1509. * @method addListener
  1510. * @param { String } types 监听的事件名称,同时监听多个事件使用空格分隔
  1511. * @param { Function } fn 监听的事件被触发时,会执行该回调函数
  1512. * @waining 事件被触发时,监听的函数假如返回的值恒等于true,回调函数的队列中后面的函数将不执行
  1513. * @example
  1514. * ```javascript
  1515. * editor.addListener('selectionchange',function(){
  1516. * console.log("选区已经变化!");
  1517. * })
  1518. * editor.addListener('beforegetcontent aftergetcontent',function(type){
  1519. * if(type == 'beforegetcontent'){
  1520. * //do something
  1521. * }else{
  1522. * //do something
  1523. * }
  1524. * console.log(this.getContent) // this是注册的事件的编辑器实例
  1525. * })
  1526. * ```
  1527. * @see UE.EventBase:fireEvent(String)
  1528. */
  1529. addListener: function(types, listener) {
  1530. types = utils.trim(types).split(/\s+/);
  1531. for (var i = 0, ti; (ti = types[i++]); ) {
  1532. getListener(this, ti, true).push(listener);
  1533. }
  1534. },
  1535. on: function(types, listener) {
  1536. return this.addListener(types, listener);
  1537. },
  1538. off: function(types, listener) {
  1539. return this.removeListener(types, listener);
  1540. },
  1541. trigger: function() {
  1542. return this.fireEvent.apply(this, arguments);
  1543. },
  1544. /**
  1545. * 移除事件监听器
  1546. * @method removeListener
  1547. * @param { String } types 移除的事件名称,同时移除多个事件使用空格分隔
  1548. * @param { Function } fn 移除监听事件的函数引用
  1549. * @example
  1550. * ```javascript
  1551. * //changeCallback为方法体
  1552. * editor.removeListener("selectionchange",changeCallback);
  1553. * ```
  1554. */
  1555. removeListener: function(types, listener) {
  1556. types = utils.trim(types).split(/\s+/);
  1557. for (var i = 0, ti; (ti = types[i++]); ) {
  1558. utils.removeItem(getListener(this, ti) || [], listener);
  1559. }
  1560. },
  1561. /**
  1562. * 触发事件
  1563. * @method fireEvent
  1564. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1565. * @remind 该方法会触发addListener
  1566. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1567. * @example
  1568. * ```javascript
  1569. * editor.fireEvent("selectionchange");
  1570. * ```
  1571. */
  1572. /**
  1573. * 触发事件
  1574. * @method fireEvent
  1575. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1576. * @param { *... } options 可选参数,可以传入一个或多个参数,会传给事件触发的回调函数
  1577. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1578. * @example
  1579. * ```javascript
  1580. *
  1581. * editor.addListener( "selectionchange", function ( type, arg1, arg2 ) {
  1582. *
  1583. * console.log( arg1 + " " + arg2 );
  1584. *
  1585. * } );
  1586. *
  1587. * //触发selectionchange事件, 会执行上面的事件监听器
  1588. * //output: Hello World
  1589. * editor.fireEvent("selectionchange", "Hello", "World");
  1590. * ```
  1591. */
  1592. fireEvent: function() {
  1593. var types = arguments[0];
  1594. types = utils.trim(types).split(" ");
  1595. for (var i = 0, ti; (ti = types[i++]); ) {
  1596. var listeners = getListener(this, ti),
  1597. r,
  1598. t,
  1599. k;
  1600. if (listeners) {
  1601. k = listeners.length;
  1602. while (k--) {
  1603. if (!listeners[k]) continue;
  1604. t = listeners[k].apply(this, arguments);
  1605. if (t === true) {
  1606. return t;
  1607. }
  1608. if (t !== undefined) {
  1609. r = t;
  1610. }
  1611. }
  1612. }
  1613. if ((t = this["on" + ti.toLowerCase()])) {
  1614. r = t.apply(this, arguments);
  1615. }
  1616. }
  1617. return r;
  1618. }
  1619. };
  1620. /**
  1621. * 获得对象所拥有监听类型的所有监听器
  1622. * @unfile
  1623. * @module UE
  1624. * @since 1.2.6.1
  1625. * @method getListener
  1626. * @public
  1627. * @param { Object } obj 查询监听器的对象
  1628. * @param { String } type 事件类型
  1629. * @param { Boolean } force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  1630. * @return { Array } 监听器数组
  1631. */
  1632. function getListener(obj, type, force) {
  1633. var allListeners;
  1634. type = type.toLowerCase();
  1635. return (
  1636. (allListeners =
  1637. obj.__allListeners || (force && (obj.__allListeners = {}))) &&
  1638. (allListeners[type] || (force && (allListeners[type] = [])))
  1639. );
  1640. }
  1641. // core/dtd.js
  1642. ///import editor.js
  1643. ///import core/dom/dom.js
  1644. ///import core/utils.js
  1645. /**
  1646. * dtd html语义化的体现类
  1647. * @constructor
  1648. * @namespace dtd
  1649. */
  1650. var dtd = (dom.dtd = (function() {
  1651. function _(s) {
  1652. for (var k in s) {
  1653. s[k.toUpperCase()] = s[k];
  1654. }
  1655. return s;
  1656. }
  1657. var X = utils.extend2;
  1658. var A = _({ isindex: 1, fieldset: 1 }),
  1659. B = _({ input: 1, button: 1, select: 1, textarea: 1, label: 1 }),
  1660. C = X(_({ a: 1 }), B),
  1661. D = X({ iframe: 1 }, C),
  1662. E = _({
  1663. hr: 1,
  1664. ul: 1,
  1665. menu: 1,
  1666. div: 1,
  1667. blockquote: 1,
  1668. noscript: 1,
  1669. table: 1,
  1670. center: 1,
  1671. address: 1,
  1672. dir: 1,
  1673. pre: 1,
  1674. h5: 1,
  1675. dl: 1,
  1676. h4: 1,
  1677. noframes: 1,
  1678. h6: 1,
  1679. ol: 1,
  1680. h1: 1,
  1681. h3: 1,
  1682. h2: 1
  1683. }),
  1684. F = _({ ins: 1, del: 1, script: 1, style: 1 }),
  1685. G = X(
  1686. _({
  1687. mark: 1,
  1688. b: 1,
  1689. acronym: 1,
  1690. bdo: 1,
  1691. var: 1,
  1692. "#": 1,
  1693. abbr: 1,
  1694. code: 1,
  1695. br: 1,
  1696. i: 1,
  1697. cite: 1,
  1698. kbd: 1,
  1699. u: 1,
  1700. strike: 1,
  1701. s: 1,
  1702. tt: 1,
  1703. strong: 1,
  1704. q: 1,
  1705. samp: 1,
  1706. em: 1,
  1707. dfn: 1,
  1708. span: 1
  1709. }),
  1710. F
  1711. ),
  1712. H = X(
  1713. _({
  1714. sub: 1,
  1715. img: 1,
  1716. embed: 1,
  1717. object: 1,
  1718. sup: 1,
  1719. basefont: 1,
  1720. map: 1,
  1721. applet: 1,
  1722. font: 1,
  1723. big: 1,
  1724. small: 1
  1725. }),
  1726. G
  1727. ),
  1728. I = X(_({ p: 1 }), H),
  1729. J = X(_({ iframe: 1 }), H, B),
  1730. K = _({
  1731. img: 1,
  1732. embed: 1,
  1733. noscript: 1,
  1734. br: 1,
  1735. kbd: 1,
  1736. center: 1,
  1737. button: 1,
  1738. basefont: 1,
  1739. h5: 1,
  1740. h4: 1,
  1741. samp: 1,
  1742. h6: 1,
  1743. ol: 1,
  1744. h1: 1,
  1745. h3: 1,
  1746. h2: 1,
  1747. form: 1,
  1748. font: 1,
  1749. "#": 1,
  1750. select: 1,
  1751. menu: 1,
  1752. ins: 1,
  1753. abbr: 1,
  1754. label: 1,
  1755. code: 1,
  1756. table: 1,
  1757. script: 1,
  1758. cite: 1,
  1759. input: 1,
  1760. iframe: 1,
  1761. strong: 1,
  1762. textarea: 1,
  1763. noframes: 1,
  1764. big: 1,
  1765. small: 1,
  1766. span: 1,
  1767. hr: 1,
  1768. sub: 1,
  1769. bdo: 1,
  1770. var: 1,
  1771. div: 1,
  1772. object: 1,
  1773. sup: 1,
  1774. strike: 1,
  1775. dir: 1,
  1776. map: 1,
  1777. dl: 1,
  1778. applet: 1,
  1779. del: 1,
  1780. isindex: 1,
  1781. fieldset: 1,
  1782. ul: 1,
  1783. b: 1,
  1784. acronym: 1,
  1785. a: 1,
  1786. blockquote: 1,
  1787. i: 1,
  1788. u: 1,
  1789. s: 1,
  1790. tt: 1,
  1791. address: 1,
  1792. q: 1,
  1793. pre: 1,
  1794. p: 1,
  1795. em: 1,
  1796. dfn: 1
  1797. }),
  1798. L = X(_({ a: 0 }), J), //a不能被切开,所以把他
  1799. M = _({ tr: 1 }),
  1800. N = _({ "#": 1 }),
  1801. O = X(_({ param: 1 }), K),
  1802. P = X(_({ form: 1 }), A, D, E, I),
  1803. Q = _({ li: 1, ol: 1, ul: 1 }),
  1804. R = _({ style: 1, script: 1 }),
  1805. S = _({ base: 1, link: 1, meta: 1, title: 1 }),
  1806. T = X(S, R),
  1807. U = _({ head: 1, body: 1 }),
  1808. V = _({ html: 1 });
  1809. var block = _({
  1810. address: 1,
  1811. blockquote: 1,
  1812. center: 1,
  1813. dir: 1,
  1814. div: 1,
  1815. dl: 1,
  1816. fieldset: 1,
  1817. form: 1,
  1818. h1: 1,
  1819. h2: 1,
  1820. h3: 1,
  1821. h4: 1,
  1822. h5: 1,
  1823. h6: 1,
  1824. hr: 1,
  1825. isindex: 1,
  1826. menu: 1,
  1827. noframes: 1,
  1828. ol: 1,
  1829. p: 1,
  1830. pre: 1,
  1831. table: 1,
  1832. ul: 1
  1833. }),
  1834. empty = _({
  1835. area: 1,
  1836. base: 1,
  1837. basefont: 1,
  1838. br: 1,
  1839. col: 1,
  1840. command: 1,
  1841. dialog: 1,
  1842. embed: 1,
  1843. hr: 1,
  1844. img: 1,
  1845. input: 1,
  1846. isindex: 1,
  1847. keygen: 1,
  1848. link: 1,
  1849. meta: 1,
  1850. param: 1,
  1851. source: 1,
  1852. track: 1,
  1853. wbr: 1
  1854. });
  1855. return _({
  1856. // $ 表示自定的属性
  1857. // body外的元素列表.
  1858. $nonBodyContent: X(V, U, S),
  1859. //块结构元素列表
  1860. $block: block,
  1861. //内联元素列表
  1862. $inline: L,
  1863. $inlineWithA: X(_({ a: 1 }), L),
  1864. $body: X(_({ script: 1, style: 1 }), block),
  1865. $cdata: _({ script: 1, style: 1 }),
  1866. //自闭和元素
  1867. $empty: empty,
  1868. //不是自闭合,但不能让range选中里边
  1869. $nonChild: _({ iframe: 1, textarea: 1 }),
  1870. //列表元素列表
  1871. $listItem: _({ dd: 1, dt: 1, li: 1 }),
  1872. //列表根元素列表
  1873. $list: _({ ul: 1, ol: 1, dl: 1 }),
  1874. //不能认为是空的元素
  1875. $isNotEmpty: _({
  1876. table: 1,
  1877. ul: 1,
  1878. ol: 1,
  1879. dl: 1,
  1880. iframe: 1,
  1881. area: 1,
  1882. base: 1,
  1883. col: 1,
  1884. hr: 1,
  1885. img: 1,
  1886. embed: 1,
  1887. input: 1,
  1888. textarea: 1,
  1889. link: 1,
  1890. meta: 1,
  1891. param: 1,
  1892. h1: 1,
  1893. h2: 1,
  1894. h3: 1,
  1895. h4: 1,
  1896. h5: 1,
  1897. h6: 1
  1898. }),
  1899. //如果没有子节点就可以删除的元素列表,像span,a
  1900. $removeEmpty: _({
  1901. a: 1,
  1902. abbr: 1,
  1903. acronym: 1,
  1904. address: 1,
  1905. b: 1,
  1906. bdo: 1,
  1907. big: 1,
  1908. cite: 1,
  1909. code: 1,
  1910. del: 1,
  1911. dfn: 1,
  1912. em: 1,
  1913. font: 1,
  1914. i: 1,
  1915. ins: 1,
  1916. label: 1,
  1917. kbd: 1,
  1918. q: 1,
  1919. s: 1,
  1920. samp: 1,
  1921. small: 1,
  1922. span: 1,
  1923. strike: 1,
  1924. strong: 1,
  1925. sub: 1,
  1926. sup: 1,
  1927. tt: 1,
  1928. u: 1,
  1929. var: 1
  1930. }),
  1931. $removeEmptyBlock: _({ p: 1, div: 1 }),
  1932. //在table元素里的元素列表
  1933. $tableContent: _({
  1934. caption: 1,
  1935. col: 1,
  1936. colgroup: 1,
  1937. tbody: 1,
  1938. td: 1,
  1939. tfoot: 1,
  1940. th: 1,
  1941. thead: 1,
  1942. tr: 1,
  1943. table: 1
  1944. }),
  1945. //不转换的标签
  1946. $notTransContent: _({ pre: 1, script: 1, style: 1, textarea: 1 }),
  1947. html: U,
  1948. head: T,
  1949. style: N,
  1950. script: N,
  1951. body: P,
  1952. base: {},
  1953. link: {},
  1954. meta: {},
  1955. title: N,
  1956. col: {},
  1957. tr: _({ td: 1, th: 1 }),
  1958. img: {},
  1959. embed: {},
  1960. colgroup: _({ thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1 }),
  1961. noscript: P,
  1962. td: P,
  1963. br: {},
  1964. th: P,
  1965. center: P,
  1966. kbd: L,
  1967. button: X(I, E),
  1968. basefont: {},
  1969. h5: L,
  1970. h4: L,
  1971. samp: L,
  1972. h6: L,
  1973. ol: Q,
  1974. h1: L,
  1975. h3: L,
  1976. option: N,
  1977. h2: L,
  1978. form: X(A, D, E, I),
  1979. select: _({ optgroup: 1, option: 1 }),
  1980. font: L,
  1981. ins: L,
  1982. menu: Q,
  1983. abbr: L,
  1984. label: L,
  1985. table: _({
  1986. thead: 1,
  1987. col: 1,
  1988. tbody: 1,
  1989. tr: 1,
  1990. colgroup: 1,
  1991. caption: 1,
  1992. tfoot: 1
  1993. }),
  1994. code: L,
  1995. tfoot: M,
  1996. cite: L,
  1997. li: P,
  1998. input: {},
  1999. iframe: P,
  2000. strong: L,
  2001. textarea: N,
  2002. noframes: P,
  2003. big: L,
  2004. small: L,
  2005. //trace:
  2006. span: _({
  2007. "#": 1,
  2008. br: 1,
  2009. b: 1,
  2010. strong: 1,
  2011. u: 1,
  2012. i: 1,
  2013. em: 1,
  2014. sub: 1,
  2015. sup: 1,
  2016. strike: 1,
  2017. span: 1
  2018. }),
  2019. hr: L,
  2020. dt: L,
  2021. sub: L,
  2022. optgroup: _({ option: 1 }),
  2023. param: {},
  2024. bdo: L,
  2025. var: L,
  2026. div: P,
  2027. object: O,
  2028. sup: L,
  2029. dd: P,
  2030. strike: L,
  2031. area: {},
  2032. dir: Q,
  2033. map: X(_({ area: 1, form: 1, p: 1 }), A, F, E),
  2034. applet: O,
  2035. dl: _({ dt: 1, dd: 1 }),
  2036. del: L,
  2037. isindex: {},
  2038. fieldset: X(_({ legend: 1 }), K),
  2039. thead: M,
  2040. ul: Q,
  2041. acronym: L,
  2042. b: L,
  2043. a: X(_({ a: 1 }), J),
  2044. blockquote: X(_({ td: 1, tr: 1, tbody: 1, li: 1 }), P),
  2045. caption: L,
  2046. i: L,
  2047. u: L,
  2048. tbody: M,
  2049. s: L,
  2050. address: X(D, I),
  2051. tt: L,
  2052. legend: L,
  2053. q: L,
  2054. pre: X(G, C),
  2055. p: X(_({ a: 1 }), L),
  2056. em: L,
  2057. dfn: L,
  2058. mark: L
  2059. });
  2060. })());
  2061. // core/domUtils.js
  2062. /**
  2063. * Dom操作工具包
  2064. * @file
  2065. * @module UE.dom.domUtils
  2066. * @since 1.2.6.1
  2067. */
  2068. /**
  2069. * Dom操作工具包
  2070. * @unfile
  2071. * @module UE.dom.domUtils
  2072. */
  2073. function getDomNode(node, start, ltr, startFromChild, fn, guard) {
  2074. var tmpNode = startFromChild && node[start],
  2075. parent;
  2076. !tmpNode && (tmpNode = node[ltr]);
  2077. while (!tmpNode && (parent = (parent || node).parentNode)) {
  2078. if (parent.tagName == "BODY" || (guard && !guard(parent))) {
  2079. return null;
  2080. }
  2081. tmpNode = parent[ltr];
  2082. }
  2083. if (tmpNode && fn && !fn(tmpNode)) {
  2084. return getDomNode(tmpNode, start, ltr, false, fn);
  2085. }
  2086. return tmpNode;
  2087. }
  2088. var attrFix = ie && browser.version < 9
  2089. ? {
  2090. tabindex: "tabIndex",
  2091. readonly: "readOnly",
  2092. for: "htmlFor",
  2093. class: "className",
  2094. maxlength: "maxLength",
  2095. cellspacing: "cellSpacing",
  2096. cellpadding: "cellPadding",
  2097. rowspan: "rowSpan",
  2098. colspan: "colSpan",
  2099. usemap: "useMap",
  2100. frameborder: "frameBorder"
  2101. }
  2102. : {
  2103. tabindex: "tabIndex",
  2104. readonly: "readOnly"
  2105. },
  2106. styleBlock = utils.listToMap([
  2107. "-webkit-box",
  2108. "-moz-box",
  2109. "block",
  2110. "list-item",
  2111. "table",
  2112. "table-row-group",
  2113. "table-header-group",
  2114. "table-footer-group",
  2115. "table-row",
  2116. "table-column-group",
  2117. "table-column",
  2118. "table-cell",
  2119. "table-caption"
  2120. ]);
  2121. var domUtils = (dom.domUtils = {
  2122. //节点常量
  2123. NODE_ELEMENT: 1,
  2124. NODE_DOCUMENT: 9,
  2125. NODE_TEXT: 3,
  2126. NODE_COMMENT: 8,
  2127. NODE_DOCUMENT_FRAGMENT: 11,
  2128. //位置关系
  2129. POSITION_IDENTICAL: 0,
  2130. POSITION_DISCONNECTED: 1,
  2131. POSITION_FOLLOWING: 2,
  2132. POSITION_PRECEDING: 4,
  2133. POSITION_IS_CONTAINED: 8,
  2134. POSITION_CONTAINS: 16,
  2135. //ie6使用其他的会有一段空白出现
  2136. fillChar: ie && browser.version == "6" ? "\ufeff" : "\u200B",
  2137. //-------------------------Node部分--------------------------------
  2138. keys: {
  2139. /*Backspace*/ 8: 1,
  2140. /*Delete*/ 46: 1,
  2141. /*Shift*/ 16: 1,
  2142. /*Ctrl*/ 17: 1,
  2143. /*Alt*/ 18: 1,
  2144. 37: 1,
  2145. 38: 1,
  2146. 39: 1,
  2147. 40: 1,
  2148. 13: 1 /*enter*/
  2149. },
  2150. /**
  2151. * 获取节点A相对于节点B的位置关系
  2152. * @method getPosition
  2153. * @param { Node } nodeA 需要查询位置关系的节点A
  2154. * @param { Node } nodeB 需要查询位置关系的节点B
  2155. * @return { Number } 节点A与节点B的关系
  2156. * @example
  2157. * ```javascript
  2158. * //output: 20
  2159. * var position = UE.dom.domUtils.getPosition( document.documentElement, document.body );
  2160. *
  2161. * switch ( position ) {
  2162. *
  2163. * //0
  2164. * case UE.dom.domUtils.POSITION_IDENTICAL:
  2165. * console.log('元素相同');
  2166. * break;
  2167. * //1
  2168. * case UE.dom.domUtils.POSITION_DISCONNECTED:
  2169. * console.log('两个节点在不同的文档中');
  2170. * break;
  2171. * //2
  2172. * case UE.dom.domUtils.POSITION_FOLLOWING:
  2173. * console.log('节点A在节点B之后');
  2174. * break;
  2175. * //4
  2176. * case UE.dom.domUtils.POSITION_PRECEDING;
  2177. * console.log('节点A在节点B之前');
  2178. * break;
  2179. * //8
  2180. * case UE.dom.domUtils.POSITION_IS_CONTAINED:
  2181. * console.log('节点A被节点B包含');
  2182. * break;
  2183. * case 10:
  2184. * console.log('节点A被节点B包含且节点A在节点B之后');
  2185. * break;
  2186. * //16
  2187. * case UE.dom.domUtils.POSITION_CONTAINS:
  2188. * console.log('节点A包含节点B');
  2189. * break;
  2190. * case 20:
  2191. * console.log('节点A包含节点B且节点A在节点B之前');
  2192. * break;
  2193. *
  2194. * }
  2195. * ```
  2196. */
  2197. getPosition: function(nodeA, nodeB) {
  2198. // 如果两个节点是同一个节点
  2199. if (nodeA === nodeB) {
  2200. // domUtils.POSITION_IDENTICAL
  2201. return 0;
  2202. }
  2203. var node,
  2204. parentsA = [nodeA],
  2205. parentsB = [nodeB];
  2206. node = nodeA;
  2207. while ((node = node.parentNode)) {
  2208. // 如果nodeB是nodeA的祖先节点
  2209. if (node === nodeB) {
  2210. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  2211. return 10;
  2212. }
  2213. parentsA.push(node);
  2214. }
  2215. node = nodeB;
  2216. while ((node = node.parentNode)) {
  2217. // 如果nodeA是nodeB的祖先节点
  2218. if (node === nodeA) {
  2219. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  2220. return 20;
  2221. }
  2222. parentsB.push(node);
  2223. }
  2224. parentsA.reverse();
  2225. parentsB.reverse();
  2226. if (parentsA[0] !== parentsB[0]) {
  2227. // domUtils.POSITION_DISCONNECTED
  2228. return 1;
  2229. }
  2230. var i = -1;
  2231. while ((i++, parentsA[i] === parentsB[i])) {}
  2232. nodeA = parentsA[i];
  2233. nodeB = parentsB[i];
  2234. while ((nodeA = nodeA.nextSibling)) {
  2235. if (nodeA === nodeB) {
  2236. // domUtils.POSITION_PRECEDING
  2237. return 4;
  2238. }
  2239. }
  2240. // domUtils.POSITION_FOLLOWING
  2241. return 2;
  2242. },
  2243. /**
  2244. * 检测节点node在父节点中的索引位置
  2245. * @method getNodeIndex
  2246. * @param { Node } node 需要检测的节点对象
  2247. * @return { Number } 该节点在父节点中的位置
  2248. * @see UE.dom.domUtils.getNodeIndex(Node,Boolean)
  2249. */
  2250. /**
  2251. * 检测节点node在父节点中的索引位置, 根据给定的mergeTextNode参数决定是否要合并多个连续的文本节点为一个节点
  2252. * @method getNodeIndex
  2253. * @param { Node } node 需要检测的节点对象
  2254. * @param { Boolean } mergeTextNode 是否合并多个连续的文本节点为一个节点
  2255. * @return { Number } 该节点在父节点中的位置
  2256. * @example
  2257. * ```javascript
  2258. *
  2259. * var node = document.createElement("div");
  2260. *
  2261. * node.appendChild( document.createTextNode( "hello" ) );
  2262. * node.appendChild( document.createTextNode( "world" ) );
  2263. * node.appendChild( node = document.createElement( "div" ) );
  2264. *
  2265. * //output: 2
  2266. * console.log( UE.dom.domUtils.getNodeIndex( node ) );
  2267. *
  2268. * //output: 1
  2269. * console.log( UE.dom.domUtils.getNodeIndex( node, true ) );
  2270. *
  2271. * ```
  2272. */
  2273. getNodeIndex: function(node, ignoreTextNode) {
  2274. var preNode = node,
  2275. i = 0;
  2276. while ((preNode = preNode.previousSibling)) {
  2277. if (ignoreTextNode && preNode.nodeType == 3) {
  2278. if (preNode.nodeType != preNode.nextSibling.nodeType) {
  2279. i++;
  2280. }
  2281. continue;
  2282. }
  2283. i++;
  2284. }
  2285. return i;
  2286. },
  2287. /**
  2288. * 检测节点node是否在给定的document对象上
  2289. * @method inDoc
  2290. * @param { Node } node 需要检测的节点对象
  2291. * @param { DomDocument } doc 需要检测的document对象
  2292. * @return { Boolean } 该节点node是否在给定的document的dom树上
  2293. * @example
  2294. * ```javascript
  2295. *
  2296. * var node = document.createElement("div");
  2297. *
  2298. * //output: false
  2299. * console.log( UE.do.domUtils.inDoc( node, document ) );
  2300. *
  2301. * document.body.appendChild( node );
  2302. *
  2303. * //output: true
  2304. * console.log( UE.do.domUtils.inDoc( node, document ) );
  2305. *
  2306. * ```
  2307. */
  2308. inDoc: function(node, doc) {
  2309. return domUtils.getPosition(node, doc) == 10;
  2310. },
  2311. /**
  2312. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  2313. * 查找的起点是给定node节点的父节点。
  2314. * @method findParent
  2315. * @param { Node } node 需要查找的节点
  2316. * @param { Function } filterFn 自定义的过滤方法。
  2317. * @warning 查找的终点是到body节点为止
  2318. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  2319. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  2320. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  2321. * @example
  2322. * ```javascript
  2323. * var filterNode = UE.dom.domUtils.findParent( document.body.firstChild, function ( node ) {
  2324. *
  2325. * //由于查找的终点是body节点, 所以永远也不会匹配当前过滤器的条件, 即这里永远会返回false
  2326. * return node.tagName === "HTML";
  2327. *
  2328. * } );
  2329. *
  2330. * //output: true
  2331. * console.log( filterNode === null );
  2332. * ```
  2333. */
  2334. /**
  2335. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  2336. * 如果includeSelf的值为true,则查找的起点是给定的节点node, 否则, 起点是node的父节点
  2337. * @method findParent
  2338. * @param { Node } node 需要查找的节点
  2339. * @param { Function } filterFn 自定义的过滤方法。
  2340. * @param { Boolean } includeSelf 查找过程是否包含自身
  2341. * @warning 查找的终点是到body节点为止
  2342. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  2343. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  2344. * @remind 如果includeSelf为true, 则过滤器第一次执行时的参数会是节点本身。
  2345. * 反之, 过滤器第一次执行时的参数将是该节点的父节点。
  2346. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  2347. * @example
  2348. * ```html
  2349. * <body>
  2350. *
  2351. * <div id="test">
  2352. * </div>
  2353. *
  2354. * <script type="text/javascript">
  2355. *
  2356. * //output: DIV, BODY
  2357. * var filterNode = UE.dom.domUtils.findParent( document.getElementById( "test" ), function ( node ) {
  2358. *
  2359. * console.log( node.tagName );
  2360. * return false;
  2361. *
  2362. * }, true );
  2363. *
  2364. * </script>
  2365. * </body>
  2366. * ```
  2367. */
  2368. findParent: function(node, filterFn, includeSelf) {
  2369. if (node && !domUtils.isBody(node)) {
  2370. node = includeSelf ? node : node.parentNode;
  2371. while (node) {
  2372. if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
  2373. return filterFn && !filterFn(node) && domUtils.isBody(node)
  2374. ? null
  2375. : node;
  2376. }
  2377. node = node.parentNode;
  2378. }
  2379. }
  2380. return null;
  2381. },
  2382. /**
  2383. * 查找node的节点名为tagName的第一个祖先节点, 查找的起点是node节点的父节点。
  2384. * @method findParentByTagName
  2385. * @param { Node } node 需要查找的节点对象
  2386. * @param { Array } tagNames 需要查找的父节点的名称数组
  2387. * @warning 查找的终点是到body节点为止
  2388. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2389. * @example
  2390. * ```javascript
  2391. * var node = UE.dom.domUtils.findParentByTagName( document.getElementsByTagName("div")[0], [ "BODY" ] );
  2392. * //output: BODY
  2393. * console.log( node.tagName );
  2394. * ```
  2395. */
  2396. /**
  2397. * 查找node的节点名为tagName的祖先节点, 如果includeSelf的值为true,则查找的起点是给定的节点node,
  2398. * 否则, 起点是node的父节点。
  2399. * @method findParentByTagName
  2400. * @param { Node } node 需要查找的节点对象
  2401. * @param { Array } tagNames 需要查找的父节点的名称数组
  2402. * @param { Boolean } includeSelf 查找过程是否包含node节点自身
  2403. * @warning 查找的终点是到body节点为止
  2404. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2405. * @example
  2406. * ```javascript
  2407. * var queryTarget = document.getElementsByTagName("div")[0];
  2408. * var node = UE.dom.domUtils.findParentByTagName( queryTarget, [ "DIV" ], true );
  2409. * //output: true
  2410. * console.log( queryTarget === node );
  2411. * ```
  2412. */
  2413. findParentByTagName: function(node, tagNames, includeSelf, excludeFn) {
  2414. tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
  2415. return domUtils.findParent(
  2416. node,
  2417. function(node) {
  2418. return tagNames[node.tagName] && !(excludeFn && excludeFn(node));
  2419. },
  2420. includeSelf
  2421. );
  2422. },
  2423. /**
  2424. * 查找节点node的祖先节点集合, 查找的起点是给定节点的父节点,结果集中不包含给定的节点。
  2425. * @method findParents
  2426. * @param { Node } node 需要查找的节点对象
  2427. * @return { Array } 给定节点的祖先节点数组
  2428. * @grammar UE.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
  2429. * @grammar UE.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
  2430. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
  2431. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
  2432. */
  2433. /**
  2434. * 查找节点node的祖先节点集合, 如果includeSelf的值为true,
  2435. * 则返回的结果集中允许出现当前给定的节点, 否则, 该节点不会出现在其结果集中。
  2436. * @method findParents
  2437. * @param { Node } node 需要查找的节点对象
  2438. * @param { Boolean } includeSelf 查找的结果中是否允许包含当前查找的节点对象
  2439. * @return { Array } 给定节点的祖先节点数组
  2440. */
  2441. findParents: function(node, includeSelf, filterFn, closerFirst) {
  2442. var parents = includeSelf && ((filterFn && filterFn(node)) || !filterFn)
  2443. ? [node]
  2444. : [];
  2445. while ((node = domUtils.findParent(node, filterFn))) {
  2446. parents.push(node);
  2447. }
  2448. return closerFirst ? parents : parents.reverse();
  2449. },
  2450. /**
  2451. * 在节点node后面插入新节点newNode
  2452. * @method insertAfter
  2453. * @param { Node } node 目标节点
  2454. * @param { Node } newNode 新插入的节点, 该节点将置于目标节点之后
  2455. * @return { Node } 新插入的节点
  2456. */
  2457. insertAfter: function(node, newNode) {
  2458. return node.nextSibling
  2459. ? node.parentNode.insertBefore(newNode, node.nextSibling)
  2460. : node.parentNode.appendChild(newNode);
  2461. },
  2462. /**
  2463. * 删除节点node及其下属的所有节点
  2464. * @method remove
  2465. * @param { Node } node 需要删除的节点对象
  2466. * @return { Node } 返回刚删除的节点对象
  2467. * @example
  2468. * ```html
  2469. * <div id="test">
  2470. * <div id="child">你好</div>
  2471. * </div>
  2472. * <script>
  2473. * UE.dom.domUtils.remove( document.body, false );
  2474. * //output: false
  2475. * console.log( document.getElementById( "child" ) !== null );
  2476. * </script>
  2477. * ```
  2478. */
  2479. /**
  2480. * 删除节点node,并根据keepChildren的值决定是否保留子节点
  2481. * @method remove
  2482. * @param { Node } node 需要删除的节点对象
  2483. * @param { Boolean } keepChildren 是否需要保留子节点
  2484. * @return { Node } 返回刚删除的节点对象
  2485. * @example
  2486. * ```html
  2487. * <div id="test">
  2488. * <div id="child">你好</div>
  2489. * </div>
  2490. * <script>
  2491. * UE.dom.domUtils.remove( document.body, true );
  2492. * //output: true
  2493. * console.log( document.getElementById( "child" ) !== null );
  2494. * </script>
  2495. * ```
  2496. */
  2497. remove: function(node, keepChildren) {
  2498. var parent = node.parentNode,
  2499. child;
  2500. if (parent) {
  2501. if (keepChildren && node.hasChildNodes()) {
  2502. while ((child = node.firstChild)) {
  2503. parent.insertBefore(child, node);
  2504. }
  2505. }
  2506. parent.removeChild(node);
  2507. }
  2508. return node;
  2509. },
  2510. /**
  2511. * 取得node节点的下一个兄弟节点, 如果该节点其后没有兄弟节点, 则递归查找其父节点之后的第一个兄弟节点,
  2512. * 直到找到满足条件的节点或者递归到BODY节点之后才会结束。
  2513. * @method getNextDomNode
  2514. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2515. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2516. * @example
  2517. * ```html
  2518. * <body>
  2519. * <div id="test">
  2520. * <span></span>
  2521. * </div>
  2522. * <i>xxx</i>
  2523. * </body>
  2524. * <script>
  2525. *
  2526. * //output: i节点
  2527. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2528. *
  2529. * </script>
  2530. * ```
  2531. * @example
  2532. * ```html
  2533. * <body>
  2534. * <div>
  2535. * <span></span>
  2536. * <i id="test">xxx</i>
  2537. * </div>
  2538. * <b>xxx</b>
  2539. * </body>
  2540. * <script>
  2541. *
  2542. * //由于id为test的i节点之后没有兄弟节点, 则查找其父节点(div)后面的兄弟节点
  2543. * //output: b节点
  2544. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2545. *
  2546. * </script>
  2547. * ```
  2548. */
  2549. /**
  2550. * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点,
  2551. * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false,
  2552. * 则执行<a href="#UE.dom.domUtils.getNextDomNode(Node)">getNextDomNode(Node node)</a>的查找过程。
  2553. * @method getNextDomNode
  2554. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2555. * @param { Boolean } startFromChild 查找过程是否从其子节点开始
  2556. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2557. * @see UE.dom.domUtils.getNextDomNode(Node)
  2558. */
  2559. getNextDomNode: function(node, startFromChild, filterFn, guard) {
  2560. return getDomNode(
  2561. node,
  2562. "firstChild",
  2563. "nextSibling",
  2564. startFromChild,
  2565. filterFn,
  2566. guard
  2567. );
  2568. },
  2569. getPreDomNode: function(node, startFromChild, filterFn, guard) {
  2570. return getDomNode(
  2571. node,
  2572. "lastChild",
  2573. "previousSibling",
  2574. startFromChild,
  2575. filterFn,
  2576. guard
  2577. );
  2578. },
  2579. /**
  2580. * 检测节点node是否属是UEditor定义的bookmark节点
  2581. * @method isBookmarkNode
  2582. * @private
  2583. * @param { Node } node 需要检测的节点对象
  2584. * @return { Boolean } 是否是bookmark节点
  2585. * @example
  2586. * ```html
  2587. * <span id="_baidu_bookmark_1"></span>
  2588. * <script>
  2589. * var bookmarkNode = document.getElementById("_baidu_bookmark_1");
  2590. * //output: true
  2591. * console.log( UE.dom.domUtils.isBookmarkNode( bookmarkNode ) );
  2592. * </script>
  2593. * ```
  2594. */
  2595. isBookmarkNode: function(node) {
  2596. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id);
  2597. },
  2598. /**
  2599. * 获取节点node所属的window对象
  2600. * @method getWindow
  2601. * @param { Node } node 节点对象
  2602. * @return { Window } 当前节点所属的window对象
  2603. * @example
  2604. * ```javascript
  2605. * //output: true
  2606. * console.log( UE.dom.domUtils.getWindow( document.body ) === window );
  2607. * ```
  2608. */
  2609. getWindow: function(node) {
  2610. var doc = node.ownerDocument || node;
  2611. return doc.defaultView || doc.parentWindow;
  2612. },
  2613. /**
  2614. * 获取离nodeA与nodeB最近的公共的祖先节点
  2615. * @method getCommonAncestor
  2616. * @param { Node } nodeA 第一个节点
  2617. * @param { Node } nodeB 第二个节点
  2618. * @remind 如果给定的两个节点是同一个节点, 将直接返回该节点。
  2619. * @return { Node | NULL } 如果未找到公共节点, 返回NULL, 否则返回最近的公共祖先节点。
  2620. * @example
  2621. * ```javascript
  2622. * var commonAncestor = UE.dom.domUtils.getCommonAncestor( document.body, document.body.firstChild );
  2623. * //output: true
  2624. * console.log( commonAncestor.tagName.toLowerCase() === 'body' );
  2625. * ```
  2626. */
  2627. getCommonAncestor: function(nodeA, nodeB) {
  2628. if (nodeA === nodeB) return nodeA;
  2629. var parentsA = [nodeA],
  2630. parentsB = [nodeB],
  2631. parent = nodeA,
  2632. i = -1;
  2633. while ((parent = parent.parentNode)) {
  2634. if (parent === nodeB) {
  2635. return parent;
  2636. }
  2637. parentsA.push(parent);
  2638. }
  2639. parent = nodeB;
  2640. while ((parent = parent.parentNode)) {
  2641. if (parent === nodeA) return parent;
  2642. parentsB.push(parent);
  2643. }
  2644. parentsA.reverse();
  2645. parentsB.reverse();
  2646. while ((i++, parentsA[i] === parentsB[i])) {}
  2647. return i == 0 ? null : parentsA[i - 1];
  2648. },
  2649. /**
  2650. * 清除node节点左右连续为空的兄弟inline节点
  2651. * @method clearEmptySibling
  2652. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2653. * 则这些兄弟节点将被删除
  2654. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
  2655. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
  2656. * @example
  2657. * ```html
  2658. * <body>
  2659. * <div></div>
  2660. * <span id="test"></span>
  2661. * <i></i>
  2662. * <b></b>
  2663. * <em>xxx</em>
  2664. * <span></span>
  2665. * </body>
  2666. * <script>
  2667. *
  2668. * UE.dom.domUtils.clearEmptySibling( document.getElementById( "test" ) );
  2669. *
  2670. * //output: <div></div><span id="test"></span><em>xxx</em><span></span>
  2671. * console.log( document.body.innerHTML );
  2672. *
  2673. * </script>
  2674. * ```
  2675. */
  2676. /**
  2677. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2678. * 则忽略对右边兄弟节点的操作。
  2679. * @method clearEmptySibling
  2680. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2681. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2682. * 则这些兄弟节点将被删除
  2683. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2684. */
  2685. /**
  2686. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2687. * 则忽略对右边兄弟节点的操作, 如果ignorePre的值为true,则忽略对左边兄弟节点的操作。
  2688. * @method clearEmptySibling
  2689. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2690. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2691. * @param { Boolean } ignorePre 是否忽略忽略对左边的兄弟节点的操作
  2692. * 则这些兄弟节点将被删除
  2693. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2694. */
  2695. clearEmptySibling: function(node, ignoreNext, ignorePre) {
  2696. function clear(next, dir) {
  2697. var tmpNode;
  2698. while (
  2699. next &&
  2700. !domUtils.isBookmarkNode(next) &&
  2701. (domUtils.isEmptyInlineElement(next) ||
  2702. //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
  2703. !new RegExp("[^\t\n\r" + domUtils.fillChar + "]").test(
  2704. next.nodeValue
  2705. ))
  2706. ) {
  2707. tmpNode = next[dir];
  2708. domUtils.remove(next);
  2709. next = tmpNode;
  2710. }
  2711. }
  2712. !ignoreNext && clear(node.nextSibling, "nextSibling");
  2713. !ignorePre && clear(node.previousSibling, "previousSibling");
  2714. },
  2715. /**
  2716. * 将一个文本节点textNode拆分成两个文本节点,offset指定拆分位置
  2717. * @method split
  2718. * @param { Node } textNode 需要拆分的文本节点对象
  2719. * @param { int } offset 需要拆分的位置, 位置计算从0开始
  2720. * @return { Node } 拆分后形成的新节点
  2721. * @example
  2722. * ```html
  2723. * <div id="test">abcdef</div>
  2724. * <script>
  2725. * var newNode = UE.dom.domUtils.split( document.getElementById( "test" ).firstChild, 3 );
  2726. * //output: def
  2727. * console.log( newNode.nodeValue );
  2728. * </script>
  2729. * ```
  2730. */
  2731. split: function(node, offset) {
  2732. var doc = node.ownerDocument;
  2733. if (browser.ie && offset == node.nodeValue.length) {
  2734. var next = doc.createTextNode("");
  2735. return domUtils.insertAfter(node, next);
  2736. }
  2737. var retval = node.splitText(offset);
  2738. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  2739. if (browser.ie8) {
  2740. var tmpNode = doc.createTextNode("");
  2741. domUtils.insertAfter(retval, tmpNode);
  2742. domUtils.remove(tmpNode);
  2743. }
  2744. return retval;
  2745. },
  2746. /**
  2747. * 检测文本节点textNode是否为空节点(包括空格、换行、占位符等字符)
  2748. * @method isWhitespace
  2749. * @param { Node } node 需要检测的节点对象
  2750. * @return { Boolean } 检测的节点是否为空
  2751. * @example
  2752. * ```html
  2753. * <div id="test">
  2754. *
  2755. * </div>
  2756. * <script>
  2757. * //output: true
  2758. * console.log( UE.dom.domUtils.isWhitespace( document.getElementById("test").firstChild ) );
  2759. * </script>
  2760. * ```
  2761. */
  2762. isWhitespace: function(node) {
  2763. return !new RegExp("[^ \t\n\r" + domUtils.fillChar + "]").test(
  2764. node.nodeValue
  2765. );
  2766. },
  2767. /**
  2768. * 获取元素element相对于viewport的位置坐标
  2769. * @method getXY
  2770. * @param { Node } element 需要计算位置的节点对象
  2771. * @return { Object } 返回形如{x:left,y:top}的一个key-value映射对象, 其中键x代表水平偏移距离,
  2772. * y代表垂直偏移距离。
  2773. *
  2774. * @example
  2775. * ```javascript
  2776. * var location = UE.dom.domUtils.getXY( document.getElementById("test") );
  2777. * //output: test的坐标为: 12, 24
  2778. * console.log( 'test的坐标为: ', location.x, ',', location.y );
  2779. * ```
  2780. */
  2781. getXY: function(element) {
  2782. var x = 0,
  2783. y = 0;
  2784. while (element.offsetParent) {
  2785. y += element.offsetTop;
  2786. x += element.offsetLeft;
  2787. element = element.offsetParent;
  2788. }
  2789. return { x: x, y: y };
  2790. },
  2791. /**
  2792. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2793. * @method on
  2794. * @param { Node } element 需要绑定事件的节点对象
  2795. * @param { String } type 绑定的事件类型
  2796. * @param { Function } handler 事件处理器
  2797. * @example
  2798. * ```javascript
  2799. * UE.dom.domUtils.on(document.body,"click",function(e){
  2800. * //e为事件对象,this为被点击元素对戏那个
  2801. * });
  2802. * ```
  2803. */
  2804. /**
  2805. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2806. * @method on
  2807. * @param { Node } element 需要绑定事件的节点对象
  2808. * @param { Array } type 绑定的事件类型数组
  2809. * @param { Function } handler 事件处理器
  2810. * @example
  2811. * ```javascript
  2812. * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
  2813. * //evt为事件对象,this为被点击元素对象
  2814. * });
  2815. * ```
  2816. */
  2817. on: function(element, type, handler) {
  2818. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2819. k = types.length;
  2820. if (k)
  2821. while (k--) {
  2822. type = types[k];
  2823. if (element.addEventListener) {
  2824. element.addEventListener(type, handler, false);
  2825. } else {
  2826. if (!handler._d) {
  2827. handler._d = {
  2828. els: []
  2829. };
  2830. }
  2831. var key = type + handler.toString(),
  2832. index = utils.indexOf(handler._d.els, element);
  2833. if (!handler._d[key] || index == -1) {
  2834. if (index == -1) {
  2835. handler._d.els.push(element);
  2836. }
  2837. if (!handler._d[key]) {
  2838. handler._d[key] = function(evt) {
  2839. return handler.call(evt.srcElement, evt || window.event);
  2840. };
  2841. }
  2842. element.attachEvent("on" + type, handler._d[key]);
  2843. }
  2844. }
  2845. }
  2846. element = null;
  2847. },
  2848. /**
  2849. * 解除DOM事件绑定
  2850. * @method un
  2851. * @param { Node } element 需要解除事件绑定的节点对象
  2852. * @param { String } type 需要接触绑定的事件类型
  2853. * @param { Function } handler 对应的事件处理器
  2854. * @example
  2855. * ```javascript
  2856. * UE.dom.domUtils.un(document.body,"click",function(evt){
  2857. * //evt为事件对象,this为被点击元素对象
  2858. * });
  2859. * ```
  2860. */
  2861. /**
  2862. * 解除DOM事件绑定
  2863. * @method un
  2864. * @param { Node } element 需要解除事件绑定的节点对象
  2865. * @param { Array } type 需要接触绑定的事件类型数组
  2866. * @param { Function } handler 对应的事件处理器
  2867. * @example
  2868. * ```javascript
  2869. * UE.dom.domUtils.un(document.body, ["click","mousedown"],function(evt){
  2870. * //evt为事件对象,this为被点击元素对象
  2871. * });
  2872. * ```
  2873. */
  2874. un: function(element, type, handler) {
  2875. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2876. k = types.length;
  2877. if (k)
  2878. while (k--) {
  2879. type = types[k];
  2880. if (element.removeEventListener) {
  2881. element.removeEventListener(type, handler, false);
  2882. } else {
  2883. var key = type + handler.toString();
  2884. try {
  2885. element.detachEvent(
  2886. "on" + type,
  2887. handler._d ? handler._d[key] : handler
  2888. );
  2889. } catch (e) {}
  2890. if (handler._d && handler._d[key]) {
  2891. var index = utils.indexOf(handler._d.els, element);
  2892. if (index != -1) {
  2893. handler._d.els.splice(index, 1);
  2894. }
  2895. handler._d.els.length == 0 && delete handler._d[key];
  2896. }
  2897. }
  2898. }
  2899. },
  2900. /**
  2901. * 比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值
  2902. * @method isSameElement
  2903. * @param { Node } nodeA 需要比较的节点
  2904. * @param { Node } nodeB 需要比较的节点
  2905. * @return { Boolean } 两个节点是否具有相同的标签名、属性名以及属性值
  2906. * @example
  2907. * ```html
  2908. * <span style="font-size:12px">ssss</span>
  2909. * <span style="font-size:12px">bbbbb</span>
  2910. * <span style="font-size:13px">ssss</span>
  2911. * <span style="font-size:14px">bbbbb</span>
  2912. *
  2913. * <script>
  2914. *
  2915. * var nodes = document.getElementsByTagName( "span" );
  2916. *
  2917. * //output: true
  2918. * console.log( UE.dom.domUtils.isSameElement( nodes[0], nodes[1] ) );
  2919. *
  2920. * //output: false
  2921. * console.log( UE.dom.domUtils.isSameElement( nodes[2], nodes[3] ) );
  2922. *
  2923. * </script>
  2924. * ```
  2925. */
  2926. isSameElement: function(nodeA, nodeB) {
  2927. if (nodeA.tagName != nodeB.tagName) {
  2928. return false;
  2929. }
  2930. var thisAttrs = nodeA.attributes,
  2931. otherAttrs = nodeB.attributes;
  2932. if (!ie && thisAttrs.length != otherAttrs.length) {
  2933. return false;
  2934. }
  2935. var attrA,
  2936. attrB,
  2937. al = 0,
  2938. bl = 0;
  2939. for (var i = 0; (attrA = thisAttrs[i++]); ) {
  2940. if (attrA.nodeName == "style") {
  2941. if (attrA.specified) {
  2942. al++;
  2943. }
  2944. if (domUtils.isSameStyle(nodeA, nodeB)) {
  2945. continue;
  2946. } else {
  2947. return false;
  2948. }
  2949. }
  2950. if (ie) {
  2951. if (attrA.specified) {
  2952. al++;
  2953. attrB = otherAttrs.getNamedItem(attrA.nodeName);
  2954. } else {
  2955. continue;
  2956. }
  2957. } else {
  2958. attrB = nodeB.attributes[attrA.nodeName];
  2959. }
  2960. if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) {
  2961. return false;
  2962. }
  2963. }
  2964. // 有可能attrB的属性包含了attrA的属性之外还有自己的属性
  2965. if (ie) {
  2966. for (i = 0; (attrB = otherAttrs[i++]); ) {
  2967. if (attrB.specified) {
  2968. bl++;
  2969. }
  2970. }
  2971. if (al != bl) {
  2972. return false;
  2973. }
  2974. }
  2975. return true;
  2976. },
  2977. /**
  2978. * 判断节点nodeA与节点nodeB的元素的style属性是否一致
  2979. * @method isSameStyle
  2980. * @param { Node } nodeA 需要比较的节点
  2981. * @param { Node } nodeB 需要比较的节点
  2982. * @return { Boolean } 两个节点是否具有相同的style属性值
  2983. * @example
  2984. * ```html
  2985. * <span style="font-size:12px">ssss</span>
  2986. * <span style="font-size:12px">bbbbb</span>
  2987. * <span style="font-size:13px">ssss</span>
  2988. * <span style="font-size:14px">bbbbb</span>
  2989. *
  2990. * <script>
  2991. *
  2992. * var nodes = document.getElementsByTagName( "span" );
  2993. *
  2994. * //output: true
  2995. * console.log( UE.dom.domUtils.isSameStyle( nodes[0], nodes[1] ) );
  2996. *
  2997. * //output: false
  2998. * console.log( UE.dom.domUtils.isSameStyle( nodes[2], nodes[3] ) );
  2999. *
  3000. * </script>
  3001. * ```
  3002. */
  3003. isSameStyle: function(nodeA, nodeB) {
  3004. var styleA = nodeA.style.cssText
  3005. .replace(/( ?; ?)/g, ";")
  3006. .replace(/( ?: ?)/g, ":"),
  3007. styleB = nodeB.style.cssText
  3008. .replace(/( ?; ?)/g, ";")
  3009. .replace(/( ?: ?)/g, ":");
  3010. if (browser.opera) {
  3011. styleA = nodeA.style;
  3012. styleB = nodeB.style;
  3013. if (styleA.length != styleB.length) return false;
  3014. for (var p in styleA) {
  3015. if (/^(\d+|csstext)$/i.test(p)) {
  3016. continue;
  3017. }
  3018. if (styleA[p] != styleB[p]) {
  3019. return false;
  3020. }
  3021. }
  3022. return true;
  3023. }
  3024. if (!styleA || !styleB) {
  3025. return styleA == styleB;
  3026. }
  3027. styleA = styleA.split(";");
  3028. styleB = styleB.split(";");
  3029. if (styleA.length != styleB.length) {
  3030. return false;
  3031. }
  3032. for (var i = 0, ci; (ci = styleA[i++]); ) {
  3033. if (utils.indexOf(styleB, ci) == -1) {
  3034. return false;
  3035. }
  3036. }
  3037. return true;
  3038. },
  3039. /**
  3040. * 检查节点node是否为block元素
  3041. * @method isBlockElm
  3042. * @param { Node } node 需要检测的节点对象
  3043. * @return { Boolean } 是否是block元素节点
  3044. * @warning 该方法的判断规则如下: 如果该元素原本是block元素, 则不论该元素当前的css样式是什么都会返回true;
  3045. * 否则,检测该元素的css样式, 如果该元素当前是block元素, 则返回true。 其余情况下都返回false。
  3046. * @example
  3047. * ```html
  3048. * <span id="test1" style="display: block"></span>
  3049. * <span id="test2"></span>
  3050. * <div id="test3" style="display: inline"></div>
  3051. *
  3052. * <script>
  3053. *
  3054. * //output: true
  3055. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test1") ) );
  3056. *
  3057. * //output: false
  3058. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test2") ) );
  3059. *
  3060. * //output: true
  3061. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test3") ) );
  3062. *
  3063. * </script>
  3064. * ```
  3065. */
  3066. isBlockElm: function(node) {
  3067. return (
  3068. node.nodeType == 1 &&
  3069. (dtd.$block[node.tagName] ||
  3070. styleBlock[domUtils.getComputedStyle(node, "display")]) &&
  3071. !dtd.$nonChild[node.tagName]
  3072. );
  3073. },
  3074. /**
  3075. * 检测node节点是否为body节点
  3076. * @method isBody
  3077. * @param { Element } node 需要检测的dom元素
  3078. * @return { Boolean } 给定的元素是否是body元素
  3079. * @example
  3080. * ```javascript
  3081. * //output: true
  3082. * console.log( UE.dom.domUtils.isBody( document.body ) );
  3083. * ```
  3084. */
  3085. isBody: function(node) {
  3086. return node && node.nodeType == 1 && node.tagName.toLowerCase() == "body";
  3087. },
  3088. /**
  3089. * 以node节点为分界,将该节点的指定祖先节点parent拆分成两个独立的节点,
  3090. * 拆分形成的两个节点之间是node节点
  3091. * @method breakParent
  3092. * @param { Node } node 作为分界的节点对象
  3093. * @param { Node } parent 该节点必须是node节点的祖先节点, 且是block节点。
  3094. * @return { Node } 给定的node分界节点
  3095. * @example
  3096. * ```javascript
  3097. *
  3098. * var node = document.createElement("span"),
  3099. * wrapNode = document.createElement( "div" ),
  3100. * parent = document.createElement("p");
  3101. *
  3102. * parent.appendChild( node );
  3103. * wrapNode.appendChild( parent );
  3104. *
  3105. * //拆分前
  3106. * //output: <p><span></span></p>
  3107. * console.log( wrapNode.innerHTML );
  3108. *
  3109. *
  3110. * UE.dom.domUtils.breakParent( node, parent );
  3111. * //拆分后
  3112. * //output: <p></p><span></span><p></p>
  3113. * console.log( wrapNode.innerHTML );
  3114. *
  3115. * ```
  3116. */
  3117. breakParent: function(node, parent) {
  3118. var tmpNode,
  3119. parentClone = node,
  3120. clone = node,
  3121. leftNodes,
  3122. rightNodes;
  3123. do {
  3124. parentClone = parentClone.parentNode;
  3125. if (leftNodes) {
  3126. tmpNode = parentClone.cloneNode(false);
  3127. tmpNode.appendChild(leftNodes);
  3128. leftNodes = tmpNode;
  3129. tmpNode = parentClone.cloneNode(false);
  3130. tmpNode.appendChild(rightNodes);
  3131. rightNodes = tmpNode;
  3132. } else {
  3133. leftNodes = parentClone.cloneNode(false);
  3134. rightNodes = leftNodes.cloneNode(false);
  3135. }
  3136. while ((tmpNode = clone.previousSibling)) {
  3137. leftNodes.insertBefore(tmpNode, leftNodes.firstChild);
  3138. }
  3139. while ((tmpNode = clone.nextSibling)) {
  3140. rightNodes.appendChild(tmpNode);
  3141. }
  3142. clone = parentClone;
  3143. } while (parent !== parentClone);
  3144. tmpNode = parent.parentNode;
  3145. tmpNode.insertBefore(leftNodes, parent);
  3146. tmpNode.insertBefore(rightNodes, parent);
  3147. tmpNode.insertBefore(node, rightNodes);
  3148. domUtils.remove(parent);
  3149. return node;
  3150. },
  3151. /**
  3152. * 检查节点node是否是空inline节点
  3153. * @method isEmptyInlineElement
  3154. * @param { Node } node 需要检测的节点对象
  3155. * @return { Number } 如果给定的节点是空的inline节点, 则返回1, 否则返回0。
  3156. * @example
  3157. * ```html
  3158. * <b><i></i></b> => 1
  3159. * <b><i></i><u></u></b> => 1
  3160. * <b></b> => 1
  3161. * <b>xx<i></i></b> => 0
  3162. * ```
  3163. */
  3164. isEmptyInlineElement: function(node) {
  3165. if (node.nodeType != 1 || !dtd.$removeEmpty[node.tagName]) {
  3166. return 0;
  3167. }
  3168. node = node.firstChild;
  3169. while (node) {
  3170. //如果是创建的bookmark就跳过
  3171. if (domUtils.isBookmarkNode(node)) {
  3172. return 0;
  3173. }
  3174. if (
  3175. (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node)) ||
  3176. (node.nodeType == 3 && !domUtils.isWhitespace(node))
  3177. ) {
  3178. return 0;
  3179. }
  3180. node = node.nextSibling;
  3181. }
  3182. return 1;
  3183. },
  3184. /**
  3185. * 删除node节点下首尾两端的空白文本子节点
  3186. * @method trimWhiteTextNode
  3187. * @param { Element } node 需要执行删除操作的元素对象
  3188. * @example
  3189. * ```javascript
  3190. * var node = document.createElement("div");
  3191. *
  3192. * node.appendChild( document.createTextNode( "" ) );
  3193. *
  3194. * node.appendChild( document.createElement("div") );
  3195. *
  3196. * node.appendChild( document.createTextNode( "" ) );
  3197. *
  3198. * //3
  3199. * console.log( node.childNodes.length );
  3200. *
  3201. * UE.dom.domUtils.trimWhiteTextNode( node );
  3202. *
  3203. * //1
  3204. * console.log( node.childNodes.length );
  3205. * ```
  3206. */
  3207. trimWhiteTextNode: function(node) {
  3208. function remove(dir) {
  3209. var child;
  3210. while (
  3211. (child = node[dir]) &&
  3212. child.nodeType == 3 &&
  3213. domUtils.isWhitespace(child)
  3214. ) {
  3215. node.removeChild(child);
  3216. }
  3217. }
  3218. remove("firstChild");
  3219. remove("lastChild");
  3220. },
  3221. /**
  3222. * 合并node节点下相同的子节点
  3223. * @name mergeChild
  3224. * @desc
  3225. * UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签
  3226. * @example
  3227. * <p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xx</span></p>
  3228. * ==> UE.dom.domUtils.mergeChild(node,'span')
  3229. * <p><span style="font-size:12px;">xxaaxx</span></p>
  3230. */
  3231. mergeChild: function(node, tagName, attrs) {
  3232. var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase());
  3233. for (var i = 0, ci; (ci = list[i++]); ) {
  3234. if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
  3235. continue;
  3236. }
  3237. //span单独处理
  3238. if (ci.tagName.toLowerCase() == "span") {
  3239. if (node === ci.parentNode) {
  3240. domUtils.trimWhiteTextNode(node);
  3241. if (node.childNodes.length == 1) {
  3242. node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
  3243. domUtils.remove(ci, true);
  3244. continue;
  3245. }
  3246. }
  3247. ci.style.cssText = node.style.cssText + ";" + ci.style.cssText;
  3248. if (attrs) {
  3249. var style = attrs.style;
  3250. if (style) {
  3251. style = style.split(";");
  3252. for (var j = 0, s; (s = style[j++]); ) {
  3253. ci.style[utils.cssStyleToDomStyle(s.split(":")[0])] = s.split(
  3254. ":"
  3255. )[1];
  3256. }
  3257. }
  3258. }
  3259. if (domUtils.isSameStyle(ci, node)) {
  3260. domUtils.remove(ci, true);
  3261. }
  3262. continue;
  3263. }
  3264. if (domUtils.isSameElement(node, ci)) {
  3265. domUtils.remove(ci, true);
  3266. }
  3267. }
  3268. },
  3269. /**
  3270. * 原生方法getElementsByTagName的封装
  3271. * @method getElementsByTagName
  3272. * @param { Node } node 目标节点对象
  3273. * @param { String } tagName 需要查找的节点的tagName, 多个tagName以空格分割
  3274. * @return { Array } 符合条件的节点集合
  3275. */
  3276. getElementsByTagName: function(node, name, filter) {
  3277. if (filter && utils.isString(filter)) {
  3278. var className = filter;
  3279. filter = function(node) {
  3280. return domUtils.hasClass(node, className);
  3281. };
  3282. }
  3283. name = utils.trim(name).replace(/[ ]{2,}/g, " ").split(" ");
  3284. var arr = [];
  3285. for (var n = 0, ni; (ni = name[n++]); ) {
  3286. var list = node.getElementsByTagName(ni);
  3287. for (var i = 0, ci; (ci = list[i++]); ) {
  3288. if (!filter || filter(ci)) arr.push(ci);
  3289. }
  3290. }
  3291. return arr;
  3292. },
  3293. /**
  3294. * 将节点node提取到父节点上
  3295. * @method mergeToParent
  3296. * @param { Element } node 需要提取的元素对象
  3297. * @example
  3298. * ```html
  3299. * <div id="parent">
  3300. * <div id="sub">
  3301. * <span id="child"></span>
  3302. * </div>
  3303. * </div>
  3304. *
  3305. * <script>
  3306. *
  3307. * var child = document.getElementById( "child" );
  3308. *
  3309. * //output: sub
  3310. * console.log( child.parentNode.id );
  3311. *
  3312. * UE.dom.domUtils.mergeToParent( child );
  3313. *
  3314. * //output: parent
  3315. * console.log( child.parentNode.id );
  3316. *
  3317. * </script>
  3318. * ```
  3319. */
  3320. mergeToParent: function(node) {
  3321. var parent = node.parentNode;
  3322. while (parent && dtd.$removeEmpty[parent.tagName]) {
  3323. if (parent.tagName == node.tagName || parent.tagName == "A") {
  3324. //针对a标签单独处理
  3325. domUtils.trimWhiteTextNode(parent);
  3326. //span需要特殊处理 不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
  3327. if (
  3328. (parent.tagName == "SPAN" && !domUtils.isSameStyle(parent, node)) ||
  3329. (parent.tagName == "A" && node.tagName == "SPAN")
  3330. ) {
  3331. if (parent.childNodes.length > 1 || parent !== node.parentNode) {
  3332. node.style.cssText =
  3333. parent.style.cssText + ";" + node.style.cssText;
  3334. parent = parent.parentNode;
  3335. continue;
  3336. } else {
  3337. parent.style.cssText += ";" + node.style.cssText;
  3338. //trace:952 a标签要保持下划线
  3339. if (parent.tagName == "A") {
  3340. parent.style.textDecoration = "underline";
  3341. }
  3342. }
  3343. }
  3344. if (parent.tagName != "A") {
  3345. parent === node.parentNode && domUtils.remove(node, true);
  3346. break;
  3347. }
  3348. }
  3349. parent = parent.parentNode;
  3350. }
  3351. },
  3352. /**
  3353. * 合并节点node的左右兄弟节点
  3354. * @method mergeSibling
  3355. * @param { Element } node 需要合并的目标节点
  3356. * @example
  3357. * ```html
  3358. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3359. *
  3360. * <script>
  3361. * var demoNode = document.getElementById("test");
  3362. * UE.dom.domUtils.mergeSibling( demoNode );
  3363. * //output: xxxxoooxxxx
  3364. * console.log( demoNode.innerHTML );
  3365. * </script>
  3366. * ```
  3367. */
  3368. /**
  3369. * 合并节点node的左右兄弟节点, 可以根据给定的条件选择是否忽略合并左节点。
  3370. * @method mergeSibling
  3371. * @param { Element } node 需要合并的目标节点
  3372. * @param { Boolean } ignorePre 是否忽略合并左节点
  3373. * @example
  3374. * ```html
  3375. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3376. *
  3377. * <script>
  3378. * var demoNode = document.getElementById("test");
  3379. * UE.dom.domUtils.mergeSibling( demoNode, true );
  3380. * //output: oooxxxx
  3381. * console.log( demoNode.innerHTML );
  3382. * </script>
  3383. * ```
  3384. */
  3385. /**
  3386. * 合并节点node的左右兄弟节点,可以根据给定的条件选择是否忽略合并左右节点。
  3387. * @method mergeSibling
  3388. * @param { Element } node 需要合并的目标节点
  3389. * @param { Boolean } ignorePre 是否忽略合并左节点
  3390. * @param { Boolean } ignoreNext 是否忽略合并右节点
  3391. * @remind 如果同时忽略左右节点, 则该操作什么也不会做
  3392. * @example
  3393. * ```html
  3394. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3395. *
  3396. * <script>
  3397. * var demoNode = document.getElementById("test");
  3398. * UE.dom.domUtils.mergeSibling( demoNode, false, true );
  3399. * //output: xxxxooo
  3400. * console.log( demoNode.innerHTML );
  3401. * </script>
  3402. * ```
  3403. */
  3404. mergeSibling: function(node, ignorePre, ignoreNext) {
  3405. function merge(rtl, start, node) {
  3406. var next;
  3407. if (
  3408. (next = node[rtl]) &&
  3409. !domUtils.isBookmarkNode(next) &&
  3410. next.nodeType == 1 &&
  3411. domUtils.isSameElement(node, next)
  3412. ) {
  3413. while (next.firstChild) {
  3414. if (start == "firstChild") {
  3415. node.insertBefore(next.lastChild, node.firstChild);
  3416. } else {
  3417. node.appendChild(next.firstChild);
  3418. }
  3419. }
  3420. domUtils.remove(next);
  3421. }
  3422. }
  3423. !ignorePre && merge("previousSibling", "firstChild", node);
  3424. !ignoreNext && merge("nextSibling", "lastChild", node);
  3425. },
  3426. /**
  3427. * 设置节点node及其子节点不会被选中
  3428. * @method unSelectable
  3429. * @param { Element } node 需要执行操作的dom元素
  3430. * @remind 执行该操作后的节点, 将不能被鼠标选中
  3431. * @example
  3432. * ```javascript
  3433. * UE.dom.domUtils.unSelectable( document.body );
  3434. * ```
  3435. */
  3436. unSelectable: (ie && browser.ie9below) || browser.opera
  3437. ? function(node) {
  3438. //for ie9
  3439. node.onselectstart = function() {
  3440. return false;
  3441. };
  3442. node.onclick = node.onkeyup = node.onkeydown = function() {
  3443. return false;
  3444. };
  3445. node.unselectable = "on";
  3446. node.setAttribute("unselectable", "on");
  3447. for (var i = 0, ci; (ci = node.all[i++]); ) {
  3448. switch (ci.tagName.toLowerCase()) {
  3449. case "iframe":
  3450. case "textarea":
  3451. case "input":
  3452. case "select":
  3453. break;
  3454. default:
  3455. ci.unselectable = "on";
  3456. node.setAttribute("unselectable", "on");
  3457. }
  3458. }
  3459. }
  3460. : function(node) {
  3461. node.style.MozUserSelect = node.style.webkitUserSelect = node.style.msUserSelect = node.style.KhtmlUserSelect =
  3462. "none";
  3463. },
  3464. /**
  3465. * 删除节点node上的指定属性名称的属性
  3466. * @method removeAttributes
  3467. * @param { Node } node 需要删除属性的节点对象
  3468. * @param { String } attrNames 可以是空格隔开的多个属性名称,该操作将会依次删除相应的属性
  3469. * @example
  3470. * ```html
  3471. * <div id="wrap">
  3472. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3473. * </div>
  3474. *
  3475. * <script>
  3476. *
  3477. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), "id name" );
  3478. *
  3479. * //output: <span style="font-size:14px;">xxxxx</span>
  3480. * console.log( document.getElementById("wrap").innerHTML );
  3481. *
  3482. * </script>
  3483. * ```
  3484. */
  3485. /**
  3486. * 删除节点node上的指定属性名称的属性
  3487. * @method removeAttributes
  3488. * @param { Node } node 需要删除属性的节点对象
  3489. * @param { Array } attrNames 需要删除的属性名数组
  3490. * @example
  3491. * ```html
  3492. * <div id="wrap">
  3493. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3494. * </div>
  3495. *
  3496. * <script>
  3497. *
  3498. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), ["id", "name"] );
  3499. *
  3500. * //output: <span style="font-size:14px;">xxxxx</span>
  3501. * console.log( document.getElementById("wrap").innerHTML );
  3502. *
  3503. * </script>
  3504. * ```
  3505. */
  3506. removeAttributes: function(node, attrNames) {
  3507. attrNames = utils.isArray(attrNames)
  3508. ? attrNames
  3509. : utils.trim(attrNames).replace(/[ ]{2,}/g, " ").split(" ");
  3510. for (var i = 0, ci; (ci = attrNames[i++]); ) {
  3511. ci = attrFix[ci] || ci;
  3512. switch (ci) {
  3513. case "className":
  3514. node[ci] = "";
  3515. break;
  3516. case "style":
  3517. node.style.cssText = "";
  3518. var val = node.getAttributeNode("style");
  3519. !browser.ie && val && node.removeAttributeNode(val);
  3520. }
  3521. node.removeAttribute(ci);
  3522. }
  3523. },
  3524. /**
  3525. * 在doc下创建一个标签名为tag,属性为attrs的元素
  3526. * @method createElement
  3527. * @param { DomDocument } doc 新创建的元素属于该document节点创建
  3528. * @param { String } tagName 需要创建的元素的标签名
  3529. * @param { Object } attrs 新创建的元素的属性key-value集合
  3530. * @return { Element } 新创建的元素对象
  3531. * @example
  3532. * ```javascript
  3533. * var ele = UE.dom.domUtils.createElement( document, 'div', {
  3534. * id: 'test'
  3535. * } );
  3536. *
  3537. * //output: DIV
  3538. * console.log( ele.tagName );
  3539. *
  3540. * //output: test
  3541. * console.log( ele.id );
  3542. *
  3543. * ```
  3544. */
  3545. createElement: function(doc, tag, attrs) {
  3546. return domUtils.setAttributes(doc.createElement(tag), attrs);
  3547. },
  3548. /**
  3549. * 为节点node添加属性attrs,attrs为属性键值对
  3550. * @method setAttributes
  3551. * @param { Element } node 需要设置属性的元素对象
  3552. * @param { Object } attrs 需要设置的属性名-值对
  3553. * @return { Element } 设置属性的元素对象
  3554. * @example
  3555. * ```html
  3556. * <span id="test"></span>
  3557. *
  3558. * <script>
  3559. *
  3560. * var testNode = UE.dom.domUtils.setAttributes( document.getElementById( "test" ), {
  3561. * id: 'demo'
  3562. * } );
  3563. *
  3564. * //output: demo
  3565. * console.log( testNode.id );
  3566. *
  3567. * </script>
  3568. *
  3569. */
  3570. setAttributes: function(node, attrs) {
  3571. for (var attr in attrs) {
  3572. if (attrs.hasOwnProperty(attr)) {
  3573. var value = attrs[attr];
  3574. switch (attr) {
  3575. case "class":
  3576. //ie下要这样赋值,setAttribute不起作用
  3577. node.className = value;
  3578. break;
  3579. case "style":
  3580. node.style.cssText = node.style.cssText + ";" + value;
  3581. break;
  3582. case "innerHTML":
  3583. node[attr] = value;
  3584. break;
  3585. case "value":
  3586. node.value = value;
  3587. break;
  3588. default:
  3589. node.setAttribute(attrFix[attr] || attr, value);
  3590. }
  3591. }
  3592. }
  3593. return node;
  3594. },
  3595. /**
  3596. * 获取元素element经过计算后的样式值
  3597. * @method getComputedStyle
  3598. * @param { Element } element 需要获取样式的元素对象
  3599. * @param { String } styleName 需要获取的样式名
  3600. * @return { String } 获取到的样式值
  3601. * @example
  3602. * ```html
  3603. * <style type="text/css">
  3604. * #test {
  3605. * font-size: 15px;
  3606. * }
  3607. * </style>
  3608. *
  3609. * <span id="test"></span>
  3610. *
  3611. * <script>
  3612. * //output: 15px
  3613. * console.log( UE.dom.domUtils.getComputedStyle( document.getElementById( "test" ), 'font-size' ) );
  3614. * </script>
  3615. * ```
  3616. */
  3617. getComputedStyle: function(element, styleName) {
  3618. //一下的属性单独处理
  3619. var pros = "width height top left";
  3620. if (pros.indexOf(styleName) > -1) {
  3621. return (
  3622. element[
  3623. "offset" +
  3624. styleName.replace(/^\w/, function(s) {
  3625. return s.toUpperCase();
  3626. })
  3627. ] + "px"
  3628. );
  3629. }
  3630. //忽略文本节点
  3631. if (element.nodeType == 3) {
  3632. element = element.parentNode;
  3633. }
  3634. //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改.
  3635. if (
  3636. browser.ie &&
  3637. browser.version < 9 &&
  3638. styleName == "font-size" &&
  3639. !element.style.fontSize &&
  3640. !dtd.$empty[element.tagName] &&
  3641. !dtd.$nonChild[element.tagName]
  3642. ) {
  3643. var span = element.ownerDocument.createElement("span");
  3644. span.style.cssText = "padding:0;border:0;font-family:simsun;";
  3645. span.innerHTML = ".";
  3646. element.appendChild(span);
  3647. var result = span.offsetHeight;
  3648. element.removeChild(span);
  3649. span = null;
  3650. return result + "px";
  3651. }
  3652. try {
  3653. var value =
  3654. domUtils.getStyle(element, styleName) ||
  3655. (window.getComputedStyle
  3656. ? domUtils
  3657. .getWindow(element)
  3658. .getComputedStyle(element, "")
  3659. .getPropertyValue(styleName)
  3660. : (element.currentStyle || element.style)[
  3661. utils.cssStyleToDomStyle(styleName)
  3662. ]);
  3663. } catch (e) {
  3664. return "";
  3665. }
  3666. return utils.transUnitToPx(utils.fixColor(styleName, value));
  3667. },
  3668. /**
  3669. * 删除元素element指定的className
  3670. * @method removeClasses
  3671. * @param { Element } ele 需要删除class的元素节点
  3672. * @param { String } classNames 需要删除的className, 多个className之间以空格分开
  3673. * @example
  3674. * ```html
  3675. * <span id="test" class="test1 test2 test3">xxx</span>
  3676. *
  3677. * <script>
  3678. *
  3679. * var testNode = document.getElementById( "test" );
  3680. * UE.dom.domUtils.removeClasses( testNode, "test1 test2" );
  3681. *
  3682. * //output: test3
  3683. * console.log( testNode.className );
  3684. *
  3685. * </script>
  3686. * ```
  3687. */
  3688. /**
  3689. * 删除元素element指定的className
  3690. * @method removeClasses
  3691. * @param { Element } ele 需要删除class的元素节点
  3692. * @param { Array } classNames 需要删除的className数组
  3693. * @example
  3694. * ```html
  3695. * <span id="test" class="test1 test2 test3">xxx</span>
  3696. *
  3697. * <script>
  3698. *
  3699. * var testNode = document.getElementById( "test" );
  3700. * UE.dom.domUtils.removeClasses( testNode, ["test1", "test2"] );
  3701. *
  3702. * //output: test3
  3703. * console.log( testNode.className );
  3704. *
  3705. * </script>
  3706. * ```
  3707. */
  3708. removeClasses: function(elm, classNames) {
  3709. classNames = utils.isArray(classNames)
  3710. ? classNames
  3711. : utils.trim(classNames).replace(/[ ]{2,}/g, " ").split(" ");
  3712. for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]); ) {
  3713. cls = cls.replace(new RegExp("\\b" + ci + "\\b"), "");
  3714. }
  3715. cls = utils.trim(cls).replace(/[ ]{2,}/g, " ");
  3716. if (cls) {
  3717. elm.className = cls;
  3718. } else {
  3719. domUtils.removeAttributes(elm, ["class"]);
  3720. }
  3721. },
  3722. /**
  3723. * 给元素element添加className
  3724. * @method addClass
  3725. * @param { Node } ele 需要增加className的元素
  3726. * @param { String } classNames 需要添加的className, 多个className之间以空格分割
  3727. * @remind 相同的类名不会被重复添加
  3728. * @example
  3729. * ```html
  3730. * <span id="test" class="cls1 cls2"></span>
  3731. *
  3732. * <script>
  3733. * var testNode = document.getElementById("test");
  3734. *
  3735. * UE.dom.domUtils.addClass( testNode, "cls2 cls3 cls4" );
  3736. *
  3737. * //output: cl1 cls2 cls3 cls4
  3738. * console.log( testNode.className );
  3739. *
  3740. * <script>
  3741. * ```
  3742. */
  3743. /**
  3744. * 给元素element添加className
  3745. * @method addClass
  3746. * @param { Node } ele 需要增加className的元素
  3747. * @param { Array } classNames 需要添加的className的数组
  3748. * @remind 相同的类名不会被重复添加
  3749. * @example
  3750. * ```html
  3751. * <span id="test" class="cls1 cls2"></span>
  3752. *
  3753. * <script>
  3754. * var testNode = document.getElementById("test");
  3755. *
  3756. * UE.dom.domUtils.addClass( testNode, ["cls2", "cls3", "cls4"] );
  3757. *
  3758. * //output: cl1 cls2 cls3 cls4
  3759. * console.log( testNode.className );
  3760. *
  3761. * <script>
  3762. * ```
  3763. */
  3764. addClass: function(elm, classNames) {
  3765. if (!elm) return;
  3766. classNames = utils.trim(classNames).replace(/[ ]{2,}/g, " ").split(" ");
  3767. for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]); ) {
  3768. if (!new RegExp("\\b" + ci + "\\b").test(cls)) {
  3769. cls += " " + ci;
  3770. }
  3771. }
  3772. elm.className = utils.trim(cls);
  3773. },
  3774. /**
  3775. * 判断元素element是否包含给定的样式类名className
  3776. * @method hasClass
  3777. * @param { Node } ele 需要检测的元素
  3778. * @param { String } classNames 需要检测的className, 多个className之间用空格分割
  3779. * @return { Boolean } 元素是否包含所有给定的className
  3780. * @example
  3781. * ```html
  3782. * <span id="test1" class="cls1 cls2"></span>
  3783. *
  3784. * <script>
  3785. * var test1 = document.getElementById("test1");
  3786. *
  3787. * //output: false
  3788. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1 cls3" ) );
  3789. *
  3790. * //output: true
  3791. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1" ) );
  3792. * </script>
  3793. * ```
  3794. */
  3795. /**
  3796. * 判断元素element是否包含给定的样式类名className
  3797. * @method hasClass
  3798. * @param { Node } ele 需要检测的元素
  3799. * @param { Array } classNames 需要检测的className数组
  3800. * @return { Boolean } 元素是否包含所有给定的className
  3801. * @example
  3802. * ```html
  3803. * <span id="test1" class="cls1 cls2"></span>
  3804. *
  3805. * <script>
  3806. * var test1 = document.getElementById("test1");
  3807. *
  3808. * //output: false
  3809. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1", "cls3" ] ) );
  3810. *
  3811. * //output: true
  3812. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1" ]) );
  3813. * </script>
  3814. * ```
  3815. */
  3816. hasClass: function(element, className) {
  3817. if (utils.isRegExp(className)) {
  3818. return className.test(element.className);
  3819. }
  3820. className = utils.trim(className).replace(/[ ]{2,}/g, " ").split(" ");
  3821. for (var i = 0, ci, cls = element.className; (ci = className[i++]); ) {
  3822. if (!new RegExp("\\b" + ci + "\\b", "i").test(cls)) {
  3823. return false;
  3824. }
  3825. }
  3826. return i - 1 == className.length;
  3827. },
  3828. /**
  3829. * 阻止事件默认行为
  3830. * @method preventDefault
  3831. * @param { Event } evt 需要阻止默认行为的事件对象
  3832. * @example
  3833. * ```javascript
  3834. * UE.dom.domUtils.preventDefault( evt );
  3835. * ```
  3836. */
  3837. preventDefault: function(evt) {
  3838. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  3839. },
  3840. /**
  3841. * 删除元素element指定的样式
  3842. * @method removeStyle
  3843. * @param { Element } element 需要删除样式的元素
  3844. * @param { String } styleName 需要删除的样式名
  3845. * @example
  3846. * ```html
  3847. * <span id="test" style="color: red; background: blue;"></span>
  3848. *
  3849. * <script>
  3850. *
  3851. * var testNode = document.getElementById("test");
  3852. *
  3853. * UE.dom.domUtils.removeStyle( testNode, 'color' );
  3854. *
  3855. * //output: background: blue;
  3856. * console.log( testNode.style.cssText );
  3857. *
  3858. * </script>
  3859. * ```
  3860. */
  3861. removeStyle: function(element, name) {
  3862. if (browser.ie) {
  3863. //针对color先单独处理一下
  3864. if (name == "color") {
  3865. name = "(^|;)" + name;
  3866. }
  3867. element.style.cssText = element.style.cssText.replace(
  3868. new RegExp(name + "[^:]*:[^;]+;?", "ig"),
  3869. ""
  3870. );
  3871. } else {
  3872. if (element.style.removeProperty) {
  3873. element.style.removeProperty(name);
  3874. } else {
  3875. element.style.removeAttribute(utils.cssStyleToDomStyle(name));
  3876. }
  3877. }
  3878. if (!element.style.cssText) {
  3879. domUtils.removeAttributes(element, ["style"]);
  3880. }
  3881. },
  3882. /**
  3883. * 获取元素element的style属性的指定值
  3884. * @method getStyle
  3885. * @param { Element } element 需要获取属性值的元素
  3886. * @param { String } styleName 需要获取的style的名称
  3887. * @warning 该方法仅获取元素style属性中所标明的值
  3888. * @return { String } 该元素包含指定的style属性值
  3889. * @example
  3890. * ```html
  3891. * <div id="test" style="color: red;"></div>
  3892. *
  3893. * <script>
  3894. *
  3895. * var testNode = document.getElementById( "test" );
  3896. *
  3897. * //output: red
  3898. * console.log( UE.dom.domUtils.getStyle( testNode, "color" ) );
  3899. *
  3900. * //output: ""
  3901. * console.log( UE.dom.domUtils.getStyle( testNode, "background" ) );
  3902. *
  3903. * </script>
  3904. * ```
  3905. */
  3906. getStyle: function(element, name) {
  3907. var value = element.style[utils.cssStyleToDomStyle(name)];
  3908. return utils.fixColor(name, value);
  3909. },
  3910. /**
  3911. * 为元素element设置样式属性值
  3912. * @method setStyle
  3913. * @param { Element } element 需要设置样式的元素
  3914. * @param { String } styleName 样式名
  3915. * @param { String } styleValue 样式值
  3916. * @example
  3917. * ```html
  3918. * <div id="test"></div>
  3919. *
  3920. * <script>
  3921. *
  3922. * var testNode = document.getElementById( "test" );
  3923. *
  3924. * //output: ""
  3925. * console.log( testNode.style.color );
  3926. *
  3927. * UE.dom.domUtils.setStyle( testNode, 'color', 'red' );
  3928. * //output: "red"
  3929. * console.log( testNode.style.color );
  3930. *
  3931. * </script>
  3932. * ```
  3933. */
  3934. setStyle: function(element, name, value) {
  3935. element.style[utils.cssStyleToDomStyle(name)] = value;
  3936. if (!utils.trim(element.style.cssText)) {
  3937. this.removeAttributes(element, "style");
  3938. }
  3939. },
  3940. /**
  3941. * 为元素element设置多个样式属性值
  3942. * @method setStyles
  3943. * @param { Element } element 需要设置样式的元素
  3944. * @param { Object } styles 样式名值对
  3945. * @example
  3946. * ```html
  3947. * <div id="test"></div>
  3948. *
  3949. * <script>
  3950. *
  3951. * var testNode = document.getElementById( "test" );
  3952. *
  3953. * //output: ""
  3954. * console.log( testNode.style.color );
  3955. *
  3956. * UE.dom.domUtils.setStyles( testNode, {
  3957. * 'color': 'red'
  3958. * } );
  3959. * //output: "red"
  3960. * console.log( testNode.style.color );
  3961. *
  3962. * </script>
  3963. * ```
  3964. */
  3965. setStyles: function(element, styles) {
  3966. for (var name in styles) {
  3967. if (styles.hasOwnProperty(name)) {
  3968. domUtils.setStyle(element, name, styles[name]);
  3969. }
  3970. }
  3971. },
  3972. /**
  3973. * 删除_moz_dirty属性
  3974. * @private
  3975. * @method removeDirtyAttr
  3976. */
  3977. removeDirtyAttr: function(node) {
  3978. for (
  3979. var i = 0, ci, nodes = node.getElementsByTagName("*");
  3980. (ci = nodes[i++]);
  3981. ) {
  3982. ci.removeAttribute("_moz_dirty");
  3983. }
  3984. node.removeAttribute("_moz_dirty");
  3985. },
  3986. /**
  3987. * 获取子节点的数量
  3988. * @method getChildCount
  3989. * @param { Element } node 需要检测的元素
  3990. * @return { Number } 给定的node元素的子节点数量
  3991. * @example
  3992. * ```html
  3993. * <div id="test">
  3994. * <span></span>
  3995. * </div>
  3996. *
  3997. * <script>
  3998. *
  3999. * //output: 3
  4000. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test") ) );
  4001. *
  4002. * </script>
  4003. * ```
  4004. */
  4005. /**
  4006. * 根据给定的过滤规则, 获取符合条件的子节点的数量
  4007. * @method getChildCount
  4008. * @param { Element } node 需要检测的元素
  4009. * @param { Function } fn 过滤器, 要求对符合条件的子节点返回true, 反之则要求返回false
  4010. * @return { Number } 符合过滤条件的node元素的子节点数量
  4011. * @example
  4012. * ```html
  4013. * <div id="test">
  4014. * <span></span>
  4015. * </div>
  4016. *
  4017. * <script>
  4018. *
  4019. * //output: 1
  4020. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test"), function ( node ) {
  4021. *
  4022. * return node.nodeType === 1;
  4023. *
  4024. * } ) );
  4025. *
  4026. * </script>
  4027. * ```
  4028. */
  4029. getChildCount: function(node, fn) {
  4030. var count = 0,
  4031. first = node.firstChild;
  4032. fn =
  4033. fn ||
  4034. function() {
  4035. return 1;
  4036. };
  4037. while (first) {
  4038. if (fn(first)) {
  4039. count++;
  4040. }
  4041. first = first.nextSibling;
  4042. }
  4043. return count;
  4044. },
  4045. /**
  4046. * 判断给定节点是否为空节点
  4047. * @method isEmptyNode
  4048. * @param { Node } node 需要检测的节点对象
  4049. * @return { Boolean } 节点是否为空
  4050. * @example
  4051. * ```javascript
  4052. * UE.dom.domUtils.isEmptyNode( document.body );
  4053. * ```
  4054. */
  4055. isEmptyNode: function(node) {
  4056. return (
  4057. !node.firstChild ||
  4058. domUtils.getChildCount(node, function(node) {
  4059. return (
  4060. !domUtils.isBr(node) &&
  4061. !domUtils.isBookmarkNode(node) &&
  4062. !domUtils.isWhitespace(node)
  4063. );
  4064. }) == 0
  4065. );
  4066. },
  4067. clearSelectedArr: function(nodes) {
  4068. var node;
  4069. while ((node = nodes.pop())) {
  4070. domUtils.removeAttributes(node, ["class"]);
  4071. }
  4072. },
  4073. /**
  4074. * 将显示区域滚动到指定节点的位置
  4075. * @method scrollToView
  4076. * @param {Node} node 节点
  4077. * @param {window} win window对象
  4078. * @param {Number} offsetTop 距离上方的偏移量
  4079. */
  4080. scrollToView: function(node, win, offsetTop) {
  4081. var getViewPaneSize = function() {
  4082. var doc = win.document,
  4083. mode = doc.compatMode == "CSS1Compat";
  4084. return {
  4085. width:
  4086. (mode ? doc.documentElement.clientWidth : doc.body.clientWidth) || 0,
  4087. height:
  4088. (mode ? doc.documentElement.clientHeight : doc.body.clientHeight) || 0
  4089. };
  4090. },
  4091. getScrollPosition = function(win) {
  4092. if ("pageXOffset" in win) {
  4093. return {
  4094. x: win.pageXOffset || 0,
  4095. y: win.pageYOffset || 0
  4096. };
  4097. } else {
  4098. var doc = win.document;
  4099. return {
  4100. x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
  4101. y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
  4102. };
  4103. }
  4104. };
  4105. var winHeight = getViewPaneSize().height,
  4106. offset = winHeight * -1 + offsetTop;
  4107. offset += node.offsetHeight || 0;
  4108. var elementPosition = domUtils.getXY(node);
  4109. offset += elementPosition.y;
  4110. var currentScroll = getScrollPosition(win).y;
  4111. // offset += 50;
  4112. if (offset > currentScroll || offset < currentScroll - winHeight) {
  4113. win.scrollTo(0, offset + (offset < 0 ? -20 : 20));
  4114. }
  4115. },
  4116. /**
  4117. * 判断给定节点是否为br
  4118. * @method isBr
  4119. * @param { Node } node 需要判断的节点对象
  4120. * @return { Boolean } 给定的节点是否是br节点
  4121. */
  4122. isBr: function(node) {
  4123. return node.nodeType == 1 && node.tagName == "BR";
  4124. },
  4125. /**
  4126. * 判断给定的节点是否是一个“填充”节点
  4127. * @private
  4128. * @method isFillChar
  4129. * @param { Node } node 需要判断的节点
  4130. * @param { Boolean } isInStart 是否从节点内容的开始位置匹配
  4131. * @returns { Boolean } 节点是否是填充节点
  4132. */
  4133. isFillChar: function(node, isInStart) {
  4134. if (node.nodeType != 3) return false;
  4135. var text = node.nodeValue;
  4136. if (isInStart) {
  4137. return new RegExp("^" + domUtils.fillChar).test(text);
  4138. }
  4139. return !text.replace(new RegExp(domUtils.fillChar, "g"), "").length;
  4140. },
  4141. isStartInblock: function(range) {
  4142. var tmpRange = range.cloneRange(),
  4143. flag = 0,
  4144. start = tmpRange.startContainer,
  4145. tmp;
  4146. if (start.nodeType == 1 && start.childNodes[tmpRange.startOffset]) {
  4147. start = start.childNodes[tmpRange.startOffset];
  4148. var pre = start.previousSibling;
  4149. while (pre && domUtils.isFillChar(pre)) {
  4150. start = pre;
  4151. pre = pre.previousSibling;
  4152. }
  4153. }
  4154. if (this.isFillChar(start, true) && tmpRange.startOffset == 1) {
  4155. tmpRange.setStartBefore(start);
  4156. start = tmpRange.startContainer;
  4157. }
  4158. while (start && domUtils.isFillChar(start)) {
  4159. tmp = start;
  4160. start = start.previousSibling;
  4161. }
  4162. if (tmp) {
  4163. tmpRange.setStartBefore(tmp);
  4164. start = tmpRange.startContainer;
  4165. }
  4166. if (
  4167. start.nodeType == 1 &&
  4168. domUtils.isEmptyNode(start) &&
  4169. tmpRange.startOffset == 1
  4170. ) {
  4171. tmpRange.setStart(start, 0).collapse(true);
  4172. }
  4173. while (!tmpRange.startOffset) {
  4174. start = tmpRange.startContainer;
  4175. if (domUtils.isBlockElm(start) || domUtils.isBody(start)) {
  4176. flag = 1;
  4177. break;
  4178. }
  4179. var pre = tmpRange.startContainer.previousSibling,
  4180. tmpNode;
  4181. if (!pre) {
  4182. tmpRange.setStartBefore(tmpRange.startContainer);
  4183. } else {
  4184. while (pre && domUtils.isFillChar(pre)) {
  4185. tmpNode = pre;
  4186. pre = pre.previousSibling;
  4187. }
  4188. if (tmpNode) {
  4189. tmpRange.setStartBefore(tmpNode);
  4190. } else {
  4191. tmpRange.setStartBefore(tmpRange.startContainer);
  4192. }
  4193. }
  4194. }
  4195. return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0;
  4196. },
  4197. /**
  4198. * 判断给定的元素是否是一个空元素
  4199. * @method isEmptyBlock
  4200. * @param { Element } node 需要判断的元素
  4201. * @return { Boolean } 是否是空元素
  4202. * @example
  4203. * ```html
  4204. * <div id="test"></div>
  4205. *
  4206. * <script>
  4207. * //output: true
  4208. * console.log( UE.dom.domUtils.isEmptyBlock( document.getElementById("test") ) );
  4209. * </script>
  4210. * ```
  4211. */
  4212. /**
  4213. * 根据指定的判断规则判断给定的元素是否是一个空元素
  4214. * @method isEmptyBlock
  4215. * @param { Element } node 需要判断的元素
  4216. * @param { RegExp } reg 对内容执行判断的正则表达式对象
  4217. * @return { Boolean } 是否是空元素
  4218. */
  4219. isEmptyBlock: function(node, reg) {
  4220. if (node.nodeType != 1) return 0;
  4221. reg = reg || new RegExp("[ \xa0\t\r\n" + domUtils.fillChar + "]", "g");
  4222. if (
  4223. node[browser.ie ? "innerText" : "textContent"].replace(reg, "").length > 0
  4224. ) {
  4225. return 0;
  4226. }
  4227. for (var n in dtd.$isNotEmpty) {
  4228. if (node.getElementsByTagName(n).length) {
  4229. return 0;
  4230. }
  4231. }
  4232. return 1;
  4233. },
  4234. /**
  4235. * 移动元素使得该元素的位置移动指定的偏移量的距离
  4236. * @method setViewportOffset
  4237. * @param { Element } element 需要设置偏移量的元素
  4238. * @param { Object } offset 偏移量, 形如{ left: 100, top: 50 }的一个键值对, 表示该元素将在
  4239. * 现有的位置上向水平方向偏移offset.left的距离, 在竖直方向上偏移
  4240. * offset.top的距离
  4241. * @example
  4242. * ```html
  4243. * <div id="test" style="top: 100px; left: 50px; position: absolute;"></div>
  4244. *
  4245. * <script>
  4246. *
  4247. * var testNode = document.getElementById("test");
  4248. *
  4249. * UE.dom.domUtils.setViewportOffset( testNode, {
  4250. * left: 200,
  4251. * top: 50
  4252. * } );
  4253. *
  4254. * //output: top: 300px; left: 100px; position: absolute;
  4255. * console.log( testNode.style.cssText );
  4256. *
  4257. * </script>
  4258. * ```
  4259. */
  4260. setViewportOffset: function(element, offset) {
  4261. var left = parseInt(element.style.left) | 0;
  4262. var top = parseInt(element.style.top) | 0;
  4263. var rect = element.getBoundingClientRect();
  4264. var offsetLeft = offset.left - rect.left;
  4265. var offsetTop = offset.top - rect.top;
  4266. if (offsetLeft) {
  4267. element.style.left = left + offsetLeft + "px";
  4268. }
  4269. if (offsetTop) {
  4270. element.style.top = top + offsetTop + "px";
  4271. }
  4272. },
  4273. /**
  4274. * 用“填充字符”填充节点
  4275. * @method fillNode
  4276. * @private
  4277. * @param { DomDocument } doc 填充的节点所在的docment对象
  4278. * @param { Node } node 需要填充的节点对象
  4279. * @example
  4280. * ```html
  4281. * <div id="test"></div>
  4282. *
  4283. * <script>
  4284. * var testNode = document.getElementById("test");
  4285. *
  4286. * //output: 0
  4287. * console.log( testNode.childNodes.length );
  4288. *
  4289. * UE.dom.domUtils.fillNode( document, testNode );
  4290. *
  4291. * //output: 1
  4292. * console.log( testNode.childNodes.length );
  4293. *
  4294. * </script>
  4295. * ```
  4296. */
  4297. fillNode: function(doc, node) {
  4298. var tmpNode = browser.ie
  4299. ? doc.createTextNode(domUtils.fillChar)
  4300. : doc.createElement("br");
  4301. node.innerHTML = "";
  4302. node.appendChild(tmpNode);
  4303. },
  4304. /**
  4305. * 把节点src的所有子节点追加到另一个节点tag上去
  4306. * @method moveChild
  4307. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  4308. * @param { Node } tag 目标节点, 从源节点移除的子节点将被追加到该节点下
  4309. * @example
  4310. * ```html
  4311. * <div id="test1">
  4312. * <span></span>
  4313. * </div>
  4314. * <div id="test2">
  4315. * <div></div>
  4316. * </div>
  4317. *
  4318. * <script>
  4319. *
  4320. * var test1 = document.getElementById("test1"),
  4321. * test2 = document.getElementById("test2");
  4322. *
  4323. * UE.dom.domUtils.moveChild( test1, test2 );
  4324. *
  4325. * //output: ""(空字符串)
  4326. * console.log( test1.innerHTML );
  4327. *
  4328. * //output: "<div></div><span></span>"
  4329. * console.log( test2.innerHTML );
  4330. *
  4331. * </script>
  4332. * ```
  4333. */
  4334. /**
  4335. * 把节点src的所有子节点移动到另一个节点tag上去, 可以通过dir参数控制附加的行为是“追加”还是“插入顶部”
  4336. * @method moveChild
  4337. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  4338. * @param { Node } tag 目标节点, 从源节点移除的子节点将被附加到该节点下
  4339. * @param { Boolean } dir 附加方式, 如果为true, 则附加进去的节点将被放到目标节点的顶部, 反之,则放到末尾
  4340. * @example
  4341. * ```html
  4342. * <div id="test1">
  4343. * <span></span>
  4344. * </div>
  4345. * <div id="test2">
  4346. * <div></div>
  4347. * </div>
  4348. *
  4349. * <script>
  4350. *
  4351. * var test1 = document.getElementById("test1"),
  4352. * test2 = document.getElementById("test2");
  4353. *
  4354. * UE.dom.domUtils.moveChild( test1, test2, true );
  4355. *
  4356. * //output: ""(空字符串)
  4357. * console.log( test1.innerHTML );
  4358. *
  4359. * //output: "<span></span><div></div>"
  4360. * console.log( test2.innerHTML );
  4361. *
  4362. * </script>
  4363. * ```
  4364. */
  4365. moveChild: function(src, tag, dir) {
  4366. while (src.firstChild) {
  4367. if (dir && tag.firstChild) {
  4368. tag.insertBefore(src.lastChild, tag.firstChild);
  4369. } else {
  4370. tag.appendChild(src.firstChild);
  4371. }
  4372. }
  4373. },
  4374. /**
  4375. * 判断节点的标签上是否不存在任何属性
  4376. * @method hasNoAttributes
  4377. * @private
  4378. * @param { Node } node 需要检测的节点对象
  4379. * @return { Boolean } 节点是否不包含任何属性
  4380. * @example
  4381. * ```html
  4382. * <div id="test"><span>xxxx</span></div>
  4383. *
  4384. * <script>
  4385. *
  4386. * //output: false
  4387. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test") ) );
  4388. *
  4389. * //output: true
  4390. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test").firstChild ) );
  4391. *
  4392. * </script>
  4393. * ```
  4394. */
  4395. hasNoAttributes: function(node) {
  4396. return browser.ie
  4397. ? /^<\w+\s*?>/.test(node.outerHTML)
  4398. : node.attributes.length == 0;
  4399. },
  4400. /**
  4401. * 检测节点是否是UEditor所使用的辅助节点
  4402. * @method isCustomeNode
  4403. * @private
  4404. * @param { Node } node 需要检测的节点
  4405. * @remind 辅助节点是指编辑器要完成工作临时添加的节点, 在输出的时候将会从编辑器内移除, 不会影响最终的结果。
  4406. * @return { Boolean } 给定的节点是否是一个辅助节点
  4407. */
  4408. isCustomeNode: function(node) {
  4409. return node.nodeType == 1 && node.getAttribute("_ue_custom_node_");
  4410. },
  4411. /**
  4412. * 检测节点的标签是否是给定的标签
  4413. * @method isTagNode
  4414. * @param { Node } node 需要检测的节点对象
  4415. * @param { String } tagName 标签
  4416. * @return { Boolean } 节点的标签是否是给定的标签
  4417. * @example
  4418. * ```html
  4419. * <div id="test"></div>
  4420. *
  4421. * <script>
  4422. *
  4423. * //output: true
  4424. * console.log( UE.dom.domUtils.isTagNode( document.getElementById("test"), "div" ) );
  4425. *
  4426. * </script>
  4427. * ```
  4428. */
  4429. isTagNode: function(node, tagNames) {
  4430. return (
  4431. node.nodeType == 1 &&
  4432. new RegExp("\\b" + node.tagName + "\\b", "i").test(tagNames)
  4433. );
  4434. },
  4435. /**
  4436. * 给定一个节点数组,在通过指定的过滤器过滤后, 获取其中满足过滤条件的第一个节点
  4437. * @method filterNodeList
  4438. * @param { Array } nodeList 需要过滤的节点数组
  4439. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  4440. * @return { Node | NULL } 如果找到符合过滤条件的节点, 则返回该节点, 否则返回NULL
  4441. * @example
  4442. * ```javascript
  4443. * var divNodes = document.getElementsByTagName("div");
  4444. * divNodes = [].slice.call( divNodes, 0 );
  4445. *
  4446. * //output: null
  4447. * console.log( UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4448. * return node.tagName.toLowerCase() !== 'div';
  4449. * } ) );
  4450. * ```
  4451. */
  4452. /**
  4453. * 给定一个节点数组nodeList和一组标签名tagNames, 获取其中能够匹配标签名的节点集合中的第一个节点
  4454. * @method filterNodeList
  4455. * @param { Array } nodeList 需要过滤的节点数组
  4456. * @param { String } tagNames 需要匹配的标签名, 多个标签名之间用空格分割
  4457. * @return { Node | NULL } 如果找到标签名匹配的节点, 则返回该节点, 否则返回NULL
  4458. * @example
  4459. * ```javascript
  4460. * var divNodes = document.getElementsByTagName("div");
  4461. * divNodes = [].slice.call( divNodes, 0 );
  4462. *
  4463. * //output: null
  4464. * console.log( UE.dom.domUtils.filterNodeList( divNodes, 'a span' ) );
  4465. * ```
  4466. */
  4467. /**
  4468. * 给定一个节点数组,在通过指定的过滤器过滤后, 如果参数forAll为true, 则会返回所有满足过滤
  4469. * 条件的节点集合, 否则, 返回满足条件的节点集合中的第一个节点
  4470. * @method filterNodeList
  4471. * @param { Array } nodeList 需要过滤的节点数组
  4472. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  4473. * @param { Boolean } forAll 是否返回整个节点数组, 如果该参数为false, 则返回节点集合中的第一个节点
  4474. * @return { Array | Node | NULL } 如果找到符合过滤条件的节点, 则根据参数forAll的值决定返回满足
  4475. * 过滤条件的节点数组或第一个节点, 否则返回NULL
  4476. * @example
  4477. * ```javascript
  4478. * var divNodes = document.getElementsByTagName("div");
  4479. * divNodes = [].slice.call( divNodes, 0 );
  4480. *
  4481. * //output: 3(假定有3个div)
  4482. * console.log( divNodes.length );
  4483. *
  4484. * var nodes = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4485. * return node.tagName.toLowerCase() === 'div';
  4486. * }, true );
  4487. *
  4488. * //output: 3
  4489. * console.log( nodes.length );
  4490. *
  4491. * var node = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4492. * return node.tagName.toLowerCase() === 'div';
  4493. * }, false );
  4494. *
  4495. * //output: div
  4496. * console.log( node.nodeName );
  4497. * ```
  4498. */
  4499. filterNodeList: function(nodelist, filter, forAll) {
  4500. var results = [];
  4501. if (!utils.isFunction(filter)) {
  4502. var str = filter;
  4503. filter = function(n) {
  4504. return (
  4505. utils.indexOf(
  4506. utils.isArray(str) ? str : str.split(" "),
  4507. n.tagName.toLowerCase()
  4508. ) != -1
  4509. );
  4510. };
  4511. }
  4512. utils.each(nodelist, function(n) {
  4513. filter(n) && results.push(n);
  4514. });
  4515. return results.length == 0
  4516. ? null
  4517. : results.length == 1 || !forAll ? results[0] : results;
  4518. },
  4519. /**
  4520. * 查询给定的range选区是否在给定的node节点内,且在该节点的最末尾
  4521. * @method isInNodeEndBoundary
  4522. * @param { UE.dom.Range } rng 需要判断的range对象, 该对象的startContainer不能为NULL
  4523. * @param node 需要检测的节点对象
  4524. * @return { Number } 如果给定的选取range对象是在node内部的最末端, 则返回1, 否则返回0
  4525. */
  4526. isInNodeEndBoundary: function(rng, node) {
  4527. var start = rng.startContainer;
  4528. if (start.nodeType == 3 && rng.startOffset != start.nodeValue.length) {
  4529. return 0;
  4530. }
  4531. if (start.nodeType == 1 && rng.startOffset != start.childNodes.length) {
  4532. return 0;
  4533. }
  4534. while (start !== node) {
  4535. if (start.nextSibling) {
  4536. return 0;
  4537. }
  4538. start = start.parentNode;
  4539. }
  4540. return 1;
  4541. },
  4542. isBoundaryNode: function(node, dir) {
  4543. var tmp;
  4544. while (!domUtils.isBody(node)) {
  4545. tmp = node;
  4546. node = node.parentNode;
  4547. if (tmp !== node[dir]) {
  4548. return false;
  4549. }
  4550. }
  4551. return true;
  4552. },
  4553. fillHtml: browser.ie11below ? "&nbsp;" : "<br/>"
  4554. });
  4555. var fillCharReg = new RegExp(domUtils.fillChar, "g");
  4556. // core/Range.js
  4557. /**
  4558. * Range封装
  4559. * @file
  4560. * @module UE.dom
  4561. * @class Range
  4562. * @since 1.2.6.1
  4563. */
  4564. /**
  4565. * dom操作封装
  4566. * @unfile
  4567. * @module UE.dom
  4568. */
  4569. /**
  4570. * Range实现类,本类是UEditor底层核心类,封装不同浏览器之间的Range操作。
  4571. * @unfile
  4572. * @module UE.dom
  4573. * @class Range
  4574. */
  4575. ;(function() {
  4576. var guid = 0,
  4577. fillChar = domUtils.fillChar,
  4578. fillData;
  4579. /**
  4580. * 更新range的collapse状态
  4581. * @param {Range} range range对象
  4582. */
  4583. function updateCollapse(range) {
  4584. range.collapsed =
  4585. range.startContainer &&
  4586. range.endContainer &&
  4587. range.startContainer === range.endContainer &&
  4588. range.startOffset == range.endOffset;
  4589. }
  4590. function selectOneNode(rng) {
  4591. return (
  4592. !rng.collapsed &&
  4593. rng.startContainer.nodeType == 1 &&
  4594. rng.startContainer === rng.endContainer &&
  4595. rng.endOffset - rng.startOffset == 1
  4596. );
  4597. }
  4598. function setEndPoint(toStart, node, offset, range) {
  4599. //如果node是自闭合标签要处理
  4600. if (
  4601. node.nodeType == 1 &&
  4602. (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])
  4603. ) {
  4604. offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1);
  4605. node = node.parentNode;
  4606. }
  4607. if (toStart) {
  4608. range.startContainer = node;
  4609. range.startOffset = offset;
  4610. if (!range.endContainer) {
  4611. range.collapse(true);
  4612. }
  4613. } else {
  4614. range.endContainer = node;
  4615. range.endOffset = offset;
  4616. if (!range.startContainer) {
  4617. range.collapse(false);
  4618. }
  4619. }
  4620. updateCollapse(range);
  4621. return range;
  4622. }
  4623. function execContentsAction(range, action) {
  4624. //调整边界
  4625. //range.includeBookmark();
  4626. var start = range.startContainer,
  4627. end = range.endContainer,
  4628. startOffset = range.startOffset,
  4629. endOffset = range.endOffset,
  4630. doc = range.document,
  4631. frag = doc.createDocumentFragment(),
  4632. tmpStart,
  4633. tmpEnd;
  4634. if (start.nodeType == 1) {
  4635. start =
  4636. start.childNodes[startOffset] ||
  4637. (tmpStart = start.appendChild(doc.createTextNode("")));
  4638. }
  4639. if (end.nodeType == 1) {
  4640. end =
  4641. end.childNodes[endOffset] ||
  4642. (tmpEnd = end.appendChild(doc.createTextNode("")));
  4643. }
  4644. if (start === end && start.nodeType == 3) {
  4645. frag.appendChild(
  4646. doc.createTextNode(
  4647. start.substringData(startOffset, endOffset - startOffset)
  4648. )
  4649. );
  4650. //is not clone
  4651. if (action) {
  4652. start.deleteData(startOffset, endOffset - startOffset);
  4653. range.collapse(true);
  4654. }
  4655. return frag;
  4656. }
  4657. var current,
  4658. currentLevel,
  4659. clone = frag,
  4660. startParents = domUtils.findParents(start, true),
  4661. endParents = domUtils.findParents(end, true);
  4662. for (var i = 0; startParents[i] == endParents[i]; ) {
  4663. i++;
  4664. }
  4665. for (var j = i, si; (si = startParents[j]); j++) {
  4666. current = si.nextSibling;
  4667. if (si == start) {
  4668. if (!tmpStart) {
  4669. if (range.startContainer.nodeType == 3) {
  4670. clone.appendChild(
  4671. doc.createTextNode(start.nodeValue.slice(startOffset))
  4672. );
  4673. //is not clone
  4674. if (action) {
  4675. start.deleteData(
  4676. startOffset,
  4677. start.nodeValue.length - startOffset
  4678. );
  4679. }
  4680. } else {
  4681. clone.appendChild(!action ? start.cloneNode(true) : start);
  4682. }
  4683. }
  4684. } else {
  4685. currentLevel = si.cloneNode(false);
  4686. clone.appendChild(currentLevel);
  4687. }
  4688. while (current) {
  4689. if (current === end || current === endParents[j]) {
  4690. break;
  4691. }
  4692. si = current.nextSibling;
  4693. clone.appendChild(!action ? current.cloneNode(true) : current);
  4694. current = si;
  4695. }
  4696. clone = currentLevel;
  4697. }
  4698. clone = frag;
  4699. if (!startParents[i]) {
  4700. clone.appendChild(startParents[i - 1].cloneNode(false));
  4701. clone = clone.firstChild;
  4702. }
  4703. for (var j = i, ei; (ei = endParents[j]); j++) {
  4704. current = ei.previousSibling;
  4705. if (ei == end) {
  4706. if (!tmpEnd && range.endContainer.nodeType == 3) {
  4707. clone.appendChild(
  4708. doc.createTextNode(end.substringData(0, endOffset))
  4709. );
  4710. //is not clone
  4711. if (action) {
  4712. end.deleteData(0, endOffset);
  4713. }
  4714. }
  4715. } else {
  4716. currentLevel = ei.cloneNode(false);
  4717. clone.appendChild(currentLevel);
  4718. }
  4719. //如果两端同级,右边第一次已经被开始做了
  4720. if (j != i || !startParents[i]) {
  4721. while (current) {
  4722. if (current === start) {
  4723. break;
  4724. }
  4725. ei = current.previousSibling;
  4726. clone.insertBefore(
  4727. !action ? current.cloneNode(true) : current,
  4728. clone.firstChild
  4729. );
  4730. current = ei;
  4731. }
  4732. }
  4733. clone = currentLevel;
  4734. }
  4735. if (action) {
  4736. range
  4737. .setStartBefore(
  4738. !endParents[i]
  4739. ? endParents[i - 1]
  4740. : !startParents[i] ? startParents[i - 1] : endParents[i]
  4741. )
  4742. .collapse(true);
  4743. }
  4744. tmpStart && domUtils.remove(tmpStart);
  4745. tmpEnd && domUtils.remove(tmpEnd);
  4746. return frag;
  4747. }
  4748. /**
  4749. * 创建一个跟document绑定的空的Range实例
  4750. * @constructor
  4751. * @param { Document } document 新建的选区所属的文档对象
  4752. */
  4753. /**
  4754. * @property { Node } startContainer 当前Range的开始边界的容器节点, 可以是一个元素节点或者是文本节点
  4755. */
  4756. /**
  4757. * @property { Node } startOffset 当前Range的开始边界容器节点的偏移量, 如果是元素节点,
  4758. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4759. */
  4760. /**
  4761. * @property { Node } endContainer 当前Range的结束边界的容器节点, 可以是一个元素节点或者是文本节点
  4762. */
  4763. /**
  4764. * @property { Node } endOffset 当前Range的结束边界容器节点的偏移量, 如果是元素节点,
  4765. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4766. */
  4767. /**
  4768. * @property { Boolean } collapsed 当前Range是否闭合
  4769. * @default true
  4770. * @remind Range是闭合的时候, startContainer === endContainer && startOffset === endOffset
  4771. */
  4772. /**
  4773. * @property { Document } document 当前Range所属的Document对象
  4774. * @remind 不同range的的document属性可以是不同的
  4775. */
  4776. var Range = (dom.Range = function(document) {
  4777. var me = this;
  4778. me.startContainer = me.startOffset = me.endContainer = me.endOffset = null;
  4779. me.document = document;
  4780. me.collapsed = true;
  4781. });
  4782. /**
  4783. * 删除fillData
  4784. * @param doc
  4785. * @param excludeNode
  4786. */
  4787. function removeFillData(doc, excludeNode) {
  4788. try {
  4789. if (fillData && domUtils.inDoc(fillData, doc)) {
  4790. if (!fillData.nodeValue.replace(fillCharReg, "").length) {
  4791. var tmpNode = fillData.parentNode;
  4792. domUtils.remove(fillData);
  4793. while (
  4794. tmpNode &&
  4795. domUtils.isEmptyInlineElement(tmpNode) &&
  4796. //safari的contains有bug
  4797. (browser.safari
  4798. ? !(
  4799. domUtils.getPosition(tmpNode, excludeNode) &
  4800. domUtils.POSITION_CONTAINS
  4801. )
  4802. : !tmpNode.contains(excludeNode))
  4803. ) {
  4804. fillData = tmpNode.parentNode;
  4805. domUtils.remove(tmpNode);
  4806. tmpNode = fillData;
  4807. }
  4808. } else {
  4809. fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, "");
  4810. }
  4811. }
  4812. } catch (e) {}
  4813. }
  4814. /**
  4815. * @param node
  4816. * @param dir
  4817. */
  4818. function mergeSibling(node, dir) {
  4819. var tmpNode;
  4820. node = node[dir];
  4821. while (node && domUtils.isFillChar(node)) {
  4822. tmpNode = node[dir];
  4823. domUtils.remove(node);
  4824. node = tmpNode;
  4825. }
  4826. }
  4827. Range.prototype = {
  4828. /**
  4829. * 克隆选区的内容到一个DocumentFragment里
  4830. * @method cloneContents
  4831. * @return { DocumentFragment | NULL } 如果选区是闭合的将返回null, 否则, 返回包含所clone内容的DocumentFragment元素
  4832. * @example
  4833. * ```html
  4834. * <body>
  4835. * <!-- 中括号表示选区 -->
  4836. * <b>x<i>x[x</i>xx]x</b>
  4837. *
  4838. * <script>
  4839. * //range是已选中的选区
  4840. * var fragment = range.cloneContents(),
  4841. * node = document.createElement("div");
  4842. *
  4843. * node.appendChild( fragment );
  4844. *
  4845. * //output: <i>x</i>xx
  4846. * console.log( node.innerHTML );
  4847. *
  4848. * </script>
  4849. * </body>
  4850. * ```
  4851. */
  4852. cloneContents: function() {
  4853. return this.collapsed ? null : execContentsAction(this, 0);
  4854. },
  4855. /**
  4856. * 删除当前选区范围中的所有内容
  4857. * @method deleteContents
  4858. * @remind 执行完该操作后, 当前Range对象变成了闭合状态
  4859. * @return { UE.dom.Range } 当前操作的Range对象
  4860. * @example
  4861. * ```html
  4862. * <body>
  4863. * <!-- 中括号表示选区 -->
  4864. * <b>x<i>x[x</i>xx]x</b>
  4865. *
  4866. * <script>
  4867. * //range是已选中的选区
  4868. * range.deleteContents();
  4869. *
  4870. * //竖线表示闭合后的选区位置
  4871. * //output: <b>x<i>x</i>|x</b>
  4872. * console.log( document.body.innerHTML );
  4873. *
  4874. * //此时, range的各项属性为
  4875. * //output: B
  4876. * console.log( range.startContainer.tagName );
  4877. * //output: 2
  4878. * console.log( range.startOffset );
  4879. * //output: B
  4880. * console.log( range.endContainer.tagName );
  4881. * //output: 2
  4882. * console.log( range.endOffset );
  4883. * //output: true
  4884. * console.log( range.collapsed );
  4885. *
  4886. * </script>
  4887. * </body>
  4888. * ```
  4889. */
  4890. deleteContents: function() {
  4891. var txt;
  4892. if (!this.collapsed) {
  4893. execContentsAction(this, 1);
  4894. }
  4895. if (browser.webkit) {
  4896. txt = this.startContainer;
  4897. if (txt.nodeType == 3 && !txt.nodeValue.length) {
  4898. this.setStartBefore(txt).collapse(true);
  4899. domUtils.remove(txt);
  4900. }
  4901. }
  4902. return this;
  4903. },
  4904. /**
  4905. * 将当前选区的内容提取到一个DocumentFragment里
  4906. * @method extractContents
  4907. * @remind 执行该操作后, 选区将变成闭合状态
  4908. * @warning 执行该操作后, 原来选区所选中的内容将从dom树上剥离出来
  4909. * @return { DocumentFragment } 返回包含所提取内容的DocumentFragment对象
  4910. * @example
  4911. * ```html
  4912. * <body>
  4913. * <!-- 中括号表示选区 -->
  4914. * <b>x<i>x[x</i>xx]x</b>
  4915. *
  4916. * <script>
  4917. * //range是已选中的选区
  4918. * var fragment = range.extractContents(),
  4919. * node = document.createElement( "div" );
  4920. *
  4921. * node.appendChild( fragment );
  4922. *
  4923. * //竖线表示闭合后的选区位置
  4924. *
  4925. * //output: <b>x<i>x</i>|x</b>
  4926. * console.log( document.body.innerHTML );
  4927. * //output: <i>x</i>xx
  4928. * console.log( node.innerHTML );
  4929. *
  4930. * //此时, range的各项属性为
  4931. * //output: B
  4932. * console.log( range.startContainer.tagName );
  4933. * //output: 2
  4934. * console.log( range.startOffset );
  4935. * //output: B
  4936. * console.log( range.endContainer.tagName );
  4937. * //output: 2
  4938. * console.log( range.endOffset );
  4939. * //output: true
  4940. * console.log( range.collapsed );
  4941. *
  4942. * </script>
  4943. * </body>
  4944. */
  4945. extractContents: function() {
  4946. return this.collapsed ? null : execContentsAction(this, 2);
  4947. },
  4948. /**
  4949. * 设置Range的开始容器节点和偏移量
  4950. * @method setStart
  4951. * @remind 如果给定的节点是元素节点,那么offset指的是其子元素中索引为offset的元素,
  4952. * 如果是文本节点,那么offset指的是其文本内容的第offset个字符
  4953. * @remind 如果提供的容器节点是一个不能包含子元素的节点, 则该选区的开始容器将被设置
  4954. * 为该节点的父节点, 此时, 其距离开始容器的偏移量也变成了该节点在其父节点
  4955. * 中的索引
  4956. * @param { Node } node 将被设为当前选区开始边界容器的节点对象
  4957. * @param { int } offset 选区的开始位置偏移量
  4958. * @return { UE.dom.Range } 当前range对象
  4959. * @example
  4960. * ```html
  4961. * <!-- 选区 -->
  4962. * <b>xxx<i>x<span>xx</span>xx<em>xx</em>xxx</i>[xxx]</b>
  4963. *
  4964. * <script>
  4965. *
  4966. * //执行操作
  4967. * range.setStart( document.getElementsByTagName("i")[0], 1 );
  4968. *
  4969. * //此时, 选区变成了
  4970. * //<b>xxx<i>x[<span>xx</span>xx<em>xx</em>xxx</i>xxx]</b>
  4971. *
  4972. * </script>
  4973. * ```
  4974. * @example
  4975. * ```html
  4976. * <!-- 选区 -->
  4977. * <b>xxx<img>[xx]x</b>
  4978. *
  4979. * <script>
  4980. *
  4981. * //执行操作
  4982. * range.setStart( document.getElementsByTagName("img")[0], 3 );
  4983. *
  4984. * //此时, 选区变成了
  4985. * //<b>xxx[<img>xx]x</b>
  4986. *
  4987. * </script>
  4988. * ```
  4989. */
  4990. setStart: function(node, offset) {
  4991. return setEndPoint(true, node, offset, this);
  4992. },
  4993. /**
  4994. * 设置Range的结束容器和偏移量
  4995. * @method setEnd
  4996. * @param { Node } node 作为当前选区结束边界容器的节点对象
  4997. * @param { int } offset 结束边界的偏移量
  4998. * @see UE.dom.Range:setStart(Node,int)
  4999. * @return { UE.dom.Range } 当前range对象
  5000. */
  5001. setEnd: function(node, offset) {
  5002. return setEndPoint(false, node, offset, this);
  5003. },
  5004. /**
  5005. * 将Range开始位置设置到node节点之后
  5006. * @method setStartAfter
  5007. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引+1
  5008. * @param { Node } node 选区的开始边界将紧接着该节点之后
  5009. * @return { UE.dom.Range } 当前range对象
  5010. * @example
  5011. * ```html
  5012. * <!-- 选区示例 -->
  5013. * <b>xx<i>xxx</i><span>xx[x</span>xxx]</b>
  5014. *
  5015. * <script>
  5016. *
  5017. * //执行操作
  5018. * range.setStartAfter( document.getElementsByTagName("i")[0] );
  5019. *
  5020. * //结果选区
  5021. * //<b>xx<i>xxx</i>[<span>xxx</span>xxx]</b>
  5022. *
  5023. * </script>
  5024. * ```
  5025. */
  5026. setStartAfter: function(node) {
  5027. return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1);
  5028. },
  5029. /**
  5030. * 将Range开始位置设置到node节点之前
  5031. * @method setStartBefore
  5032. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引
  5033. * @param { Node } node 新的选区开始位置在该节点之前
  5034. * @see UE.dom.Range:setStartAfter(Node)
  5035. * @return { UE.dom.Range } 当前range对象
  5036. */
  5037. setStartBefore: function(node) {
  5038. return this.setStart(node.parentNode, domUtils.getNodeIndex(node));
  5039. },
  5040. /**
  5041. * 将Range结束位置设置到node节点之后
  5042. * @method setEndAfter
  5043. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引+1
  5044. * @param { Node } node 目标节点
  5045. * @see UE.dom.Range:setStartAfter(Node)
  5046. * @return { UE.dom.Range } 当前range对象
  5047. * @example
  5048. * ```html
  5049. * <!-- 选区示例 -->
  5050. * <b>[xx<i>xxx</i><span>xx]x</span>xxx</b>
  5051. *
  5052. * <script>
  5053. *
  5054. * //执行操作
  5055. * range.setStartAfter( document.getElementsByTagName("span")[0] );
  5056. *
  5057. * //结果选区
  5058. * //<b>[xx<i>xxx</i><span>xxx</span>]xxx</b>
  5059. *
  5060. * </script>
  5061. * ```
  5062. */
  5063. setEndAfter: function(node) {
  5064. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1);
  5065. },
  5066. /**
  5067. * 将Range结束位置设置到node节点之前
  5068. * @method setEndBefore
  5069. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引
  5070. * @param { Node } node 目标节点
  5071. * @see UE.dom.Range:setEndAfter(Node)
  5072. * @return { UE.dom.Range } 当前range对象
  5073. */
  5074. setEndBefore: function(node) {
  5075. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node));
  5076. },
  5077. /**
  5078. * 设置Range的开始位置到node节点内的第一个子节点之前
  5079. * @method setStartAtFirst
  5080. * @remind 选区的开始容器将变成给定的节点, 且偏移量为0
  5081. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  5082. * @param { Node } node 目标节点
  5083. * @see UE.dom.Range:setStartBefore(Node)
  5084. * @return { UE.dom.Range } 当前range对象
  5085. * @example
  5086. * ```html
  5087. * <!-- 选区示例 -->
  5088. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5089. *
  5090. * <script>
  5091. *
  5092. * //执行操作
  5093. * range.setStartAtFirst( document.getElementsByTagName("i")[0] );
  5094. *
  5095. * //结果选区
  5096. * //<b>xx<i>[xxx</i><span>xx]x</span>xxx</b>
  5097. *
  5098. * </script>
  5099. * ```
  5100. */
  5101. setStartAtFirst: function(node) {
  5102. return this.setStart(node, 0);
  5103. },
  5104. /**
  5105. * 设置Range的开始位置到node节点内的最后一个节点之后
  5106. * @method setStartAtLast
  5107. * @remind 选区的开始容器将变成给定的节点, 且偏移量为该节点的子节点数
  5108. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  5109. * @param { Node } node 目标节点
  5110. * @see UE.dom.Range:setStartAtFirst(Node)
  5111. * @return { UE.dom.Range } 当前range对象
  5112. */
  5113. setStartAtLast: function(node) {
  5114. return this.setStart(
  5115. node,
  5116. node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length
  5117. );
  5118. },
  5119. /**
  5120. * 设置Range的结束位置到node节点内的第一个节点之前
  5121. * @method setEndAtFirst
  5122. * @param { Node } node 目标节点
  5123. * @remind 选区的结束容器将变成给定的节点, 且偏移量为0
  5124. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  5125. * @see UE.dom.Range:setStartAtFirst(Node)
  5126. * @return { UE.dom.Range } 当前range对象
  5127. */
  5128. setEndAtFirst: function(node) {
  5129. return this.setEnd(node, 0);
  5130. },
  5131. /**
  5132. * 设置Range的结束位置到node节点内的最后一个节点之后
  5133. * @method setEndAtLast
  5134. * @param { Node } node 目标节点
  5135. * @remind 选区的结束容器将变成给定的节点, 且偏移量为该节点的子节点数量
  5136. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  5137. * @see UE.dom.Range:setStartAtFirst(Node)
  5138. * @return { UE.dom.Range } 当前range对象
  5139. */
  5140. setEndAtLast: function(node) {
  5141. return this.setEnd(
  5142. node,
  5143. node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length
  5144. );
  5145. },
  5146. /**
  5147. * 选中给定节点
  5148. * @method selectNode
  5149. * @remind 此时, 选区的开始容器和结束容器都是该节点的父节点, 其startOffset是该节点在父节点中的位置索引,
  5150. * 而endOffset为startOffset+1
  5151. * @param { Node } node 需要选中的节点
  5152. * @return { UE.dom.Range } 当前range对象,此时的range仅包含当前给定的节点对象
  5153. * @example
  5154. * ```html
  5155. * <!-- 选区示例 -->
  5156. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5157. *
  5158. * <script>
  5159. *
  5160. * //执行操作
  5161. * range.selectNode( document.getElementsByTagName("i")[0] );
  5162. *
  5163. * //结果选区
  5164. * //<b>xx[<i>xxx</i>]<span>xxx</span>xxx</b>
  5165. *
  5166. * </script>
  5167. * ```
  5168. */
  5169. selectNode: function(node) {
  5170. return this.setStartBefore(node).setEndAfter(node);
  5171. },
  5172. /**
  5173. * 选中给定节点内部的所有节点
  5174. * @method selectNodeContents
  5175. * @remind 此时, 选区的开始容器和结束容器都是该节点, 其startOffset为0,
  5176. * 而endOffset是该节点的子节点数。
  5177. * @param { Node } node 目标节点, 当前range将包含该节点内的所有节点
  5178. * @return { UE.dom.Range } 当前range对象, 此时range仅包含给定节点的所有子节点
  5179. * @example
  5180. * ```html
  5181. * <!-- 选区示例 -->
  5182. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5183. *
  5184. * <script>
  5185. *
  5186. * //执行操作
  5187. * range.selectNode( document.getElementsByTagName("b")[0] );
  5188. *
  5189. * //结果选区
  5190. * //<b>[xx<i>xxx</i><span>xxx</span>xxx]</b>
  5191. *
  5192. * </script>
  5193. * ```
  5194. */
  5195. selectNodeContents: function(node) {
  5196. return this.setStart(node, 0).setEndAtLast(node);
  5197. },
  5198. /**
  5199. * clone当前Range对象
  5200. * @method cloneRange
  5201. * @remind 返回的range是一个全新的range对象, 其内部所有属性与当前被clone的range相同。
  5202. * @return { UE.dom.Range } 当前range对象的一个副本
  5203. */
  5204. cloneRange: function() {
  5205. var me = this;
  5206. return new Range(me.document)
  5207. .setStart(me.startContainer, me.startOffset)
  5208. .setEnd(me.endContainer, me.endOffset);
  5209. },
  5210. /**
  5211. * 向当前选区的结束处闭合选区
  5212. * @method collapse
  5213. * @return { UE.dom.Range } 当前range对象
  5214. * @example
  5215. * ```html
  5216. * <!-- 选区示例 -->
  5217. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5218. *
  5219. * <script>
  5220. *
  5221. * //执行操作
  5222. * range.collapse();
  5223. *
  5224. * //结果选区
  5225. * //“|”表示选区已闭合
  5226. * //<b>xx<i>xxx</i><span>xx|x</span>xxx</b>
  5227. *
  5228. * </script>
  5229. * ```
  5230. */
  5231. /**
  5232. * 闭合当前选区,根据给定的toStart参数项决定是向当前选区开始处闭合还是向结束处闭合,
  5233. * 如果toStart的值为true,则向开始位置闭合, 反之,向结束位置闭合。
  5234. * @method collapse
  5235. * @param { Boolean } toStart 是否向选区开始处闭合
  5236. * @return { UE.dom.Range } 当前range对象,此时range对象处于闭合状态
  5237. * @see UE.dom.Range:collapse()
  5238. * @example
  5239. * ```html
  5240. * <!-- 选区示例 -->
  5241. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5242. *
  5243. * <script>
  5244. *
  5245. * //执行操作
  5246. * range.collapse( true );
  5247. *
  5248. * //结果选区
  5249. * //“|”表示选区已闭合
  5250. * //<b>xx<i>xxx</i><span>|xxx</span>xxx</b>
  5251. *
  5252. * </script>
  5253. * ```
  5254. */
  5255. collapse: function(toStart) {
  5256. var me = this;
  5257. if (toStart) {
  5258. me.endContainer = me.startContainer;
  5259. me.endOffset = me.startOffset;
  5260. } else {
  5261. me.startContainer = me.endContainer;
  5262. me.startOffset = me.endOffset;
  5263. }
  5264. me.collapsed = true;
  5265. return me;
  5266. },
  5267. /**
  5268. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置
  5269. * @method shrinkBoundary
  5270. * @return { UE.dom.Range } 当前range对象
  5271. * @example
  5272. * ```html
  5273. * <span>xx<b>xx[</b>xxxxx]</span> => <span>xx<b>xx</b>[xxxxx]</span>
  5274. * ```
  5275. *
  5276. * @example
  5277. * ```html
  5278. * <!-- 选区示例 -->
  5279. * <b>x[xx</b><i>]xxx</i>
  5280. *
  5281. * <script>
  5282. *
  5283. * //执行收缩
  5284. * range.shrinkBoundary();
  5285. *
  5286. * //结果选区
  5287. * //<b>x[xx]</b><i>xxx</i>
  5288. * </script>
  5289. * ```
  5290. *
  5291. * @example
  5292. * ```html
  5293. * [<b><i>xxxx</i>xxxxxxx</b>] => <b><i>[xxxx</i>xxxxxxx]</b>
  5294. * ```
  5295. */
  5296. /**
  5297. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置,
  5298. * 如果ignoreEnd的值为true,则忽略对结束位置的调整
  5299. * @method shrinkBoundary
  5300. * @param { Boolean } ignoreEnd 是否忽略对结束位置的调整
  5301. * @return { UE.dom.Range } 当前range对象
  5302. * @see UE.dom.domUtils.Range:shrinkBoundary()
  5303. */
  5304. shrinkBoundary: function(ignoreEnd) {
  5305. var me = this,
  5306. child,
  5307. collapsed = me.collapsed;
  5308. function check(node) {
  5309. return (
  5310. node.nodeType == 1 &&
  5311. !domUtils.isBookmarkNode(node) &&
  5312. !dtd.$empty[node.tagName] &&
  5313. !dtd.$nonChild[node.tagName]
  5314. );
  5315. }
  5316. while (
  5317. me.startContainer.nodeType == 1 && //是element
  5318. (child = me.startContainer.childNodes[me.startOffset]) && //子节点也是element
  5319. check(child)
  5320. ) {
  5321. me.setStart(child, 0);
  5322. }
  5323. if (collapsed) {
  5324. return me.collapse(true);
  5325. }
  5326. if (!ignoreEnd) {
  5327. while (
  5328. me.endContainer.nodeType == 1 && //是element
  5329. me.endOffset > 0 && //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
  5330. (child = me.endContainer.childNodes[me.endOffset - 1]) && //子节点也是element
  5331. check(child)
  5332. ) {
  5333. me.setEnd(child, child.childNodes.length);
  5334. }
  5335. }
  5336. return me;
  5337. },
  5338. /**
  5339. * 获取离当前选区内包含的所有节点最近的公共祖先节点,
  5340. * @method getCommonAncestor
  5341. * @remind 返回的公共祖先节点一定不是range自身的容器节点, 但有可能是一个文本节点
  5342. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5343. * @example
  5344. * ```html
  5345. * //选区示例
  5346. * <span>xxx<b>x[x<em>xx]x</em>xxx</b>xx</span>
  5347. * <script>
  5348. *
  5349. * var node = range.getCommonAncestor();
  5350. *
  5351. * //公共祖先节点是: b节点
  5352. * //输出: B
  5353. * console.log(node.tagName);
  5354. *
  5355. * </script>
  5356. * ```
  5357. */
  5358. /**
  5359. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  5360. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  5361. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点
  5362. * @method getCommonAncestor
  5363. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  5364. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5365. * @see UE.dom.Range:getCommonAncestor()
  5366. * @example
  5367. * ```html
  5368. * <body>
  5369. *
  5370. * <!-- 选区示例 -->
  5371. * <b>xxx<i>xxxx<span>xx[x</span>xx]x</i>xxxxxxx</b>
  5372. *
  5373. * <script>
  5374. *
  5375. * var node = range.getCommonAncestor( false );
  5376. *
  5377. * //这里的公共祖先节点是B而不是I, 是因为参数限制了获取到的节点不能是容器节点
  5378. * //output: B
  5379. * console.log( node.tagName );
  5380. *
  5381. * </script>
  5382. *
  5383. * </body>
  5384. * ```
  5385. */
  5386. /**
  5387. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  5388. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  5389. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点; 同时可以根据
  5390. * ignoreTextNode 参数的取值决定是否忽略类型为文本节点的祖先节点。
  5391. * @method getCommonAncestor
  5392. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  5393. * @param { Boolean } ignoreTextNode 获取祖先节点的过程中是否忽略类型为文本节点的祖先节点
  5394. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5395. * @see UE.dom.Range:getCommonAncestor()
  5396. * @see UE.dom.Range:getCommonAncestor(Boolean)
  5397. * @example
  5398. * ```html
  5399. * <body>
  5400. *
  5401. * <!-- 选区示例 -->
  5402. * <b>xxx<i>xxxx<span>x[x]x</span>xxx</i>xxxxxxx</b>
  5403. *
  5404. * <script>
  5405. *
  5406. * var node = range.getCommonAncestor( true, false );
  5407. *
  5408. * //output: SPAN
  5409. * console.log( node.tagName );
  5410. *
  5411. * </script>
  5412. *
  5413. * </body>
  5414. * ```
  5415. */
  5416. getCommonAncestor: function(includeSelf, ignoreTextNode) {
  5417. var me = this,
  5418. start = me.startContainer,
  5419. end = me.endContainer;
  5420. if (start === end) {
  5421. if (includeSelf && selectOneNode(this)) {
  5422. start = start.childNodes[me.startOffset];
  5423. if (start.nodeType == 1) return start;
  5424. }
  5425. //只有在上来就相等的情况下才会出现是文本的情况
  5426. return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start;
  5427. }
  5428. return domUtils.getCommonAncestor(start, end);
  5429. },
  5430. /**
  5431. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上
  5432. * @method trimBoundary
  5433. * @remind 该操作有可能会引起文本节点被切开
  5434. * @return { UE.dom.Range } 当前range对象
  5435. * @example
  5436. * ```html
  5437. *
  5438. * //选区示例
  5439. * <b>xxx<i>[xxxxx]</i>xxx</b>
  5440. *
  5441. * <script>
  5442. * //未调整前, 选区的开始容器和结束都是文本节点
  5443. * //执行调整
  5444. * range.trimBoundary();
  5445. *
  5446. * //调整之后, 容器节点变成了i节点
  5447. * //<b>xxx[<i>xxxxx</i>]xxx</b>
  5448. * </script>
  5449. * ```
  5450. */
  5451. /**
  5452. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上,
  5453. * 可以根据 ignoreEnd 参数的值决定是否调整对结束边界的调整
  5454. * @method trimBoundary
  5455. * @param { Boolean } ignoreEnd 是否忽略对结束边界的调整
  5456. * @return { UE.dom.Range } 当前range对象
  5457. * @example
  5458. * ```html
  5459. *
  5460. * //选区示例
  5461. * <b>xxx<i>[xxxxx]</i>xxx</b>
  5462. *
  5463. * <script>
  5464. * //未调整前, 选区的开始容器和结束都是文本节点
  5465. * //执行调整
  5466. * range.trimBoundary( true );
  5467. *
  5468. * //调整之后, 开始容器节点变成了i节点
  5469. * //但是, 结束容器没有发生变化
  5470. * //<b>xxx[<i>xxxxx]</i>xxx</b>
  5471. * </script>
  5472. * ```
  5473. */
  5474. trimBoundary: function(ignoreEnd) {
  5475. this.txtToElmBoundary();
  5476. var start = this.startContainer,
  5477. offset = this.startOffset,
  5478. collapsed = this.collapsed,
  5479. end = this.endContainer;
  5480. if (start.nodeType == 3) {
  5481. if (offset == 0) {
  5482. this.setStartBefore(start);
  5483. } else {
  5484. if (offset >= start.nodeValue.length) {
  5485. this.setStartAfter(start);
  5486. } else {
  5487. var textNode = domUtils.split(start, offset);
  5488. //跟新结束边界
  5489. if (start === end) {
  5490. this.setEnd(textNode, this.endOffset - offset);
  5491. } else if (start.parentNode === end) {
  5492. this.endOffset += 1;
  5493. }
  5494. this.setStartBefore(textNode);
  5495. }
  5496. }
  5497. if (collapsed) {
  5498. return this.collapse(true);
  5499. }
  5500. }
  5501. if (!ignoreEnd) {
  5502. offset = this.endOffset;
  5503. end = this.endContainer;
  5504. if (end.nodeType == 3) {
  5505. if (offset == 0) {
  5506. this.setEndBefore(end);
  5507. } else {
  5508. offset < end.nodeValue.length && domUtils.split(end, offset);
  5509. this.setEndAfter(end);
  5510. }
  5511. }
  5512. }
  5513. return this;
  5514. },
  5515. /**
  5516. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则什么也不做
  5517. * @method txtToElmBoundary
  5518. * @remind 该操作不会修改dom节点
  5519. * @return { UE.dom.Range } 当前range对象
  5520. */
  5521. /**
  5522. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则根据参数项
  5523. * ignoreCollapsed 的值决定是否执行该调整
  5524. * @method txtToElmBoundary
  5525. * @param { Boolean } ignoreCollapsed 是否忽略选区的闭合状态, 如果该参数取值为true, 则
  5526. * 不论选区是否闭合, 都会执行该操作, 反之, 则不会对闭合的选区执行该操作
  5527. * @return { UE.dom.Range } 当前range对象
  5528. */
  5529. txtToElmBoundary: function(ignoreCollapsed) {
  5530. function adjust(r, c) {
  5531. var container = r[c + "Container"],
  5532. offset = r[c + "Offset"];
  5533. if (container.nodeType == 3) {
  5534. if (!offset) {
  5535. r[
  5536. "set" +
  5537. c.replace(/(\w)/, function(a) {
  5538. return a.toUpperCase();
  5539. }) +
  5540. "Before"
  5541. ](container);
  5542. } else if (offset >= container.nodeValue.length) {
  5543. r[
  5544. "set" +
  5545. c.replace(/(\w)/, function(a) {
  5546. return a.toUpperCase();
  5547. }) +
  5548. "After"
  5549. ](container);
  5550. }
  5551. }
  5552. }
  5553. if (ignoreCollapsed || !this.collapsed) {
  5554. adjust(this, "start");
  5555. adjust(this, "end");
  5556. }
  5557. return this;
  5558. },
  5559. /**
  5560. * 在当前选区的开始位置前插入节点,新插入的节点会被该range包含
  5561. * @method insertNode
  5562. * @param { Node } node 需要插入的节点
  5563. * @remind 插入的节点可以是一个DocumentFragment依次插入多个节点
  5564. * @return { UE.dom.Range } 当前range对象
  5565. */
  5566. insertNode: function(node) {
  5567. var first = node,
  5568. length = 1;
  5569. if (node.nodeType == 11) {
  5570. first = node.firstChild;
  5571. length = node.childNodes.length;
  5572. }
  5573. this.trimBoundary(true);
  5574. var start = this.startContainer,
  5575. offset = this.startOffset;
  5576. var nextNode = start.childNodes[offset];
  5577. if (nextNode) {
  5578. start.insertBefore(node, nextNode);
  5579. } else {
  5580. start.appendChild(node);
  5581. }
  5582. if (first.parentNode === this.endContainer) {
  5583. this.endOffset = this.endOffset + length;
  5584. }
  5585. return this.setStartBefore(first);
  5586. },
  5587. /**
  5588. * 闭合选区到当前选区的开始位置, 并且定位光标到闭合后的位置
  5589. * @method setCursor
  5590. * @return { UE.dom.Range } 当前range对象
  5591. * @see UE.dom.Range:collapse()
  5592. */
  5593. /**
  5594. * 闭合选区,可以根据参数toEnd的值控制选区是向前闭合还是向后闭合, 并且定位光标到闭合后的位置。
  5595. * @method setCursor
  5596. * @param { Boolean } toEnd 是否向后闭合, 如果为true, 则闭合选区时, 将向结束容器方向闭合,
  5597. * 反之,则向开始容器方向闭合
  5598. * @return { UE.dom.Range } 当前range对象
  5599. * @see UE.dom.Range:collapse(Boolean)
  5600. */
  5601. setCursor: function(toEnd, noFillData) {
  5602. return this.collapse(!toEnd).select(noFillData);
  5603. },
  5604. /**
  5605. * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
  5606. * @method createBookmark
  5607. * @param { Boolean } serialize 控制返回的标记位置是对当前位置的引用还是ID,如果该值为true,则
  5608. * 返回标记位置的ID, 反之则返回标记位置节点的引用
  5609. * @return { Object } 返回一个书签记录键值对, 其包含的key有: start => 开始标记的ID或者引用,
  5610. * end => 结束标记的ID或引用, id => 当前标记的类型, 如果为true,则表示
  5611. * 返回的记录的类型为ID, 反之则为引用
  5612. */
  5613. createBookmark: function(serialize, same) {
  5614. var endNode,
  5615. startNode = this.document.createElement("span");
  5616. startNode.style.cssText = "display:none;line-height:0px;";
  5617. startNode.appendChild(this.document.createTextNode("\u200D"));
  5618. startNode.id = "_baidu_bookmark_start_" + (same ? "" : guid++);
  5619. if (!this.collapsed) {
  5620. endNode = startNode.cloneNode(true);
  5621. endNode.id = "_baidu_bookmark_end_" + (same ? "" : guid++);
  5622. }
  5623. this.insertNode(startNode);
  5624. if (endNode) {
  5625. this.collapse().insertNode(endNode).setEndBefore(endNode);
  5626. }
  5627. this.setStartAfter(startNode);
  5628. return {
  5629. start: serialize ? startNode.id : startNode,
  5630. end: endNode ? (serialize ? endNode.id : endNode) : null,
  5631. id: serialize
  5632. };
  5633. },
  5634. /**
  5635. * 调整当前range的边界到书签位置,并删除该书签对象所标记的位置内的节点
  5636. * @method moveToBookmark
  5637. * @param { BookMark } bookmark createBookmark所创建的标签对象
  5638. * @return { UE.dom.Range } 当前range对象
  5639. * @see UE.dom.Range:createBookmark(Boolean)
  5640. */
  5641. moveToBookmark: function(bookmark) {
  5642. var start = bookmark.id
  5643. ? this.document.getElementById(bookmark.start)
  5644. : bookmark.start,
  5645. end = bookmark.end && bookmark.id
  5646. ? this.document.getElementById(bookmark.end)
  5647. : bookmark.end;
  5648. this.setStartBefore(start);
  5649. domUtils.remove(start);
  5650. if (end) {
  5651. this.setEndBefore(end);
  5652. domUtils.remove(end);
  5653. } else {
  5654. this.collapse(true);
  5655. }
  5656. return this;
  5657. },
  5658. /**
  5659. * 调整range的边界,使其"放大"到最近的父节点
  5660. * @method enlarge
  5661. * @remind 会引起选区的变化
  5662. * @return { UE.dom.Range } 当前range对象
  5663. */
  5664. /**
  5665. * 调整range的边界,使其"放大"到最近的父节点,根据参数 toBlock 的取值, 可以
  5666. * 要求扩大之后的父节点是block节点
  5667. * @method enlarge
  5668. * @param { Boolean } toBlock 是否要求扩大之后的父节点必须是block节点
  5669. * @return { UE.dom.Range } 当前range对象
  5670. */
  5671. enlarge: function(toBlock, stopFn) {
  5672. var isBody = domUtils.isBody,
  5673. pre,
  5674. node,
  5675. tmp = this.document.createTextNode("");
  5676. if (toBlock) {
  5677. node = this.startContainer;
  5678. if (node.nodeType == 1) {
  5679. if (node.childNodes[this.startOffset]) {
  5680. pre = node = node.childNodes[this.startOffset];
  5681. } else {
  5682. node.appendChild(tmp);
  5683. pre = node = tmp;
  5684. }
  5685. } else {
  5686. pre = node;
  5687. }
  5688. while (1) {
  5689. if (domUtils.isBlockElm(node)) {
  5690. node = pre;
  5691. while ((pre = node.previousSibling) && !domUtils.isBlockElm(pre)) {
  5692. node = pre;
  5693. }
  5694. this.setStartBefore(node);
  5695. break;
  5696. }
  5697. pre = node;
  5698. node = node.parentNode;
  5699. }
  5700. node = this.endContainer;
  5701. if (node.nodeType == 1) {
  5702. if ((pre = node.childNodes[this.endOffset])) {
  5703. node.insertBefore(tmp, pre);
  5704. } else {
  5705. node.appendChild(tmp);
  5706. }
  5707. pre = node = tmp;
  5708. } else {
  5709. pre = node;
  5710. }
  5711. while (1) {
  5712. if (domUtils.isBlockElm(node)) {
  5713. node = pre;
  5714. while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) {
  5715. node = pre;
  5716. }
  5717. this.setEndAfter(node);
  5718. break;
  5719. }
  5720. pre = node;
  5721. node = node.parentNode;
  5722. }
  5723. if (tmp.parentNode === this.endContainer) {
  5724. this.endOffset--;
  5725. }
  5726. domUtils.remove(tmp);
  5727. }
  5728. // 扩展边界到最大
  5729. if (!this.collapsed) {
  5730. while (this.startOffset == 0) {
  5731. if (stopFn && stopFn(this.startContainer)) {
  5732. break;
  5733. }
  5734. if (isBody(this.startContainer)) {
  5735. break;
  5736. }
  5737. this.setStartBefore(this.startContainer);
  5738. }
  5739. while (
  5740. this.endOffset ==
  5741. (this.endContainer.nodeType == 1
  5742. ? this.endContainer.childNodes.length
  5743. : this.endContainer.nodeValue.length)
  5744. ) {
  5745. if (stopFn && stopFn(this.endContainer)) {
  5746. break;
  5747. }
  5748. if (isBody(this.endContainer)) {
  5749. break;
  5750. }
  5751. this.setEndAfter(this.endContainer);
  5752. }
  5753. }
  5754. return this;
  5755. },
  5756. enlargeToBlockElm: function(ignoreEnd) {
  5757. while (!domUtils.isBlockElm(this.startContainer)) {
  5758. this.setStartBefore(this.startContainer);
  5759. }
  5760. if (!ignoreEnd) {
  5761. while (!domUtils.isBlockElm(this.endContainer)) {
  5762. this.setEndAfter(this.endContainer);
  5763. }
  5764. }
  5765. return this;
  5766. },
  5767. /**
  5768. * 调整Range的边界,使其"缩小"到最合适的位置
  5769. * @method adjustmentBoundary
  5770. * @return { UE.dom.Range } 当前range对象
  5771. * @see UE.dom.Range:shrinkBoundary()
  5772. */
  5773. adjustmentBoundary: function() {
  5774. if (!this.collapsed) {
  5775. while (
  5776. !domUtils.isBody(this.startContainer) &&
  5777. this.startOffset ==
  5778. this.startContainer[
  5779. this.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  5780. ].length &&
  5781. this.startContainer[
  5782. this.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  5783. ].length
  5784. ) {
  5785. this.setStartAfter(this.startContainer);
  5786. }
  5787. while (
  5788. !domUtils.isBody(this.endContainer) &&
  5789. !this.endOffset &&
  5790. this.endContainer[
  5791. this.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  5792. ].length
  5793. ) {
  5794. this.setEndBefore(this.endContainer);
  5795. }
  5796. }
  5797. return this;
  5798. },
  5799. /**
  5800. * 给range选区中的内容添加给定的inline标签
  5801. * @method applyInlineStyle
  5802. * @param { String } tagName 需要添加的标签名
  5803. * @example
  5804. * ```html
  5805. * <p>xxxx[xxxx]x</p> ==> range.applyInlineStyle("strong") ==> <p>xxxx[<strong>xxxx</strong>]x</p>
  5806. * ```
  5807. */
  5808. /**
  5809. * 给range选区中的内容添加给定的inline标签, 并且为标签附加上一些初始化属性。
  5810. * @method applyInlineStyle
  5811. * @param { String } tagName 需要添加的标签名
  5812. * @param { Object } attrs 跟随新添加的标签的属性
  5813. * @return { UE.dom.Range } 当前选区
  5814. * @example
  5815. * ```html
  5816. * <p>xxxx[xxxx]x</p>
  5817. *
  5818. * ==>
  5819. *
  5820. * <!-- 执行操作 -->
  5821. * range.applyInlineStyle("strong",{"style":"font-size:12px"})
  5822. *
  5823. * ==>
  5824. *
  5825. * <p>xxxx[<strong style="font-size:12px">xxxx</strong>]x</p>
  5826. * ```
  5827. */
  5828. applyInlineStyle: function(tagName, attrs, list) {
  5829. if (this.collapsed) return this;
  5830. this.trimBoundary()
  5831. .enlarge(false, function(node) {
  5832. return node.nodeType == 1 && domUtils.isBlockElm(node);
  5833. })
  5834. .adjustmentBoundary();
  5835. var bookmark = this.createBookmark(),
  5836. end = bookmark.end,
  5837. filterFn = function(node) {
  5838. return node.nodeType == 1
  5839. ? node.tagName.toLowerCase() != "br"
  5840. : !domUtils.isWhitespace(node);
  5841. },
  5842. current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
  5843. node,
  5844. pre,
  5845. range = this.cloneRange();
  5846. while (
  5847. current &&
  5848. domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
  5849. ) {
  5850. if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
  5851. range.setStartBefore(current);
  5852. node = current;
  5853. while (
  5854. node &&
  5855. (node.nodeType == 3 || dtd[tagName][node.tagName]) &&
  5856. node !== end
  5857. ) {
  5858. pre = node;
  5859. node = domUtils.getNextDomNode(
  5860. node,
  5861. node.nodeType == 1,
  5862. null,
  5863. function(parent) {
  5864. return dtd[tagName][parent.tagName];
  5865. }
  5866. );
  5867. }
  5868. var frag = range.setEndAfter(pre).extractContents(),
  5869. elm;
  5870. if (list && list.length > 0) {
  5871. var level, top;
  5872. top = level = list[0].cloneNode(false);
  5873. for (var i = 1, ci; (ci = list[i++]); ) {
  5874. level.appendChild(ci.cloneNode(false));
  5875. level = level.firstChild;
  5876. }
  5877. elm = level;
  5878. } else {
  5879. elm = range.document.createElement(tagName);
  5880. }
  5881. if (attrs) {
  5882. domUtils.setAttributes(elm, attrs);
  5883. }
  5884. elm.appendChild(frag);
  5885. //针对嵌套span的全局样式指定,做容错处理
  5886. if (elm.tagName == "SPAN" && attrs && attrs.style) {
  5887. utils.each(elm.getElementsByTagName("span"), function(s) {
  5888. s.style.cssText = s.style.cssText + ";" + attrs.style;
  5889. });
  5890. }
  5891. range.insertNode(list ? top : elm);
  5892. //处理下滑线在a上的情况
  5893. var aNode;
  5894. if (
  5895. tagName == "span" &&
  5896. attrs.style &&
  5897. /text\-decoration/.test(attrs.style) &&
  5898. (aNode = domUtils.findParentByTagName(elm, "a", true))
  5899. ) {
  5900. domUtils.setAttributes(aNode, attrs);
  5901. domUtils.remove(elm, true);
  5902. elm = aNode;
  5903. } else {
  5904. domUtils.mergeSibling(elm);
  5905. domUtils.clearEmptySibling(elm);
  5906. }
  5907. //去除子节点相同的
  5908. domUtils.mergeChild(elm, attrs);
  5909. current = domUtils.getNextDomNode(elm, false, filterFn);
  5910. domUtils.mergeToParent(elm);
  5911. if (node === end) {
  5912. break;
  5913. }
  5914. } else {
  5915. current = domUtils.getNextDomNode(current, true, filterFn);
  5916. }
  5917. }
  5918. return this.moveToBookmark(bookmark);
  5919. },
  5920. /**
  5921. * 移除当前选区内指定的inline标签,但保留其中的内容
  5922. * @method removeInlineStyle
  5923. * @param { String } tagName 需要移除的标签名
  5924. * @return { UE.dom.Range } 当前的range对象
  5925. * @example
  5926. * ```html
  5927. * xx[x<span>xxx<em>yyy</em>zz]z</span> => range.removeInlineStyle(["em"]) => xx[x<span>xxxyyyzz]z</span>
  5928. * ```
  5929. */
  5930. /**
  5931. * 移除当前选区内指定的一组inline标签,但保留其中的内容
  5932. * @method removeInlineStyle
  5933. * @param { Array } tagNameArr 需要移除的标签名的数组
  5934. * @return { UE.dom.Range } 当前的range对象
  5935. * @see UE.dom.Range:removeInlineStyle(String)
  5936. */
  5937. removeInlineStyle: function(tagNames) {
  5938. if (this.collapsed) return this;
  5939. tagNames = utils.isArray(tagNames) ? tagNames : [tagNames];
  5940. this.shrinkBoundary().adjustmentBoundary();
  5941. var start = this.startContainer,
  5942. end = this.endContainer;
  5943. while (1) {
  5944. if (start.nodeType == 1) {
  5945. if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) {
  5946. break;
  5947. }
  5948. if (start.tagName.toLowerCase() == "body") {
  5949. start = null;
  5950. break;
  5951. }
  5952. }
  5953. start = start.parentNode;
  5954. }
  5955. while (1) {
  5956. if (end.nodeType == 1) {
  5957. if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) {
  5958. break;
  5959. }
  5960. if (end.tagName.toLowerCase() == "body") {
  5961. end = null;
  5962. break;
  5963. }
  5964. }
  5965. end = end.parentNode;
  5966. }
  5967. var bookmark = this.createBookmark(),
  5968. frag,
  5969. tmpRange;
  5970. if (start) {
  5971. tmpRange = this.cloneRange()
  5972. .setEndBefore(bookmark.start)
  5973. .setStartBefore(start);
  5974. frag = tmpRange.extractContents();
  5975. tmpRange.insertNode(frag);
  5976. domUtils.clearEmptySibling(start, true);
  5977. start.parentNode.insertBefore(bookmark.start, start);
  5978. }
  5979. if (end) {
  5980. tmpRange = this.cloneRange()
  5981. .setStartAfter(bookmark.end)
  5982. .setEndAfter(end);
  5983. frag = tmpRange.extractContents();
  5984. tmpRange.insertNode(frag);
  5985. domUtils.clearEmptySibling(end, false, true);
  5986. end.parentNode.insertBefore(bookmark.end, end.nextSibling);
  5987. }
  5988. var current = domUtils.getNextDomNode(bookmark.start, false, function(
  5989. node
  5990. ) {
  5991. return node.nodeType == 1;
  5992. }),
  5993. next;
  5994. while (current && current !== bookmark.end) {
  5995. next = domUtils.getNextDomNode(current, true, function(node) {
  5996. return node.nodeType == 1;
  5997. });
  5998. if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) {
  5999. domUtils.remove(current, true);
  6000. }
  6001. current = next;
  6002. }
  6003. return this.moveToBookmark(bookmark);
  6004. },
  6005. /**
  6006. * 获取当前选中的自闭合的节点
  6007. * @method getClosedNode
  6008. * @return { Node | NULL } 如果当前选中的是自闭合节点, 则返回该节点, 否则返回NULL
  6009. */
  6010. getClosedNode: function() {
  6011. var node;
  6012. if (!this.collapsed) {
  6013. var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
  6014. if (selectOneNode(range)) {
  6015. var child = range.startContainer.childNodes[range.startOffset];
  6016. if (
  6017. child &&
  6018. child.nodeType == 1 &&
  6019. (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])
  6020. ) {
  6021. node = child;
  6022. }
  6023. }
  6024. }
  6025. return node;
  6026. },
  6027. /**
  6028. * 在页面上高亮range所表示的选区
  6029. * @method select
  6030. * @return { UE.dom.Range } 返回当前Range对象
  6031. */
  6032. //这里不区分ie9以上,trace:3824
  6033. select: browser.ie
  6034. ? function(noFillData, textRange) {
  6035. var nativeRange;
  6036. if (!this.collapsed) this.shrinkBoundary();
  6037. var node = this.getClosedNode();
  6038. if (node && !textRange) {
  6039. try {
  6040. nativeRange = this.document.body.createControlRange();
  6041. nativeRange.addElement(node);
  6042. nativeRange.select();
  6043. } catch (e) {}
  6044. return this;
  6045. }
  6046. var bookmark = this.createBookmark(),
  6047. start = bookmark.start,
  6048. end;
  6049. nativeRange = this.document.body.createTextRange();
  6050. nativeRange.moveToElementText(start);
  6051. nativeRange.moveStart("character", 1);
  6052. if (!this.collapsed) {
  6053. var nativeRangeEnd = this.document.body.createTextRange();
  6054. end = bookmark.end;
  6055. nativeRangeEnd.moveToElementText(end);
  6056. nativeRange.setEndPoint("EndToEnd", nativeRangeEnd);
  6057. } else {
  6058. if (!noFillData && this.startContainer.nodeType != 3) {
  6059. //使用<span>|x<span>固定住光标
  6060. var tmpText = this.document.createTextNode(fillChar),
  6061. tmp = this.document.createElement("span");
  6062. tmp.appendChild(this.document.createTextNode(fillChar));
  6063. start.parentNode.insertBefore(tmp, start);
  6064. start.parentNode.insertBefore(tmpText, start);
  6065. //当点b,i,u时,不能清除i上边的b
  6066. removeFillData(this.document, tmpText);
  6067. fillData = tmpText;
  6068. mergeSibling(tmp, "previousSibling");
  6069. mergeSibling(start, "nextSibling");
  6070. nativeRange.moveStart("character", -1);
  6071. nativeRange.collapse(true);
  6072. }
  6073. }
  6074. this.moveToBookmark(bookmark);
  6075. tmp && domUtils.remove(tmp);
  6076. //IE在隐藏状态下不支持range操作,catch一下
  6077. try {
  6078. nativeRange.select();
  6079. } catch (e) {}
  6080. return this;
  6081. }
  6082. : function(notInsertFillData) {
  6083. function checkOffset(rng) {
  6084. function check(node, offset, dir) {
  6085. if (node.nodeType == 3 && node.nodeValue.length < offset) {
  6086. rng[dir + "Offset"] = node.nodeValue.length;
  6087. }
  6088. }
  6089. check(rng.startContainer, rng.startOffset, "start");
  6090. check(rng.endContainer, rng.endOffset, "end");
  6091. }
  6092. var win = domUtils.getWindow(this.document),
  6093. sel = win.getSelection(),
  6094. txtNode;
  6095. //FF下关闭自动长高时滚动条在关闭dialog时会跳
  6096. //ff下如果不body.focus将不能定位闭合光标到编辑器内
  6097. browser.gecko ? this.document.body.focus() : win.focus();
  6098. if (sel) {
  6099. sel.removeAllRanges();
  6100. // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
  6101. // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
  6102. if (this.collapsed && !notInsertFillData) {
  6103. // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
  6104. // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
  6105. // var tmp = this.document.createTextNode('');
  6106. // this.insertNode(tmp).setStart(tmp, 0).collapse(true);
  6107. // }
  6108. //
  6109. //处理光标落在文本节点的情况
  6110. //处理以下的情况
  6111. //<b>|xxxx</b>
  6112. //<b>xxxx</b>|xxxx
  6113. //xxxx<b>|</b>
  6114. var start = this.startContainer,
  6115. child = start;
  6116. if (start.nodeType == 1) {
  6117. child = start.childNodes[this.startOffset];
  6118. }
  6119. if (
  6120. !(start.nodeType == 3 && this.startOffset) &&
  6121. (child
  6122. ? !child.previousSibling ||
  6123. child.previousSibling.nodeType != 3
  6124. : !start.lastChild || start.lastChild.nodeType != 3)
  6125. ) {
  6126. txtNode = this.document.createTextNode(fillChar);
  6127. //跟着前边走
  6128. this.insertNode(txtNode);
  6129. removeFillData(this.document, txtNode);
  6130. mergeSibling(txtNode, "previousSibling");
  6131. mergeSibling(txtNode, "nextSibling");
  6132. fillData = txtNode;
  6133. this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true);
  6134. }
  6135. }
  6136. var nativeRange = this.document.createRange();
  6137. if (
  6138. this.collapsed &&
  6139. browser.opera &&
  6140. this.startContainer.nodeType == 1
  6141. ) {
  6142. var child = this.startContainer.childNodes[this.startOffset];
  6143. if (!child) {
  6144. //往前靠拢
  6145. child = this.startContainer.lastChild;
  6146. if (child && domUtils.isBr(child)) {
  6147. this.setStartBefore(child).collapse(true);
  6148. }
  6149. } else {
  6150. //向后靠拢
  6151. while (child && domUtils.isBlockElm(child)) {
  6152. if (child.nodeType == 1 && child.childNodes[0]) {
  6153. child = child.childNodes[0];
  6154. } else {
  6155. break;
  6156. }
  6157. }
  6158. child && this.setStartBefore(child).collapse(true);
  6159. }
  6160. }
  6161. //是createAddress最后一位算的不准,现在这里进行微调
  6162. checkOffset(this);
  6163. nativeRange.setStart(this.startContainer, this.startOffset);
  6164. nativeRange.setEnd(this.endContainer, this.endOffset);
  6165. sel.addRange(nativeRange);
  6166. }
  6167. return this;
  6168. },
  6169. /**
  6170. * 滚动到当前range开始的位置
  6171. * @method scrollToView
  6172. * @param { Window } win 当前range对象所属的window对象
  6173. * @return { UE.dom.Range } 当前Range对象
  6174. */
  6175. /**
  6176. * 滚动到距离当前range开始位置 offset 的位置处
  6177. * @method scrollToView
  6178. * @param { Window } win 当前range对象所属的window对象
  6179. * @param { Number } offset 距离range开始位置处的偏移量, 如果为正数, 则向下偏移, 反之, 则向上偏移
  6180. * @return { UE.dom.Range } 当前Range对象
  6181. */
  6182. scrollToView: function(win, offset) {
  6183. win = win ? window : domUtils.getWindow(this.document);
  6184. var me = this,
  6185. span = me.document.createElement("span");
  6186. //trace:717
  6187. span.innerHTML = "&nbsp;";
  6188. me.cloneRange().insertNode(span);
  6189. domUtils.scrollToView(span, win, offset);
  6190. domUtils.remove(span);
  6191. return me;
  6192. },
  6193. /**
  6194. * 判断当前选区内容是否占位符
  6195. * @private
  6196. * @method inFillChar
  6197. * @return { Boolean } 如果是占位符返回true,否则返回false
  6198. */
  6199. inFillChar: function() {
  6200. var start = this.startContainer;
  6201. if (
  6202. this.collapsed &&
  6203. start.nodeType == 3 &&
  6204. start.nodeValue.replace(new RegExp("^" + domUtils.fillChar), "")
  6205. .length +
  6206. 1 ==
  6207. start.nodeValue.length
  6208. ) {
  6209. return true;
  6210. }
  6211. return false;
  6212. },
  6213. /**
  6214. * 保存
  6215. * @method createAddress
  6216. * @private
  6217. * @return { Boolean } 返回开始和结束的位置
  6218. * @example
  6219. * ```html
  6220. * <body>
  6221. * <p>
  6222. * aaaa
  6223. * <em>
  6224. * <!-- 选区开始 -->
  6225. * bbbb
  6226. * <!-- 选区结束 -->
  6227. * </em>
  6228. * </p>
  6229. *
  6230. * <script>
  6231. * //output: {startAddress:[0,1,0,0],endAddress:[0,1,0,4]}
  6232. * console.log( range.createAddress() );
  6233. * </script>
  6234. * </body>
  6235. * ```
  6236. */
  6237. createAddress: function(ignoreEnd, ignoreTxt) {
  6238. var addr = {},
  6239. me = this;
  6240. function getAddress(isStart) {
  6241. var node = isStart ? me.startContainer : me.endContainer;
  6242. var parents = domUtils.findParents(node, true, function(node) {
  6243. return !domUtils.isBody(node);
  6244. }),
  6245. addrs = [];
  6246. for (var i = 0, ci; (ci = parents[i++]); ) {
  6247. addrs.push(domUtils.getNodeIndex(ci, ignoreTxt));
  6248. }
  6249. var firstIndex = 0;
  6250. if (ignoreTxt) {
  6251. if (node.nodeType == 3) {
  6252. var tmpNode = node.previousSibling;
  6253. while (tmpNode && tmpNode.nodeType == 3) {
  6254. firstIndex += tmpNode.nodeValue.replace(fillCharReg, "").length;
  6255. tmpNode = tmpNode.previousSibling;
  6256. }
  6257. firstIndex += isStart ? me.startOffset : me.endOffset; // - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
  6258. } else {
  6259. node = node.childNodes[isStart ? me.startOffset : me.endOffset];
  6260. if (node) {
  6261. firstIndex = domUtils.getNodeIndex(node, ignoreTxt);
  6262. } else {
  6263. node = isStart ? me.startContainer : me.endContainer;
  6264. var first = node.firstChild;
  6265. while (first) {
  6266. if (domUtils.isFillChar(first)) {
  6267. first = first.nextSibling;
  6268. continue;
  6269. }
  6270. firstIndex++;
  6271. if (first.nodeType == 3) {
  6272. while (first && first.nodeType == 3) {
  6273. first = first.nextSibling;
  6274. }
  6275. } else {
  6276. first = first.nextSibling;
  6277. }
  6278. }
  6279. }
  6280. }
  6281. } else {
  6282. firstIndex = isStart
  6283. ? domUtils.isFillChar(node) ? 0 : me.startOffset
  6284. : me.endOffset;
  6285. }
  6286. if (firstIndex < 0) {
  6287. firstIndex = 0;
  6288. }
  6289. addrs.push(firstIndex);
  6290. return addrs;
  6291. }
  6292. addr.startAddress = getAddress(true);
  6293. if (!ignoreEnd) {
  6294. addr.endAddress = me.collapsed
  6295. ? [].concat(addr.startAddress)
  6296. : getAddress();
  6297. }
  6298. return addr;
  6299. },
  6300. /**
  6301. * 保存
  6302. * @method createAddress
  6303. * @private
  6304. * @return { Boolean } 返回开始和结束的位置
  6305. * @example
  6306. * ```html
  6307. * <body>
  6308. * <p>
  6309. * aaaa
  6310. * <em>
  6311. * <!-- 选区开始 -->
  6312. * bbbb
  6313. * <!-- 选区结束 -->
  6314. * </em>
  6315. * </p>
  6316. *
  6317. * <script>
  6318. * var range = editor.selection.getRange();
  6319. * range.moveToAddress({startAddress:[0,1,0,0],endAddress:[0,1,0,4]});
  6320. * range.select();
  6321. * //output: 'bbbb'
  6322. * console.log(editor.selection.getText());
  6323. * </script>
  6324. * </body>
  6325. * ```
  6326. */
  6327. moveToAddress: function(addr, ignoreEnd) {
  6328. var me = this;
  6329. function getNode(address, isStart) {
  6330. var tmpNode = me.document.body,
  6331. parentNode,
  6332. offset;
  6333. for (var i = 0, ci, l = address.length; i < l; i++) {
  6334. ci = address[i];
  6335. parentNode = tmpNode;
  6336. tmpNode = tmpNode.childNodes[ci];
  6337. if (!tmpNode) {
  6338. offset = ci;
  6339. break;
  6340. }
  6341. }
  6342. if (isStart) {
  6343. if (tmpNode) {
  6344. me.setStartBefore(tmpNode);
  6345. } else {
  6346. me.setStart(parentNode, offset);
  6347. }
  6348. } else {
  6349. if (tmpNode) {
  6350. me.setEndBefore(tmpNode);
  6351. } else {
  6352. me.setEnd(parentNode, offset);
  6353. }
  6354. }
  6355. }
  6356. getNode(addr.startAddress, true);
  6357. !ignoreEnd && addr.endAddress && getNode(addr.endAddress);
  6358. return me;
  6359. },
  6360. /**
  6361. * 判断给定的Range对象是否和当前Range对象表示的是同一个选区
  6362. * @method equals
  6363. * @param { UE.dom.Range } 需要判断的Range对象
  6364. * @return { Boolean } 如果给定的Range对象与当前Range对象表示的是同一个选区, 则返回true, 否则返回false
  6365. */
  6366. equals: function(rng) {
  6367. for (var p in this) {
  6368. if (this.hasOwnProperty(p)) {
  6369. if (this[p] !== rng[p]) return false;
  6370. }
  6371. }
  6372. return true;
  6373. },
  6374. /**
  6375. * 遍历range内的节点。每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  6376. * 作为其参数。
  6377. * @method traversal
  6378. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  6379. * @return { UE.dom.Range } 当前range对象
  6380. * @example
  6381. * ```html
  6382. *
  6383. * <body>
  6384. *
  6385. * <!-- 选区开始 -->
  6386. * <span></span>
  6387. * <a></a>
  6388. * <!-- 选区结束 -->
  6389. * </body>
  6390. *
  6391. * <script>
  6392. *
  6393. * //output: <span></span><a></a>
  6394. * console.log( range.cloneContents() );
  6395. *
  6396. * range.traversal( function ( node ) {
  6397. *
  6398. * if ( node.nodeType === 1 ) {
  6399. * node.className = "test";
  6400. * }
  6401. *
  6402. * } );
  6403. *
  6404. * //output: <span class="test"></span><a class="test"></a>
  6405. * console.log( range.cloneContents() );
  6406. *
  6407. * </script>
  6408. * ```
  6409. */
  6410. /**
  6411. * 遍历range内的节点。
  6412. * 每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  6413. * 作为其参数。
  6414. * 可以通过参数项 filterFn 来指定一个过滤器, 只有符合该过滤器过滤规则的节点才会触
  6415. * 发doFn函数的执行
  6416. * @method traversal
  6417. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  6418. * @param { Function } filterFn 过滤器, 该函数接受当前遍历的节点作为参数, 如果该节点满足过滤
  6419. * 规则, 请返回true, 该节点会触发doFn, 否则, 请返回false, 则该节点不
  6420. * 会触发doFn。
  6421. * @return { UE.dom.Range } 当前range对象
  6422. * @see UE.dom.Range:traversal(Function)
  6423. * @example
  6424. * ```html
  6425. *
  6426. * <body>
  6427. *
  6428. * <!-- 选区开始 -->
  6429. * <span></span>
  6430. * <a></a>
  6431. * <!-- 选区结束 -->
  6432. * </body>
  6433. *
  6434. * <script>
  6435. *
  6436. * //output: <span></span><a></a>
  6437. * console.log( range.cloneContents() );
  6438. *
  6439. * range.traversal( function ( node ) {
  6440. *
  6441. * node.className = "test";
  6442. *
  6443. * }, function ( node ) {
  6444. * return node.nodeType === 1;
  6445. * } );
  6446. *
  6447. * //output: <span class="test"></span><a class="test"></a>
  6448. * console.log( range.cloneContents() );
  6449. *
  6450. * </script>
  6451. * ```
  6452. */
  6453. traversal: function(doFn, filterFn) {
  6454. if (this.collapsed) return this;
  6455. var bookmark = this.createBookmark(),
  6456. end = bookmark.end,
  6457. current = domUtils.getNextDomNode(bookmark.start, false, filterFn);
  6458. while (
  6459. current &&
  6460. current !== end &&
  6461. domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
  6462. ) {
  6463. var tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  6464. doFn(current);
  6465. current = tmpNode;
  6466. }
  6467. return this.moveToBookmark(bookmark);
  6468. }
  6469. };
  6470. })();
  6471. // core/Selection.js
  6472. /**
  6473. * 选集
  6474. * @file
  6475. * @module UE.dom
  6476. * @class Selection
  6477. * @since 1.2.6.1
  6478. */
  6479. /**
  6480. * 选区集合
  6481. * @unfile
  6482. * @module UE.dom
  6483. * @class Selection
  6484. */
  6485. ;(function() {
  6486. function getBoundaryInformation(range, start) {
  6487. var getIndex = domUtils.getNodeIndex;
  6488. range = range.duplicate();
  6489. range.collapse(start);
  6490. var parent = range.parentElement();
  6491. //如果节点里没有子节点,直接退出
  6492. if (!parent.hasChildNodes()) {
  6493. return { container: parent, offset: 0 };
  6494. }
  6495. var siblings = parent.children,
  6496. child,
  6497. testRange = range.duplicate(),
  6498. startIndex = 0,
  6499. endIndex = siblings.length - 1,
  6500. index = -1,
  6501. distance;
  6502. while (startIndex <= endIndex) {
  6503. index = Math.floor((startIndex + endIndex) / 2);
  6504. child = siblings[index];
  6505. testRange.moveToElementText(child);
  6506. var position = testRange.compareEndPoints("StartToStart", range);
  6507. if (position > 0) {
  6508. endIndex = index - 1;
  6509. } else if (position < 0) {
  6510. startIndex = index + 1;
  6511. } else {
  6512. //trace:1043
  6513. return { container: parent, offset: getIndex(child) };
  6514. }
  6515. }
  6516. if (index == -1) {
  6517. testRange.moveToElementText(parent);
  6518. testRange.setEndPoint("StartToStart", range);
  6519. distance = testRange.text.replace(/(\r\n|\r)/g, "\n").length;
  6520. siblings = parent.childNodes;
  6521. if (!distance) {
  6522. child = siblings[siblings.length - 1];
  6523. return { container: child, offset: child.nodeValue.length };
  6524. }
  6525. var i = siblings.length;
  6526. while (distance > 0) {
  6527. distance -= siblings[--i].nodeValue.length;
  6528. }
  6529. return { container: siblings[i], offset: -distance };
  6530. }
  6531. testRange.collapse(position > 0);
  6532. testRange.setEndPoint(position > 0 ? "StartToStart" : "EndToStart", range);
  6533. distance = testRange.text.replace(/(\r\n|\r)/g, "\n").length;
  6534. if (!distance) {
  6535. return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName]
  6536. ? {
  6537. container: parent,
  6538. offset: getIndex(child) + (position > 0 ? 0 : 1)
  6539. }
  6540. : {
  6541. container: child,
  6542. offset: position > 0 ? 0 : child.childNodes.length
  6543. };
  6544. }
  6545. while (distance > 0) {
  6546. try {
  6547. var pre = child;
  6548. child = child[position > 0 ? "previousSibling" : "nextSibling"];
  6549. distance -= child.nodeValue.length;
  6550. } catch (e) {
  6551. return { container: parent, offset: getIndex(pre) };
  6552. }
  6553. }
  6554. return {
  6555. container: child,
  6556. offset: position > 0 ? -distance : child.nodeValue.length + distance
  6557. };
  6558. }
  6559. /**
  6560. * 将ieRange转换为Range对象
  6561. * @param {Range} ieRange ieRange对象
  6562. * @param {Range} range Range对象
  6563. * @return {Range} range 返回转换后的Range对象
  6564. */
  6565. function transformIERangeToRange(ieRange, range) {
  6566. if (ieRange.item) {
  6567. range.selectNode(ieRange.item(0));
  6568. } else {
  6569. var bi = getBoundaryInformation(ieRange, true);
  6570. range.setStart(bi.container, bi.offset);
  6571. if (ieRange.compareEndPoints("StartToEnd", ieRange) != 0) {
  6572. bi = getBoundaryInformation(ieRange, false);
  6573. range.setEnd(bi.container, bi.offset);
  6574. }
  6575. }
  6576. return range;
  6577. }
  6578. /**
  6579. * 获得ieRange
  6580. * @param {Selection} sel Selection对象
  6581. * @return {ieRange} 得到ieRange
  6582. */
  6583. function _getIERange(sel) {
  6584. var ieRange;
  6585. //ie下有可能报错
  6586. try {
  6587. ieRange = sel.getNative().createRange();
  6588. } catch (e) {
  6589. return null;
  6590. }
  6591. var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
  6592. if ((el.ownerDocument || el) === sel.document) {
  6593. return ieRange;
  6594. }
  6595. return null;
  6596. }
  6597. var Selection = (dom.Selection = function(doc) {
  6598. var me = this,
  6599. iframe;
  6600. me.document = doc;
  6601. if (browser.ie9below) {
  6602. iframe = domUtils.getWindow(doc).frameElement;
  6603. domUtils.on(iframe, "beforedeactivate", function() {
  6604. me._bakIERange = me.getIERange();
  6605. });
  6606. domUtils.on(iframe, "activate", function() {
  6607. try {
  6608. if (!_getIERange(me) && me._bakIERange) {
  6609. me._bakIERange.select();
  6610. }
  6611. } catch (ex) {}
  6612. me._bakIERange = null;
  6613. });
  6614. }
  6615. iframe = doc = null;
  6616. });
  6617. Selection.prototype = {
  6618. rangeInBody: function(rng, txtRange) {
  6619. var node = browser.ie9below || txtRange
  6620. ? rng.item ? rng.item() : rng.parentElement()
  6621. : rng.startContainer;
  6622. return node === this.document.body || domUtils.inDoc(node, this.document);
  6623. },
  6624. /**
  6625. * 获取原生seleciton对象
  6626. * @method getNative
  6627. * @return { Object } 获得selection对象
  6628. * @example
  6629. * ```javascript
  6630. * editor.selection.getNative();
  6631. * ```
  6632. */
  6633. getNative: function() {
  6634. var doc = this.document;
  6635. try {
  6636. return !doc
  6637. ? null
  6638. : browser.ie9below
  6639. ? doc.selection
  6640. : domUtils.getWindow(doc).getSelection();
  6641. } catch (e) {
  6642. return null;
  6643. }
  6644. },
  6645. /**
  6646. * 获得ieRange
  6647. * @method getIERange
  6648. * @return { Object } 返回ie原生的Range
  6649. * @example
  6650. * ```javascript
  6651. * editor.selection.getIERange();
  6652. * ```
  6653. */
  6654. getIERange: function() {
  6655. var ieRange = _getIERange(this);
  6656. if (!ieRange) {
  6657. if (this._bakIERange) {
  6658. return this._bakIERange;
  6659. }
  6660. }
  6661. return ieRange;
  6662. },
  6663. /**
  6664. * 缓存当前选区的range和选区的开始节点
  6665. * @method cache
  6666. */
  6667. cache: function() {
  6668. this.clear();
  6669. this._cachedRange = this.getRange();
  6670. this._cachedStartElement = this.getStart();
  6671. this._cachedStartElementPath = this.getStartElementPath();
  6672. },
  6673. /**
  6674. * 获取选区开始位置的父节点到body
  6675. * @method getStartElementPath
  6676. * @return { Array } 返回父节点集合
  6677. * @example
  6678. * ```javascript
  6679. * editor.selection.getStartElementPath();
  6680. * ```
  6681. */
  6682. getStartElementPath: function() {
  6683. if (this._cachedStartElementPath) {
  6684. return this._cachedStartElementPath;
  6685. }
  6686. var start = this.getStart();
  6687. if (start) {
  6688. return domUtils.findParents(start, true, null, true);
  6689. }
  6690. return [];
  6691. },
  6692. /**
  6693. * 清空缓存
  6694. * @method clear
  6695. */
  6696. clear: function() {
  6697. this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null;
  6698. },
  6699. /**
  6700. * 编辑器是否得到了选区
  6701. * @method isFocus
  6702. */
  6703. isFocus: function() {
  6704. try {
  6705. if (browser.ie9below) {
  6706. var nativeRange = _getIERange(this);
  6707. return !!(nativeRange && this.rangeInBody(nativeRange));
  6708. } else {
  6709. return !!this.getNative().rangeCount;
  6710. }
  6711. } catch (e) {
  6712. return false;
  6713. }
  6714. },
  6715. /**
  6716. * 获取选区对应的Range
  6717. * @method getRange
  6718. * @return { Object } 得到Range对象
  6719. * @example
  6720. * ```javascript
  6721. * editor.selection.getRange();
  6722. * ```
  6723. */
  6724. getRange: function() {
  6725. var me = this;
  6726. function optimze(range) {
  6727. var child = me.document.body.firstChild,
  6728. collapsed = range.collapsed;
  6729. while (child && child.firstChild) {
  6730. range.setStart(child, 0);
  6731. child = child.firstChild;
  6732. }
  6733. if (!range.startContainer) {
  6734. range.setStart(me.document.body, 0);
  6735. }
  6736. if (collapsed) {
  6737. range.collapse(true);
  6738. }
  6739. }
  6740. if (me._cachedRange != null) {
  6741. return this._cachedRange;
  6742. }
  6743. var range = new baidu.editor.dom.Range(me.document);
  6744. if (browser.ie9below) {
  6745. var nativeRange = me.getIERange();
  6746. if (nativeRange) {
  6747. //备份的_bakIERange可能已经实效了,dom树发生了变化比如从源码模式切回来,所以try一下,实效就放到body开始位置
  6748. try {
  6749. transformIERangeToRange(nativeRange, range);
  6750. } catch (e) {
  6751. optimze(range);
  6752. }
  6753. } else {
  6754. optimze(range);
  6755. }
  6756. } else {
  6757. var sel = me.getNative();
  6758. if (sel && sel.rangeCount) {
  6759. var firstRange = sel.getRangeAt(0);
  6760. var lastRange = sel.getRangeAt(sel.rangeCount - 1);
  6761. range
  6762. .setStart(firstRange.startContainer, firstRange.startOffset)
  6763. .setEnd(lastRange.endContainer, lastRange.endOffset);
  6764. if (
  6765. range.collapsed &&
  6766. domUtils.isBody(range.startContainer) &&
  6767. !range.startOffset
  6768. ) {
  6769. optimze(range);
  6770. }
  6771. } else {
  6772. //trace:1734 有可能已经不在dom树上了,标识的节点
  6773. if (
  6774. this._bakRange &&
  6775. domUtils.inDoc(this._bakRange.startContainer, this.document)
  6776. ) {
  6777. return this._bakRange;
  6778. }
  6779. optimze(range);
  6780. }
  6781. }
  6782. return (this._bakRange = range);
  6783. },
  6784. /**
  6785. * 获取开始元素,用于状态反射
  6786. * @method getStart
  6787. * @return { Element } 获得开始元素
  6788. * @example
  6789. * ```javascript
  6790. * editor.selection.getStart();
  6791. * ```
  6792. */
  6793. getStart: function() {
  6794. if (this._cachedStartElement) {
  6795. return this._cachedStartElement;
  6796. }
  6797. var range = browser.ie9below ? this.getIERange() : this.getRange(),
  6798. tmpRange,
  6799. start,
  6800. tmp,
  6801. parent;
  6802. if (browser.ie9below) {
  6803. if (!range) {
  6804. //todo 给第一个值可能会有问题
  6805. return this.document.body.firstChild;
  6806. }
  6807. //control元素
  6808. if (range.item) {
  6809. return range.item(0);
  6810. }
  6811. tmpRange = range.duplicate();
  6812. //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
  6813. tmpRange.text.length > 0 && tmpRange.moveStart("character", 1);
  6814. tmpRange.collapse(1);
  6815. start = tmpRange.parentElement();
  6816. parent = tmp = range.parentElement();
  6817. while ((tmp = tmp.parentNode)) {
  6818. if (tmp == start) {
  6819. start = parent;
  6820. break;
  6821. }
  6822. }
  6823. } else {
  6824. range.shrinkBoundary();
  6825. start = range.startContainer;
  6826. if (start.nodeType == 1 && start.hasChildNodes()) {
  6827. start =
  6828. start.childNodes[
  6829. Math.min(start.childNodes.length - 1, range.startOffset)
  6830. ];
  6831. }
  6832. if (start.nodeType == 3) {
  6833. return start.parentNode;
  6834. }
  6835. }
  6836. return start;
  6837. },
  6838. /**
  6839. * 得到选区中的文本
  6840. * @method getText
  6841. * @return { String } 选区中包含的文本
  6842. * @example
  6843. * ```javascript
  6844. * editor.selection.getText();
  6845. * ```
  6846. */
  6847. getText: function() {
  6848. var nativeSel, nativeRange;
  6849. if (this.isFocus() && (nativeSel = this.getNative())) {
  6850. nativeRange = browser.ie9below
  6851. ? nativeSel.createRange()
  6852. : nativeSel.getRangeAt(0);
  6853. return browser.ie9below ? nativeRange.text : nativeRange.toString();
  6854. }
  6855. return "";
  6856. },
  6857. /**
  6858. * 清除选区
  6859. * @method clearRange
  6860. * @example
  6861. * ```javascript
  6862. * editor.selection.clearRange();
  6863. * ```
  6864. */
  6865. clearRange: function() {
  6866. this.getNative()[browser.ie9below ? "empty" : "removeAllRanges"]();
  6867. }
  6868. };
  6869. })();
  6870. // core/Editor.js
  6871. /**
  6872. * 编辑器主类,包含编辑器提供的大部分公用接口
  6873. * @file
  6874. * @module UE
  6875. * @class Editor
  6876. * @since 1.2.6.1
  6877. */
  6878. /**
  6879. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  6880. * @unfile
  6881. * @module UE
  6882. */
  6883. /**
  6884. * UEditor的核心类,为用户提供与编辑器交互的接口。
  6885. * @unfile
  6886. * @module UE
  6887. * @class Editor
  6888. */
  6889. ;(function() {
  6890. var uid = 0,
  6891. _selectionChangeTimer;
  6892. /**
  6893. * 获取编辑器的html内容,赋值到编辑器所在表单的textarea文本域里面
  6894. * @private
  6895. * @method setValue
  6896. * @param { UE.Editor } editor 编辑器事例
  6897. */
  6898. function setValue(form, editor) {
  6899. var textarea;
  6900. if (editor.options.textarea) {
  6901. if (utils.isString(editor.options.textarea)) {
  6902. for (
  6903. var i = 0, ti, tis = domUtils.getElementsByTagName(form, "textarea");
  6904. (ti = tis[i++]);
  6905. ) {
  6906. if (ti.id == "ueditor_textarea_" + editor.options.textarea) {
  6907. textarea = ti;
  6908. break;
  6909. }
  6910. }
  6911. } else {
  6912. textarea = editor.textarea;
  6913. }
  6914. }
  6915. if (!textarea) {
  6916. form.appendChild(
  6917. (textarea = domUtils.createElement(document, "textarea", {
  6918. name: editor.options.textarea,
  6919. id: "ueditor_textarea_" + editor.options.textarea,
  6920. style: "display:none"
  6921. }))
  6922. );
  6923. //不要产生多个textarea
  6924. editor.textarea = textarea;
  6925. }
  6926. !textarea.getAttribute("name") &&
  6927. textarea.setAttribute("name", editor.options.textarea);
  6928. textarea.value = editor.hasContents()
  6929. ? editor.options.allHtmlEnabled
  6930. ? editor.getAllHtml()
  6931. : editor.getContent(null, null, true)
  6932. : "";
  6933. }
  6934. function loadPlugins(me) {
  6935. //初始化插件
  6936. for (var pi in UE.plugins) {
  6937. UE.plugins[pi].call(me);
  6938. }
  6939. }
  6940. function checkCurLang(I18N) {
  6941. for (var lang in I18N) {
  6942. return lang;
  6943. }
  6944. }
  6945. function langReadied(me) {
  6946. me.langIsReady = true;
  6947. me.fireEvent("langReady");
  6948. }
  6949. /**
  6950. * 编辑器准备就绪后会触发该事件
  6951. * @module UE
  6952. * @class Editor
  6953. * @event ready
  6954. * @remind render方法执行完成之后,会触发该事件
  6955. * @remind
  6956. * @example
  6957. * ```javascript
  6958. * editor.addListener( 'ready', function( editor ) {
  6959. * editor.execCommand( 'focus' ); //编辑器家在完成后,让编辑器拿到焦点
  6960. * } );
  6961. * ```
  6962. */
  6963. /**
  6964. * 执行destroy方法,会触发该事件
  6965. * @module UE
  6966. * @class Editor
  6967. * @event destroy
  6968. * @see UE.Editor:destroy()
  6969. */
  6970. /**
  6971. * 执行reset方法,会触发该事件
  6972. * @module UE
  6973. * @class Editor
  6974. * @event reset
  6975. * @see UE.Editor:reset()
  6976. */
  6977. /**
  6978. * 执行focus方法,会触发该事件
  6979. * @module UE
  6980. * @class Editor
  6981. * @event focus
  6982. * @see UE.Editor:focus(Boolean)
  6983. */
  6984. /**
  6985. * 语言加载完成会触发该事件
  6986. * @module UE
  6987. * @class Editor
  6988. * @event langReady
  6989. */
  6990. /**
  6991. * 运行命令之后会触发该命令
  6992. * @module UE
  6993. * @class Editor
  6994. * @event beforeExecCommand
  6995. */
  6996. /**
  6997. * 运行命令之后会触发该命令
  6998. * @module UE
  6999. * @class Editor
  7000. * @event afterExecCommand
  7001. */
  7002. /**
  7003. * 运行命令之前会触发该命令
  7004. * @module UE
  7005. * @class Editor
  7006. * @event firstBeforeExecCommand
  7007. */
  7008. /**
  7009. * 在getContent方法执行之前会触发该事件
  7010. * @module UE
  7011. * @class Editor
  7012. * @event beforeGetContent
  7013. * @see UE.Editor:getContent()
  7014. */
  7015. /**
  7016. * 在getContent方法执行之后会触发该事件
  7017. * @module UE
  7018. * @class Editor
  7019. * @event afterGetContent
  7020. * @see UE.Editor:getContent()
  7021. */
  7022. /**
  7023. * 在getAllHtml方法执行时会触发该事件
  7024. * @module UE
  7025. * @class Editor
  7026. * @event getAllHtml
  7027. * @see UE.Editor:getAllHtml()
  7028. */
  7029. /**
  7030. * 在setContent方法执行之前会触发该事件
  7031. * @module UE
  7032. * @class Editor
  7033. * @event beforeSetContent
  7034. * @see UE.Editor:setContent(String)
  7035. */
  7036. /**
  7037. * 在setContent方法执行之后会触发该事件
  7038. * @module UE
  7039. * @class Editor
  7040. * @event afterSetContent
  7041. * @see UE.Editor:setContent(String)
  7042. */
  7043. /**
  7044. * 每当编辑器内部选区发生改变时,将触发该事件
  7045. * @event selectionchange
  7046. * @warning 该事件的触发非常频繁,不建议在该事件的处理过程中做重量级的处理
  7047. * @example
  7048. * ```javascript
  7049. * editor.addListener( 'selectionchange', function( editor ) {
  7050. * console.log('选区发生改变');
  7051. * }
  7052. */
  7053. /**
  7054. * 在所有selectionchange的监听函数执行之前,会触发该事件
  7055. * @module UE
  7056. * @class Editor
  7057. * @event beforeSelectionChange
  7058. * @see UE.Editor:selectionchange
  7059. */
  7060. /**
  7061. * 在所有selectionchange的监听函数执行完之后,会触发该事件
  7062. * @module UE
  7063. * @class Editor
  7064. * @event afterSelectionChange
  7065. * @see UE.Editor:selectionchange
  7066. */
  7067. /**
  7068. * 编辑器内容发生改变时会触发该事件
  7069. * @module UE
  7070. * @class Editor
  7071. * @event contentChange
  7072. */
  7073. /**
  7074. * 以默认参数构建一个编辑器实例
  7075. * @constructor
  7076. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  7077. * @example
  7078. * ```javascript
  7079. * var editor = new UE.Editor();
  7080. * editor.execCommand('blod');
  7081. * ```
  7082. * @see UE.Config
  7083. */
  7084. /**
  7085. * 以给定的参数集合创建一个编辑器实例,对于未指定的参数,将应用默认参数。
  7086. * @constructor
  7087. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  7088. * @param { Object } setting 创建编辑器的参数
  7089. * @example
  7090. * ```javascript
  7091. * var editor = new UE.Editor();
  7092. * editor.execCommand('blod');
  7093. * ```
  7094. * @see UE.Config
  7095. */
  7096. var Editor = (UE.Editor = function(options) {
  7097. var me = this;
  7098. me.uid = uid++;
  7099. EventBase.call(me);
  7100. me.commands = {};
  7101. me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true);
  7102. me.shortcutkeys = {};
  7103. me.inputRules = [];
  7104. me.outputRules = [];
  7105. //设置默认的常用属性
  7106. me.setOpt(Editor.defaultOptions(me));
  7107. /* 尝试异步加载后台配置 */
  7108. me.loadServerConfig();
  7109. if (!utils.isEmptyObject(UE.I18N)) {
  7110. //修改默认的语言类型
  7111. me.options.lang = checkCurLang(UE.I18N);
  7112. UE.plugin.load(me);
  7113. langReadied(me);
  7114. } else {
  7115. utils.loadFile(
  7116. document,
  7117. {
  7118. src:
  7119. me.options.langPath +
  7120. me.options.lang +
  7121. "/" +
  7122. me.options.lang +
  7123. ".js",
  7124. tag: "script",
  7125. type: "text/javascript",
  7126. defer: "defer"
  7127. },
  7128. function() {
  7129. UE.plugin.load(me);
  7130. langReadied(me);
  7131. }
  7132. );
  7133. }
  7134. UE.instants["ueditorInstant" + me.uid] = me;
  7135. });
  7136. Editor.prototype = {
  7137. registerCommand: function(name, obj) {
  7138. this.commands[name] = obj;
  7139. },
  7140. /**
  7141. * 编辑器对外提供的监听ready事件的接口, 通过调用该方法,达到的效果与监听ready事件是一致的
  7142. * @method ready
  7143. * @param { Function } fn 编辑器ready之后所执行的回调, 如果在注册事件之前编辑器已经ready,将会
  7144. * 立即触发该回调。
  7145. * @remind 需要等待编辑器加载完成后才能执行的代码,可以使用该方法传入
  7146. * @example
  7147. * ```javascript
  7148. * editor.ready( function( editor ) {
  7149. * editor.setContent('初始化完毕');
  7150. * } );
  7151. * ```
  7152. * @see UE.Editor.event:ready
  7153. */
  7154. ready: function(fn) {
  7155. var me = this;
  7156. if (fn) {
  7157. me.isReady ? fn.apply(me) : me.addListener("ready", fn);
  7158. }
  7159. },
  7160. /**
  7161. * 该方法用于设置placeholder
  7162. * @method setPlaceholder
  7163. * @param { String } placeholder 编辑器的placeholder文案
  7164. * @example
  7165. * ```javascript
  7166. * editor.setPlaceholder('请输入内容');
  7167. * ```
  7168. */
  7169. setPlaceholder: function(){
  7170. function contentChange(){
  7171. var localHtml = this.getPlainTxt();
  7172. if(!localHtml.trim()){
  7173. UE.dom.domUtils.addClass( this.body, 'empty' );
  7174. }else{
  7175. UE.dom.domUtils.removeClasses( this.body, 'empty' );
  7176. }
  7177. }
  7178. return function(placeholder){
  7179. var _editor = this;
  7180. _editor.ready(function () {
  7181. contentChange.call(_editor);
  7182. _editor.body.setAttribute('placeholder', placeholder);
  7183. });
  7184. _editor.removeListener('keyup contentchange', contentChange);
  7185. _editor.addListener('keyup contentchange', contentChange);
  7186. }
  7187. }(),
  7188. /**
  7189. * 该方法是提供给插件里面使用,设置配置项默认值
  7190. * @method setOpt
  7191. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  7192. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  7193. * @param { String } key 编辑器的可接受的选项名称
  7194. * @param { * } val 该选项可接受的值
  7195. * @example
  7196. * ```javascript
  7197. * editor.setOpt( 'initContent', '欢迎使用编辑器' );
  7198. * ```
  7199. */
  7200. /**
  7201. * 该方法是提供给插件里面使用,以{key:value}集合的方式设置插件内用到的配置项默认值
  7202. * @method setOpt
  7203. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  7204. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  7205. * @param { Object } options 将要设置的选项的键值对对象
  7206. * @example
  7207. * ```javascript
  7208. * editor.setOpt( {
  7209. * 'initContent': '欢迎使用编辑器'
  7210. * } );
  7211. * ```
  7212. */
  7213. setOpt: function(key, val) {
  7214. var obj = {};
  7215. if (utils.isString(key)) {
  7216. obj[key] = val;
  7217. } else {
  7218. obj = key;
  7219. }
  7220. utils.extend(this.options, obj, true);
  7221. },
  7222. getOpt: function(key) {
  7223. return this.options[key];
  7224. },
  7225. /**
  7226. * 销毁编辑器实例,使用textarea代替
  7227. * @method destroy
  7228. * @example
  7229. * ```javascript
  7230. * editor.destroy();
  7231. * ```
  7232. */
  7233. destroy: function() {
  7234. var me = this;
  7235. me.fireEvent("destroy");
  7236. var container = me.container.parentNode;
  7237. var textarea = me.textarea;
  7238. if (!textarea) {
  7239. textarea = document.createElement("textarea");
  7240. container.parentNode.insertBefore(textarea, container);
  7241. } else {
  7242. textarea.style.display = "";
  7243. }
  7244. textarea.style.width = me.iframe.offsetWidth + "px";
  7245. textarea.style.height = me.iframe.offsetHeight + "px";
  7246. textarea.value = me.getContent();
  7247. textarea.id = me.key;
  7248. container.innerHTML = "";
  7249. domUtils.remove(container);
  7250. var key = me.key;
  7251. //trace:2004
  7252. for (var p in me) {
  7253. if (me.hasOwnProperty(p)) {
  7254. delete this[p];
  7255. }
  7256. }
  7257. UE.delEditor(key);
  7258. },
  7259. /**
  7260. * 渲染编辑器的DOM到指定容器
  7261. * @method render
  7262. * @param { String } containerId 指定一个容器ID
  7263. * @remind 执行该方法,会触发ready事件
  7264. * @warning 必须且只能调用一次
  7265. */
  7266. /**
  7267. * 渲染编辑器的DOM到指定容器
  7268. * @method render
  7269. * @param { Element } containerDom 直接指定容器对象
  7270. * @remind 执行该方法,会触发ready事件
  7271. * @warning 必须且只能调用一次
  7272. */
  7273. render: function(container) {
  7274. var me = this,
  7275. options = me.options,
  7276. getStyleValue = function(attr) {
  7277. return parseInt(domUtils.getComputedStyle(container, attr));
  7278. };
  7279. if (utils.isString(container)) {
  7280. container = document.getElementById(container);
  7281. }
  7282. if (container) {
  7283. if (options.initialFrameWidth) {
  7284. options.minFrameWidth = options.initialFrameWidth;
  7285. } else {
  7286. options.minFrameWidth = options.initialFrameWidth =
  7287. container.offsetWidth;
  7288. }
  7289. if (options.initialFrameHeight) {
  7290. options.minFrameHeight = options.initialFrameHeight;
  7291. } else {
  7292. options.initialFrameHeight = options.minFrameHeight =
  7293. container.offsetHeight;
  7294. }
  7295. container.style.width = /%$/.test(options.initialFrameWidth)
  7296. ? "100%"
  7297. : options.initialFrameWidth -
  7298. getStyleValue("padding-left") -
  7299. getStyleValue("padding-right") +
  7300. "px";
  7301. container.style.height = /%$/.test(options.initialFrameHeight)
  7302. ? "100%"
  7303. : options.initialFrameHeight -
  7304. getStyleValue("padding-top") -
  7305. getStyleValue("padding-bottom") +
  7306. "px";
  7307. container.style.zIndex = options.zIndex;
  7308. var html =
  7309. (ie && browser.version < 9 ? "" : "<!DOCTYPE html>") +
  7310. "<html xmlns='http://www.w3.org/1999/xhtml' class='view' >" +
  7311. "<head>" +
  7312. "<style type='text/css'>" +
  7313. //设置四周的留边
  7314. ".view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n" +
  7315. //设置默认字体和字号
  7316. //font-family不能呢随便改,在safari下fillchar会有解析问题
  7317. "body{margin:8px;font-family:sans-serif;font-size:16px;}" +
  7318. //设置placeholder
  7319. "body.empty:before{content:attr(placeholder);position:absolute;color:#999;}"+
  7320. //设置段落间距
  7321. "p{margin:5px 0;}</style>" +
  7322. (options.iframeCssUrl
  7323. ? "<link rel='stylesheet' type='text/css' href='" +
  7324. utils.unhtml(options.iframeCssUrl) +
  7325. "'/>"
  7326. : "") +
  7327. (options.initialStyle
  7328. ? "<style>" + options.initialStyle + "</style>"
  7329. : "") +
  7330. "</head>" +
  7331. "<body class='view' ></body>" +
  7332. "<script type='text/javascript' " +
  7333. (ie ? "defer='defer'" : "") +
  7334. " id='_initialScript'>" +
  7335. "setTimeout(function(){editor = window.parent.UE.instants['ueditorInstant" +
  7336. me.uid +
  7337. "'];editor._setup(document);},0);" +
  7338. "var _tmpScript = document.getElementById('_initialScript');_tmpScript.parentNode.removeChild(_tmpScript);" +
  7339. "</script>" +
  7340. (options.iframeJsUrl
  7341. ? "<script type='text/javascript' src='" +
  7342. utils.unhtml(options.iframeJsUrl) +
  7343. "'></script>"
  7344. : "") +
  7345. "</html>";
  7346. container.appendChild(
  7347. domUtils.createElement(document, "iframe", {
  7348. id: "ueditor_" + me.uid,
  7349. width: "100%",
  7350. height: "100%",
  7351. frameborder: "0",
  7352. //先注释掉了,加的原因忘记了,但开启会直接导致全屏模式下内容多时不会出现滚动条
  7353. // scrolling :'no',
  7354. src:
  7355. "javascript:void(function(){document.open();" +
  7356. (options.customDomain && document.domain != location.hostname
  7357. ? 'document.domain="' + document.domain + '";'
  7358. : "") +
  7359. 'document.write("' +
  7360. html +
  7361. '");document.close();}())'
  7362. })
  7363. );
  7364. container.style.overflow = "hidden";
  7365. //解决如果是给定的百分比,会导致高度算不对的问题
  7366. setTimeout(function() {
  7367. if (/%$/.test(options.initialFrameWidth)) {
  7368. options.minFrameWidth = options.initialFrameWidth =
  7369. container.offsetWidth;
  7370. //如果这里给定宽度,会导致ie在拖动窗口大小时,编辑区域不随着变化
  7371. // container.style.width = options.initialFrameWidth + 'px';
  7372. }
  7373. if (/%$/.test(options.initialFrameHeight)) {
  7374. options.minFrameHeight = options.initialFrameHeight =
  7375. container.offsetHeight;
  7376. container.style.height = options.initialFrameHeight + "px";
  7377. }
  7378. });
  7379. }
  7380. },
  7381. /**
  7382. * 编辑器初始化
  7383. * @method _setup
  7384. * @private
  7385. * @param { Element } doc 编辑器Iframe中的文档对象
  7386. */
  7387. _setup: function(doc) {
  7388. var me = this,
  7389. options = me.options;
  7390. if (ie) {
  7391. doc.body.disabled = true;
  7392. doc.body.contentEditable = true;
  7393. doc.body.disabled = false;
  7394. } else {
  7395. doc.body.contentEditable = true;
  7396. }
  7397. doc.body.spellcheck = false;
  7398. me.document = doc;
  7399. me.window = doc.defaultView || doc.parentWindow;
  7400. me.iframe = me.window.frameElement;
  7401. me.body = doc.body;
  7402. me.selection = new dom.Selection(doc);
  7403. //gecko初始化就能得到range,无法判断isFocus了
  7404. var geckoSel;
  7405. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7406. geckoSel.removeAllRanges();
  7407. }
  7408. this._initEvents();
  7409. //为form提交提供一个隐藏的textarea
  7410. for (
  7411. var form = this.iframe.parentNode;
  7412. !domUtils.isBody(form);
  7413. form = form.parentNode
  7414. ) {
  7415. if (form.tagName == "FORM") {
  7416. me.form = form;
  7417. if (me.options.autoSyncData) {
  7418. domUtils.on(me.window, "blur", function() {
  7419. setValue(form, me);
  7420. });
  7421. } else {
  7422. domUtils.on(form, "submit", function() {
  7423. setValue(this, me);
  7424. });
  7425. }
  7426. break;
  7427. }
  7428. }
  7429. if (options.initialContent) {
  7430. if (options.autoClearinitialContent) {
  7431. var oldExecCommand = me.execCommand;
  7432. me.execCommand = function() {
  7433. me.fireEvent("firstBeforeExecCommand");
  7434. return oldExecCommand.apply(me, arguments);
  7435. };
  7436. this._setDefaultContent(options.initialContent);
  7437. } else this.setContent(options.initialContent, false, true);
  7438. }
  7439. //编辑器不能为空内容
  7440. if (domUtils.isEmptyNode(me.body)) {
  7441. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  7442. }
  7443. //如果要求focus, 就把光标定位到内容开始
  7444. if (options.focus) {
  7445. setTimeout(function() {
  7446. me.focus(me.options.focusInEnd);
  7447. //如果自动清除开着,就不需要做selectionchange;
  7448. !me.options.autoClearinitialContent && me._selectionChange();
  7449. }, 0);
  7450. }
  7451. if (!me.container) {
  7452. me.container = this.iframe.parentNode;
  7453. }
  7454. if (options.fullscreen && me.ui) {
  7455. me.ui.setFullScreen(true);
  7456. }
  7457. try {
  7458. me.document.execCommand("2D-position", false, false);
  7459. } catch (e) {}
  7460. try {
  7461. me.document.execCommand("enableInlineTableEditing", false, false);
  7462. } catch (e) {}
  7463. try {
  7464. me.document.execCommand("enableObjectResizing", false, false);
  7465. } catch (e) {}
  7466. //挂接快捷键
  7467. me._bindshortcutKeys();
  7468. me.isReady = 1;
  7469. me.fireEvent("ready");
  7470. options.onready && options.onready.call(me);
  7471. if (!browser.ie9below) {
  7472. domUtils.on(me.window, ["blur", "focus"], function(e) {
  7473. //chrome下会出现alt+tab切换时,导致选区位置不对
  7474. if (e.type == "blur") {
  7475. me._bakRange = me.selection.getRange();
  7476. try {
  7477. me._bakNativeRange = me.selection.getNative().getRangeAt(0);
  7478. me.selection.getNative().removeAllRanges();
  7479. } catch (e) {
  7480. me._bakNativeRange = null;
  7481. }
  7482. } else {
  7483. try {
  7484. me._bakRange && me._bakRange.select();
  7485. } catch (e) {}
  7486. }
  7487. });
  7488. }
  7489. //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
  7490. if (browser.gecko && browser.version <= 10902) {
  7491. //修复ff3.6初始化进来,不能点击获得焦点
  7492. me.body.contentEditable = false;
  7493. setTimeout(function() {
  7494. me.body.contentEditable = true;
  7495. }, 100);
  7496. setInterval(function() {
  7497. me.body.style.height = me.iframe.offsetHeight - 20 + "px";
  7498. }, 100);
  7499. }
  7500. !options.isShow && me.setHide();
  7501. options.readonly && me.setDisabled();
  7502. },
  7503. /**
  7504. * 同步数据到编辑器所在的form
  7505. * 从编辑器的容器节点向上查找form元素,若找到,就同步编辑内容到找到的form里,为提交数据做准备,主要用于是手动提交的情况
  7506. * 后台取得数据的键值,使用你容器上的name属性,如果没有就使用参数里的textarea项
  7507. * @method sync
  7508. * @example
  7509. * ```javascript
  7510. * editor.sync();
  7511. * form.sumbit(); //form变量已经指向了form元素
  7512. * ```
  7513. */
  7514. /**
  7515. * 根据传入的formId,在页面上查找要同步数据的表单,若找到,就同步编辑内容到找到的form里,为提交数据做准备
  7516. * 后台取得数据的键值,该键值默认使用给定的编辑器容器的name属性,如果没有name属性则使用参数项里给定的“textarea”项
  7517. * @method sync
  7518. * @param { String } formID 指定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
  7519. */
  7520. sync: function(formId) {
  7521. var me = this,
  7522. form = formId
  7523. ? document.getElementById(formId)
  7524. : domUtils.findParent(
  7525. me.iframe.parentNode,
  7526. function(node) {
  7527. return node.tagName == "FORM";
  7528. },
  7529. true
  7530. );
  7531. form && setValue(form, me);
  7532. },
  7533. /**
  7534. * 设置编辑器高度
  7535. * @method setHeight
  7536. * @remind 当配置项autoHeightEnabled为真时,该方法无效
  7537. * @param { Number } number 设置的高度值,纯数值,不带单位
  7538. * @example
  7539. * ```javascript
  7540. * editor.setHeight(number);
  7541. * ```
  7542. */
  7543. setHeight: function(height, notSetHeight) {
  7544. if (height !== parseInt(this.iframe.parentNode.style.height)) {
  7545. this.iframe.parentNode.style.height = height + "px";
  7546. }
  7547. !notSetHeight &&
  7548. (this.options.minFrameHeight = this.options.initialFrameHeight = height);
  7549. this.body.style.height = height + "px";
  7550. !notSetHeight && this.trigger("setHeight");
  7551. },
  7552. /**
  7553. * 为编辑器的编辑命令提供快捷键
  7554. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  7555. * @method addshortcutkey
  7556. * @param { Object } keyset 命令名和快捷键键值对对象,多个按钮的快捷键用“+”分隔
  7557. * @example
  7558. * ```javascript
  7559. * editor.addshortcutkey({
  7560. * "Bold" : "ctrl+66",//^B
  7561. * "Italic" : "ctrl+73", //^I
  7562. * });
  7563. * ```
  7564. */
  7565. /**
  7566. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  7567. * @method addshortcutkey
  7568. * @param { String } cmd 触发快捷键时,响应的命令
  7569. * @param { String } keys 快捷键的字符串,多个按钮用“+”分隔
  7570. * @example
  7571. * ```javascript
  7572. * editor.addshortcutkey("Underline", "ctrl+85"); //^U
  7573. * ```
  7574. */
  7575. addshortcutkey: function(cmd, keys) {
  7576. var obj = {};
  7577. if (keys) {
  7578. obj[cmd] = keys;
  7579. } else {
  7580. obj = cmd;
  7581. }
  7582. utils.extend(this.shortcutkeys, obj);
  7583. },
  7584. /**
  7585. * 对编辑器设置keydown事件监听,绑定快捷键和命令,当快捷键组合触发成功,会响应对应的命令
  7586. * @method _bindshortcutKeys
  7587. * @private
  7588. */
  7589. _bindshortcutKeys: function() {
  7590. var me = this,
  7591. shortcutkeys = this.shortcutkeys;
  7592. me.addListener("keydown", function(type, e) {
  7593. var keyCode = e.keyCode || e.which;
  7594. for (var i in shortcutkeys) {
  7595. var tmp = shortcutkeys[i].split(",");
  7596. for (var t = 0, ti; (ti = tmp[t++]); ) {
  7597. ti = ti.split(":");
  7598. var key = ti[0],
  7599. param = ti[1];
  7600. if (
  7601. /^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) ||
  7602. /^(\d+)$/.test(key)
  7603. ) {
  7604. if (
  7605. ((RegExp.$1 == "ctrl" ? e.ctrlKey || e.metaKey : 0) &&
  7606. (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1) &&
  7607. keyCode == RegExp.$3) ||
  7608. keyCode == RegExp.$1
  7609. ) {
  7610. if (me.queryCommandState(i, param) != -1)
  7611. me.execCommand(i, param);
  7612. domUtils.preventDefault(e);
  7613. }
  7614. }
  7615. }
  7616. }
  7617. });
  7618. },
  7619. /**
  7620. * 获取编辑器的内容
  7621. * @method getContent
  7622. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  7623. * @return { String } 编辑器的内容字符串, 如果编辑器的内容为空,或者是空的标签内容(如:”&lt;p&gt;&lt;br/&gt;&lt;/p&gt;“), 则返回空字符串
  7624. * @example
  7625. * ```javascript
  7626. * //编辑器html内容:<p>1<strong>2<em>34</em>5</strong>6</p>
  7627. * var content = editor.getContent(); //返回值:<p>1<strong>2<em>34</em>5</strong>6</p>
  7628. * ```
  7629. */
  7630. /**
  7631. * 获取编辑器的内容。 可以通过参数定义编辑器内置的判空规则
  7632. * @method getContent
  7633. * @param { Function } fn 自定的判空规则, 要求该方法返回一个boolean类型的值,
  7634. * 代表当前编辑器的内容是否空,
  7635. * 如果返回true, 则该方法将直接返回空字符串;如果返回false,则编辑器将返回
  7636. * 经过内置过滤规则处理后的内容。
  7637. * @remind 该方法在处理包含有初始化内容的时候能起到很好的作用。
  7638. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  7639. * @return { String } 编辑器的内容字符串
  7640. * @example
  7641. * ```javascript
  7642. * // editor 是一个编辑器的实例
  7643. * var content = editor.getContent( function ( editor ) {
  7644. * return editor.body.innerHTML === '欢迎使用UEditor'; //返回空字符串
  7645. * } );
  7646. * ```
  7647. */
  7648. getContent: function(cmd, fn, notSetCursor, ignoreBlank, formatter) {
  7649. var me = this;
  7650. if (cmd && utils.isFunction(cmd)) {
  7651. fn = cmd;
  7652. cmd = "";
  7653. }
  7654. if (fn ? !fn() : !this.hasContents()) {
  7655. return "";
  7656. }
  7657. me.fireEvent("beforegetcontent");
  7658. var root = UE.htmlparser(me.body.innerHTML, ignoreBlank);
  7659. me.filterOutputRule(root);
  7660. me.fireEvent("aftergetcontent", cmd, root);
  7661. return root.toHtml(formatter);
  7662. },
  7663. /**
  7664. * 取得完整的html代码,可以直接显示成完整的html文档
  7665. * @method getAllHtml
  7666. * @return { String } 编辑器的内容html文档字符串
  7667. * @eaxmple
  7668. * ```javascript
  7669. * editor.getAllHtml(); //返回格式大致是: <html><head>...</head><body>...</body></html>
  7670. * ```
  7671. */
  7672. getAllHtml: function() {
  7673. var me = this,
  7674. headHtml = [],
  7675. html = "";
  7676. me.fireEvent("getAllHtml", headHtml);
  7677. if (browser.ie && browser.version > 8) {
  7678. var headHtmlForIE9 = "";
  7679. utils.each(me.document.styleSheets, function(si) {
  7680. headHtmlForIE9 += si.href
  7681. ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />'
  7682. : "<style>" + si.cssText + "</style>";
  7683. });
  7684. utils.each(me.document.getElementsByTagName("script"), function(si) {
  7685. headHtmlForIE9 += si.outerHTML;
  7686. });
  7687. }
  7688. return (
  7689. "<html><head>" +
  7690. (me.options.charset
  7691. ? '<meta http-equiv="Content-Type" content="text/html; charset=' +
  7692. me.options.charset +
  7693. '"/>'
  7694. : "") +
  7695. (headHtmlForIE9 ||
  7696. me.document.getElementsByTagName("head")[0].innerHTML) +
  7697. headHtml.join("\n") +
  7698. "</head>" +
  7699. "<body " +
  7700. (ie && browser.version < 9 ? 'class="view"' : "") +
  7701. ">" +
  7702. me.getContent(null, null, true) +
  7703. "</body></html>"
  7704. );
  7705. },
  7706. /**
  7707. * 得到编辑器的纯文本内容,但会保留段落格式
  7708. * @method getPlainTxt
  7709. * @return { String } 编辑器带段落格式的纯文本内容字符串
  7710. * @example
  7711. * ```javascript
  7712. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  7713. * console.log(editor.getPlainTxt()); //输出:"1\n2\n
  7714. * ```
  7715. */
  7716. getPlainTxt: function() {
  7717. var reg = new RegExp(domUtils.fillChar, "g"),
  7718. html = this.body.innerHTML.replace(/[\n\r]/g, ""); //ie要先去了\n在处理
  7719. html = html
  7720. .replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, "\n")
  7721. .replace(/<br\/?>/gi, "\n")
  7722. .replace(/<[^>/]+>/g, "")
  7723. .replace(/(\n)?<\/([^>]+)>/g, function(a, b, c) {
  7724. return dtd.$block[c] ? "\n" : b ? b : "";
  7725. });
  7726. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  7727. return html
  7728. .replace(reg, "")
  7729. .replace(/\u00a0/g, " ")
  7730. .replace(/&nbsp;/g, " ");
  7731. },
  7732. /**
  7733. * 获取编辑器中的纯文本内容,没有段落格式
  7734. * @method getContentTxt
  7735. * @return { String } 编辑器不带段落格式的纯文本内容字符串
  7736. * @example
  7737. * ```javascript
  7738. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  7739. * console.log(editor.getPlainTxt()); //输出:"12
  7740. * ```
  7741. */
  7742. getContentTxt: function() {
  7743. var reg = new RegExp(domUtils.fillChar, "g");
  7744. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  7745. return this.body[browser.ie ? "innerText" : "textContent"]
  7746. .replace(reg, "")
  7747. .replace(/\u00a0/g, " ");
  7748. },
  7749. /**
  7750. * 设置编辑器的内容,可修改编辑器当前的html内容
  7751. * @method setContent
  7752. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  7753. * @warning 该方法会触发selectionchange事件
  7754. * @param { String } html 要插入的html内容
  7755. * @example
  7756. * ```javascript
  7757. * editor.getContent('<p>test</p>');
  7758. * ```
  7759. */
  7760. /**
  7761. * 设置编辑器的内容,可修改编辑器当前的html内容
  7762. * @method setContent
  7763. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  7764. * @warning 该方法会触发selectionchange事件
  7765. * @param { String } html 要插入的html内容
  7766. * @param { Boolean } isAppendTo 若传入true,不清空原来的内容,在最后插入内容,否则,清空内容再插入
  7767. * @example
  7768. * ```javascript
  7769. * //假设设置前的编辑器内容是 <p>old text</p>
  7770. * editor.setContent('<p>new text</p>', true); //插入的结果是<p>old text</p><p>new text</p>
  7771. * ```
  7772. */
  7773. setContent: function(html, isAppendTo, notFireSelectionchange) {
  7774. var me = this;
  7775. me.fireEvent("beforesetcontent", html);
  7776. var root = UE.htmlparser(html);
  7777. me.filterInputRule(root);
  7778. html = root.toHtml();
  7779. me.body.innerHTML = (isAppendTo ? me.body.innerHTML : "") + html;
  7780. function isCdataDiv(node) {
  7781. return node.tagName == "DIV" && node.getAttribute("cdata_tag");
  7782. }
  7783. //给文本或者inline节点套p标签
  7784. if (me.options.enterTag == "p") {
  7785. var child = this.body.firstChild,
  7786. tmpNode;
  7787. if (
  7788. !child ||
  7789. (child.nodeType == 1 &&
  7790. (dtd.$cdata[child.tagName] ||
  7791. isCdataDiv(child) ||
  7792. domUtils.isCustomeNode(child)) &&
  7793. child === this.body.lastChild)
  7794. ) {
  7795. this.body.innerHTML =
  7796. "<p>" +
  7797. (browser.ie ? "&nbsp;" : "<br/>") +
  7798. "</p>" +
  7799. this.body.innerHTML;
  7800. } else {
  7801. var p = me.document.createElement("p");
  7802. while (child) {
  7803. while (
  7804. child &&
  7805. (child.nodeType == 3 ||
  7806. (child.nodeType == 1 &&
  7807. dtd.p[child.tagName] &&
  7808. !dtd.$cdata[child.tagName]))
  7809. ) {
  7810. tmpNode = child.nextSibling;
  7811. p.appendChild(child);
  7812. child = tmpNode;
  7813. }
  7814. if (p.firstChild) {
  7815. if (!child) {
  7816. me.body.appendChild(p);
  7817. break;
  7818. } else {
  7819. child.parentNode.insertBefore(p, child);
  7820. p = me.document.createElement("p");
  7821. }
  7822. }
  7823. child = child.nextSibling;
  7824. }
  7825. }
  7826. }
  7827. me.fireEvent("aftersetcontent");
  7828. me.fireEvent("contentchange");
  7829. !notFireSelectionchange && me._selectionChange();
  7830. //清除保存的选区
  7831. me._bakRange = me._bakIERange = me._bakNativeRange = null;
  7832. //trace:1742 setContent后gecko能得到焦点问题
  7833. var geckoSel;
  7834. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7835. geckoSel.removeAllRanges();
  7836. }
  7837. if (me.options.autoSyncData) {
  7838. me.form && setValue(me.form, me);
  7839. }
  7840. },
  7841. /**
  7842. * 让编辑器获得焦点,默认focus到编辑器头部
  7843. * @method focus
  7844. * @example
  7845. * ```javascript
  7846. * editor.focus()
  7847. * ```
  7848. */
  7849. /**
  7850. * 让编辑器获得焦点,toEnd确定focus位置
  7851. * @method focus
  7852. * @param { Boolean } toEnd 默认focus到编辑器头部,toEnd为true时focus到内容尾部
  7853. * @example
  7854. * ```javascript
  7855. * editor.focus(true)
  7856. * ```
  7857. */
  7858. focus: function(toEnd) {
  7859. try {
  7860. var me = this,
  7861. rng = me.selection.getRange();
  7862. if (toEnd) {
  7863. var node = me.body.lastChild;
  7864. if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
  7865. if (domUtils.isEmptyBlock(node)) {
  7866. rng.setStartAtFirst(node);
  7867. } else {
  7868. rng.setStartAtLast(node);
  7869. }
  7870. rng.collapse(true);
  7871. }
  7872. rng.setCursor(true);
  7873. } else {
  7874. if (
  7875. !rng.collapsed &&
  7876. domUtils.isBody(rng.startContainer) &&
  7877. rng.startOffset == 0
  7878. ) {
  7879. var node = me.body.firstChild;
  7880. if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
  7881. rng.setStartAtFirst(node).collapse(true);
  7882. }
  7883. }
  7884. rng.select(true);
  7885. }
  7886. this.fireEvent("focus selectionchange");
  7887. } catch (e) {}
  7888. },
  7889. isFocus: function() {
  7890. return this.selection.isFocus();
  7891. },
  7892. blur: function() {
  7893. var sel = this.selection.getNative();
  7894. if (sel.empty && browser.ie) {
  7895. var nativeRng = document.body.createTextRange();
  7896. nativeRng.moveToElementText(document.body);
  7897. nativeRng.collapse(true);
  7898. nativeRng.select();
  7899. sel.empty();
  7900. } else {
  7901. sel.removeAllRanges();
  7902. }
  7903. //this.fireEvent('blur selectionchange');
  7904. },
  7905. /**
  7906. * 初始化UE事件及部分事件代理
  7907. * @method _initEvents
  7908. * @private
  7909. */
  7910. _initEvents: function() {
  7911. var me = this,
  7912. doc = me.document,
  7913. win = me.window;
  7914. me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
  7915. domUtils.on(
  7916. doc,
  7917. [
  7918. "click",
  7919. "contextmenu",
  7920. "mousedown",
  7921. "keydown",
  7922. "keyup",
  7923. "keypress",
  7924. "mouseup",
  7925. "mouseover",
  7926. "mouseout",
  7927. "selectstart"
  7928. ],
  7929. me._proxyDomEvent
  7930. );
  7931. domUtils.on(win, ["focus", "blur"], me._proxyDomEvent);
  7932. domUtils.on(me.body, "drop", function(e) {
  7933. //阻止ff下默认的弹出新页面打开图片
  7934. if (browser.gecko && e.stopPropagation) {
  7935. e.stopPropagation();
  7936. }
  7937. me.fireEvent("contentchange");
  7938. });
  7939. domUtils.on(doc, ["mouseup", "keydown"], function(evt) {
  7940. //特殊键不触发selectionchange
  7941. if (
  7942. evt.type == "keydown" &&
  7943. (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)
  7944. ) {
  7945. return;
  7946. }
  7947. if (evt.button == 2) return;
  7948. me._selectionChange(250, evt);
  7949. });
  7950. },
  7951. /**
  7952. * 触发事件代理
  7953. * @method _proxyDomEvent
  7954. * @private
  7955. * @return { * } fireEvent的返回值
  7956. * @see UE.EventBase:fireEvent(String)
  7957. */
  7958. _proxyDomEvent: function(evt) {
  7959. if (
  7960. this.fireEvent("before" + evt.type.replace(/^on/, "").toLowerCase()) ===
  7961. false
  7962. ) {
  7963. return false;
  7964. }
  7965. if (this.fireEvent(evt.type.replace(/^on/, ""), evt) === false) {
  7966. return false;
  7967. }
  7968. return this.fireEvent(
  7969. "after" + evt.type.replace(/^on/, "").toLowerCase()
  7970. );
  7971. },
  7972. /**
  7973. * 变化选区
  7974. * @method _selectionChange
  7975. * @private
  7976. */
  7977. _selectionChange: function(delay, evt) {
  7978. var me = this;
  7979. //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
  7980. // if ( !me.selection.isFocus() ){
  7981. // return;
  7982. // }
  7983. var hackForMouseUp = false;
  7984. var mouseX, mouseY;
  7985. if (browser.ie && browser.version < 9 && evt && evt.type == "mouseup") {
  7986. var range = this.selection.getRange();
  7987. if (!range.collapsed) {
  7988. hackForMouseUp = true;
  7989. mouseX = evt.clientX;
  7990. mouseY = evt.clientY;
  7991. }
  7992. }
  7993. clearTimeout(_selectionChangeTimer);
  7994. _selectionChangeTimer = setTimeout(function() {
  7995. if (!me.selection || !me.selection.getNative()) {
  7996. return;
  7997. }
  7998. //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
  7999. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
  8000. var ieRange;
  8001. if (hackForMouseUp && me.selection.getNative().type == "None") {
  8002. ieRange = me.document.body.createTextRange();
  8003. try {
  8004. ieRange.moveToPoint(mouseX, mouseY);
  8005. } catch (ex) {
  8006. ieRange = null;
  8007. }
  8008. }
  8009. var bakGetIERange;
  8010. if (ieRange) {
  8011. bakGetIERange = me.selection.getIERange;
  8012. me.selection.getIERange = function() {
  8013. return ieRange;
  8014. };
  8015. }
  8016. me.selection.cache();
  8017. if (bakGetIERange) {
  8018. me.selection.getIERange = bakGetIERange;
  8019. }
  8020. if (me.selection._cachedRange && me.selection._cachedStartElement) {
  8021. me.fireEvent("beforeselectionchange");
  8022. // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
  8023. me.fireEvent("selectionchange", !!evt);
  8024. me.fireEvent("afterselectionchange");
  8025. me.selection.clear();
  8026. }
  8027. }, delay || 50);
  8028. },
  8029. /**
  8030. * 执行编辑命令
  8031. * @method _callCmdFn
  8032. * @private
  8033. * @param { String } fnName 函数名称
  8034. * @param { * } args 传给命令函数的参数
  8035. * @return { * } 返回命令函数运行的返回值
  8036. */
  8037. _callCmdFn: function(fnName, args) {
  8038. var cmdName = args[0].toLowerCase(),
  8039. cmd,
  8040. cmdFn;
  8041. cmd = this.commands[cmdName] || UE.commands[cmdName];
  8042. cmdFn = cmd && cmd[fnName];
  8043. //没有querycommandstate或者没有command的都默认返回0
  8044. if ((!cmd || !cmdFn) && fnName == "queryCommandState") {
  8045. return 0;
  8046. } else if (cmdFn) {
  8047. return cmdFn.apply(this, args);
  8048. }
  8049. },
  8050. /**
  8051. * 执行编辑命令cmdName,完成富文本编辑效果
  8052. * @method execCommand
  8053. * @param { String } cmdName 需要执行的命令
  8054. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8055. * @return { * } 返回命令函数运行的返回值
  8056. * @example
  8057. * ```javascript
  8058. * editor.execCommand(cmdName);
  8059. * ```
  8060. */
  8061. execCommand: function(cmdName) {
  8062. cmdName = cmdName.toLowerCase();
  8063. var me = this;
  8064. var result;
  8065. var cmd = me.commands[cmdName] || UE.commands[cmdName];
  8066. if (!cmd || !cmd.execCommand) {
  8067. return null;
  8068. }
  8069. if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
  8070. me.__hasEnterExecCommand = true;
  8071. if (me.queryCommandState.apply(me, arguments) != -1) {
  8072. me.fireEvent("saveScene");
  8073. me.fireEvent.apply(
  8074. me,
  8075. ["beforeexeccommand", cmdName].concat(arguments)
  8076. );
  8077. result = this._callCmdFn("execCommand", arguments);
  8078. //保存场景时,做了内容对比,再看是否进行contentchange触发,这里多触发了一次,去掉
  8079. // (!cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange');
  8080. me.fireEvent.apply(
  8081. me,
  8082. ["afterexeccommand", cmdName].concat(arguments)
  8083. );
  8084. me.fireEvent("saveScene");
  8085. }
  8086. me.__hasEnterExecCommand = false;
  8087. } else {
  8088. result = this._callCmdFn("execCommand", arguments);
  8089. !me.__hasEnterExecCommand &&
  8090. !cmd.ignoreContentChange &&
  8091. !me._ignoreContentChange &&
  8092. me.fireEvent("contentchange");
  8093. }
  8094. !me.__hasEnterExecCommand &&
  8095. !cmd.ignoreContentChange &&
  8096. !me._ignoreContentChange &&
  8097. me._selectionChange();
  8098. return result;
  8099. },
  8100. /**
  8101. * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
  8102. * @method queryCommandState
  8103. * @param { String } cmdName 需要查询的命令名称
  8104. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8105. * @return { Number } number 返回放前命令的状态,返回值三种情况:(-1|0|1)
  8106. * @example
  8107. * ```javascript
  8108. * editor.queryCommandState(cmdName) => (-1|0|1)
  8109. * ```
  8110. * @see COMMAND.LIST
  8111. */
  8112. queryCommandState: function(cmdName) {
  8113. return this._callCmdFn("queryCommandState", arguments);
  8114. },
  8115. /**
  8116. * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
  8117. * @method queryCommandValue
  8118. * @param { String } cmdName 需要查询的命令名称
  8119. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8120. * @remind 只有部分插件有此方法
  8121. * @return { * } 返回每个命令特定的当前状态值
  8122. * @grammar editor.queryCommandValue(cmdName) => {*}
  8123. * @see COMMAND.LIST
  8124. */
  8125. queryCommandValue: function(cmdName) {
  8126. return this._callCmdFn("queryCommandValue", arguments);
  8127. },
  8128. /**
  8129. * 检查编辑区域中是否有内容
  8130. * @method hasContents
  8131. * @remind 默认有文本内容,或者有以下节点都不认为是空
  8132. * table,ul,ol,dl,iframe,area,base,col,hr,img,embed,input,link,meta,param
  8133. * @return { Boolean } 检查有内容返回true,否则返回false
  8134. * @example
  8135. * ```javascript
  8136. * editor.hasContents()
  8137. * ```
  8138. */
  8139. /**
  8140. * 检查编辑区域中是否有内容,若包含参数tags中的节点类型,直接返回true
  8141. * @method hasContents
  8142. * @param { Array } tags 传入数组判断时用到的节点类型
  8143. * @return { Boolean } 若文档中包含tags数组里对应的tag,返回true,否则返回false
  8144. * @example
  8145. * ```javascript
  8146. * editor.hasContents(['span']);
  8147. * ```
  8148. */
  8149. hasContents: function(tags) {
  8150. if (tags) {
  8151. for (var i = 0, ci; (ci = tags[i++]); ) {
  8152. if (this.document.getElementsByTagName(ci).length > 0) {
  8153. return true;
  8154. }
  8155. }
  8156. }
  8157. if (!domUtils.isEmptyBlock(this.body)) {
  8158. return true;
  8159. }
  8160. //随时添加,定义的特殊标签如果存在,不能认为是空
  8161. tags = ["div"];
  8162. for (i = 0; (ci = tags[i++]); ) {
  8163. var nodes = domUtils.getElementsByTagName(this.document, ci);
  8164. for (var n = 0, cn; (cn = nodes[n++]); ) {
  8165. if (domUtils.isCustomeNode(cn)) {
  8166. return true;
  8167. }
  8168. }
  8169. }
  8170. return false;
  8171. },
  8172. /**
  8173. * 重置编辑器,可用来做多个tab使用同一个编辑器实例
  8174. * @method reset
  8175. * @remind 此方法会清空编辑器内容,清空回退列表,会触发reset事件
  8176. * @example
  8177. * ```javascript
  8178. * editor.reset()
  8179. * ```
  8180. */
  8181. reset: function() {
  8182. this.fireEvent("reset");
  8183. },
  8184. /**
  8185. * 设置当前编辑区域可以编辑
  8186. * @method setEnabled
  8187. * @example
  8188. * ```javascript
  8189. * editor.setEnabled()
  8190. * ```
  8191. */
  8192. setEnabled: function() {
  8193. var me = this,
  8194. range;
  8195. if (me.body.contentEditable == "false") {
  8196. me.body.contentEditable = true;
  8197. range = me.selection.getRange();
  8198. //有可能内容丢失了
  8199. try {
  8200. range.moveToBookmark(me.lastBk);
  8201. delete me.lastBk;
  8202. } catch (e) {
  8203. range.setStartAtFirst(me.body).collapse(true);
  8204. }
  8205. range.select(true);
  8206. if (me.bkqueryCommandState) {
  8207. me.queryCommandState = me.bkqueryCommandState;
  8208. delete me.bkqueryCommandState;
  8209. }
  8210. if (me.bkqueryCommandValue) {
  8211. me.queryCommandValue = me.bkqueryCommandValue;
  8212. delete me.bkqueryCommandValue;
  8213. }
  8214. me.fireEvent("selectionchange");
  8215. }
  8216. },
  8217. enable: function() {
  8218. return this.setEnabled();
  8219. },
  8220. /** 设置当前编辑区域不可编辑
  8221. * @method setDisabled
  8222. */
  8223. /** 设置当前编辑区域不可编辑,except中的命令除外
  8224. * @method setDisabled
  8225. * @param { String } except 例外命令的字符串
  8226. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  8227. * @example
  8228. * ```javascript
  8229. * editor.setDisabled('bold'); //禁用工具栏中除加粗之外的所有功能
  8230. * ```
  8231. */
  8232. /** 设置当前编辑区域不可编辑,except中的命令除外
  8233. * @method setDisabled
  8234. * @param { Array } except 例外命令的字符串数组,数组中的命令仍然可以执行
  8235. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  8236. * @example
  8237. * ```javascript
  8238. * editor.setDisabled(['bold','insertimage']); //禁用工具栏中除加粗和插入图片之外的所有功能
  8239. * ```
  8240. */
  8241. setDisabled: function(except) {
  8242. var me = this;
  8243. except = except ? (utils.isArray(except) ? except : [except]) : [];
  8244. if (me.body.contentEditable == "true") {
  8245. if (!me.lastBk) {
  8246. me.lastBk = me.selection.getRange().createBookmark(true);
  8247. }
  8248. me.body.contentEditable = false;
  8249. me.bkqueryCommandState = me.queryCommandState;
  8250. me.bkqueryCommandValue = me.queryCommandValue;
  8251. me.queryCommandState = function(type) {
  8252. if (utils.indexOf(except, type) != -1) {
  8253. return me.bkqueryCommandState.apply(me, arguments);
  8254. }
  8255. return -1;
  8256. };
  8257. me.queryCommandValue = function(type) {
  8258. if (utils.indexOf(except, type) != -1) {
  8259. return me.bkqueryCommandValue.apply(me, arguments);
  8260. }
  8261. return null;
  8262. };
  8263. me.fireEvent("selectionchange");
  8264. }
  8265. },
  8266. disable: function(except) {
  8267. return this.setDisabled(except);
  8268. },
  8269. /**
  8270. * 设置默认内容
  8271. * @method _setDefaultContent
  8272. * @private
  8273. * @param { String } cont 要存入的内容
  8274. */
  8275. _setDefaultContent: (function() {
  8276. function clear() {
  8277. var me = this;
  8278. if (me.document.getElementById("initContent")) {
  8279. me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
  8280. me.removeListener("firstBeforeExecCommand focus", clear);
  8281. setTimeout(function() {
  8282. me.focus();
  8283. me._selectionChange();
  8284. }, 0);
  8285. }
  8286. }
  8287. return function(cont) {
  8288. var me = this;
  8289. me.body.innerHTML = '<p id="initContent">' + cont + "</p>";
  8290. me.addListener("firstBeforeExecCommand focus", clear);
  8291. };
  8292. })(),
  8293. /**
  8294. * 显示编辑器
  8295. * @method setShow
  8296. * @example
  8297. * ```javascript
  8298. * editor.setShow()
  8299. * ```
  8300. */
  8301. setShow: function() {
  8302. var me = this,
  8303. range = me.selection.getRange();
  8304. if (me.container.style.display == "none") {
  8305. //有可能内容丢失了
  8306. try {
  8307. range.moveToBookmark(me.lastBk);
  8308. delete me.lastBk;
  8309. } catch (e) {
  8310. range.setStartAtFirst(me.body).collapse(true);
  8311. }
  8312. //ie下focus实效,所以做了个延迟
  8313. setTimeout(function() {
  8314. range.select(true);
  8315. }, 100);
  8316. me.container.style.display = "";
  8317. }
  8318. },
  8319. show: function() {
  8320. return this.setShow();
  8321. },
  8322. /**
  8323. * 隐藏编辑器
  8324. * @method setHide
  8325. * @example
  8326. * ```javascript
  8327. * editor.setHide()
  8328. * ```
  8329. */
  8330. setHide: function() {
  8331. var me = this;
  8332. if (!me.lastBk) {
  8333. me.lastBk = me.selection.getRange().createBookmark(true);
  8334. }
  8335. me.container.style.display = "none";
  8336. },
  8337. hide: function() {
  8338. return this.setHide();
  8339. },
  8340. /**
  8341. * 根据指定的路径,获取对应的语言资源
  8342. * @method getLang
  8343. * @param { String } path 路径根据的是lang目录下的语言文件的路径结构
  8344. * @return { Object | String } 根据路径返回语言资源的Json格式对象或者语言字符串
  8345. * @example
  8346. * ```javascript
  8347. * editor.getLang('contextMenu.delete'); //如果当前是中文,那返回是的是'删除'
  8348. * ```
  8349. */
  8350. getLang: function(path) {
  8351. var lang = UE.I18N[this.options.lang];
  8352. if (!lang) {
  8353. throw Error("not import language file");
  8354. }
  8355. path = (path || "").split(".");
  8356. for (var i = 0, ci; (ci = path[i++]); ) {
  8357. lang = lang[ci];
  8358. if (!lang) break;
  8359. }
  8360. return lang;
  8361. },
  8362. /**
  8363. * 计算编辑器html内容字符串的长度
  8364. * @method getContentLength
  8365. * @return { Number } 返回计算的长度
  8366. * @example
  8367. * ```javascript
  8368. * //编辑器html内容<p><strong>132</strong></p>
  8369. * editor.getContentLength() //返回27
  8370. * ```
  8371. */
  8372. /**
  8373. * 计算编辑器当前纯文本内容的长度
  8374. * @method getContentLength
  8375. * @param { Boolean } ingoneHtml 传入true时,只按照纯文本来计算
  8376. * @return { Number } 返回计算的长度,内容中有hr/img/iframe标签,长度加1
  8377. * @example
  8378. * ```javascript
  8379. * //编辑器html内容<p><strong>132</strong></p>
  8380. * editor.getContentLength() //返回3
  8381. * ```
  8382. */
  8383. getContentLength: function(ingoneHtml, tagNames) {
  8384. var count = this.getContent(false, false, true).length;
  8385. if (ingoneHtml) {
  8386. tagNames = (tagNames || []).concat(["hr", "img", "iframe"]);
  8387. count = this.getContentTxt().replace(/[\t\r\n]+/g, "").length;
  8388. for (var i = 0, ci; (ci = tagNames[i++]); ) {
  8389. count += this.document.getElementsByTagName(ci).length;
  8390. }
  8391. }
  8392. return count;
  8393. },
  8394. /**
  8395. * 注册输入过滤规则
  8396. * @method addInputRule
  8397. * @param { Function } rule 要添加的过滤规则
  8398. * @example
  8399. * ```javascript
  8400. * editor.addInputRule(function(root){
  8401. * $.each(root.getNodesByTagName('div'),function(i,node){
  8402. * node.tagName="p";
  8403. * });
  8404. * });
  8405. * ```
  8406. */
  8407. addInputRule: function(rule) {
  8408. this.inputRules.push(rule);
  8409. },
  8410. /**
  8411. * 执行注册的过滤规则
  8412. * @method filterInputRule
  8413. * @param { UE.uNode } root 要过滤的uNode节点
  8414. * @remind 执行editor.setContent方法和执行'inserthtml'命令后,会运行该过滤函数
  8415. * @example
  8416. * ```javascript
  8417. * editor.filterInputRule(editor.body);
  8418. * ```
  8419. * @see UE.Editor:addInputRule
  8420. */
  8421. filterInputRule: function(root) {
  8422. for (var i = 0, ci; (ci = this.inputRules[i++]); ) {
  8423. ci.call(this, root);
  8424. }
  8425. },
  8426. /**
  8427. * 注册输出过滤规则
  8428. * @method addOutputRule
  8429. * @param { Function } rule 要添加的过滤规则
  8430. * @example
  8431. * ```javascript
  8432. * editor.addOutputRule(function(root){
  8433. * $.each(root.getNodesByTagName('p'),function(i,node){
  8434. * node.tagName="div";
  8435. * });
  8436. * });
  8437. * ```
  8438. */
  8439. addOutputRule: function(rule) {
  8440. this.outputRules.push(rule);
  8441. },
  8442. /**
  8443. * 根据输出过滤规则,过滤编辑器内容
  8444. * @method filterOutputRule
  8445. * @remind 执行editor.getContent方法的时候,会先运行该过滤函数
  8446. * @param { UE.uNode } root 要过滤的uNode节点
  8447. * @example
  8448. * ```javascript
  8449. * editor.filterOutputRule(editor.body);
  8450. * ```
  8451. * @see UE.Editor:addOutputRule
  8452. */
  8453. filterOutputRule: function(root) {
  8454. for (var i = 0, ci; (ci = this.outputRules[i++]); ) {
  8455. ci.call(this, root);
  8456. }
  8457. },
  8458. /**
  8459. * 根据action名称获取请求的路径
  8460. * @method getActionUrl
  8461. * @remind 假如没有设置serverUrl,会根据imageUrl设置默认的controller路径
  8462. * @param { String } action action名称
  8463. * @example
  8464. * ```javascript
  8465. * editor.getActionUrl('config'); //返回 "/ueditor/php/controller.php?action=config"
  8466. * editor.getActionUrl('image'); //返回 "/ueditor/php/controller.php?action=uplaodimage"
  8467. * editor.getActionUrl('scrawl'); //返回 "/ueditor/php/controller.php?action=uplaodscrawl"
  8468. * editor.getActionUrl('imageManager'); //返回 "/ueditor/php/controller.php?action=listimage"
  8469. * ```
  8470. */
  8471. getActionUrl: function(action) {
  8472. var actionName = this.getOpt(action) || action,
  8473. imageUrl = this.getOpt("imageUrl"),
  8474. serverUrl = this.getOpt("serverUrl");
  8475. if (!serverUrl && imageUrl) {
  8476. serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, "$1controller$2");
  8477. }
  8478. if (serverUrl) {
  8479. serverUrl =
  8480. serverUrl +
  8481. (serverUrl.indexOf("?") == -1 ? "?" : "&") +
  8482. "action=" +
  8483. (actionName || "");
  8484. return utils.formatUrl(serverUrl);
  8485. } else {
  8486. return "";
  8487. }
  8488. }
  8489. };
  8490. utils.inherits(Editor, EventBase);
  8491. })();
  8492. // core/Editor.defaultoptions.js
  8493. //维护编辑器一下默认的不在插件中的配置项
  8494. UE.Editor.defaultOptions = function(editor) {
  8495. var _url = editor.options.UEDITOR_HOME_URL;
  8496. return {
  8497. isShow: true,
  8498. initialContent: "",
  8499. initialStyle: "",
  8500. autoClearinitialContent: false,
  8501. iframeCssUrl: _url + "themes/iframe.css",
  8502. textarea: "editorValue",
  8503. focus: false,
  8504. focusInEnd: true,
  8505. autoClearEmptyNode: true,
  8506. fullscreen: false,
  8507. readonly: false,
  8508. zIndex: 999,
  8509. imagePopup: true,
  8510. enterTag: "p",
  8511. customDomain: false,
  8512. lang: "zh-cn",
  8513. langPath: _url + "i18n/",
  8514. theme: "default",
  8515. themePath: _url + "themes/",
  8516. allHtmlEnabled: false,
  8517. scaleEnabled: false,
  8518. tableNativeEditInFF: false,
  8519. autoSyncData: true,
  8520. fileNameFormat: "{time}{rand:6}"
  8521. };
  8522. };
  8523. // core/loadconfig.js
  8524. ;(function() {
  8525. UE.Editor.prototype.loadServerConfig = function() {
  8526. var me = this;
  8527. setTimeout(function() {
  8528. try {
  8529. me.options.imageUrl &&
  8530. me.setOpt(
  8531. "serverUrl",
  8532. me.options.imageUrl.replace(
  8533. /^(.*[\/]).+([\.].+)$/,
  8534. "$1controller$2"
  8535. )
  8536. );
  8537. var configUrl = me.getActionUrl("config"),
  8538. isJsonp = utils.isCrossDomainUrl(configUrl);
  8539. /* 发出ajax请求 */
  8540. me._serverConfigLoaded = false;
  8541. configUrl &&
  8542. UE.ajax.request(configUrl, {
  8543. method: "GET",
  8544. dataType: isJsonp ? "jsonp" : "",
  8545. onsuccess: function(r) {
  8546. try {
  8547. var config = isJsonp ? r : eval("(" + r.responseText + ")");
  8548. utils.extend(me.options, config);
  8549. me.fireEvent("serverConfigLoaded");
  8550. me._serverConfigLoaded = true;
  8551. } catch (e) {
  8552. showErrorMsg(me.getLang("loadconfigFormatError"));
  8553. }
  8554. },
  8555. onerror: function() {
  8556. showErrorMsg(me.getLang("loadconfigHttpError"));
  8557. }
  8558. });
  8559. } catch (e) {
  8560. showErrorMsg(me.getLang("loadconfigError"));
  8561. }
  8562. });
  8563. function showErrorMsg(msg) {
  8564. console && console.error(msg);
  8565. //me.fireEvent('showMessage', {
  8566. // 'title': msg,
  8567. // 'type': 'error'
  8568. //});
  8569. }
  8570. };
  8571. UE.Editor.prototype.isServerConfigLoaded = function() {
  8572. var me = this;
  8573. return me._serverConfigLoaded || false;
  8574. };
  8575. UE.Editor.prototype.afterConfigReady = function(handler) {
  8576. if (!handler || !utils.isFunction(handler)) return;
  8577. var me = this;
  8578. var readyHandler = function() {
  8579. handler.apply(me, arguments);
  8580. me.removeListener("serverConfigLoaded", readyHandler);
  8581. };
  8582. if (me.isServerConfigLoaded()) {
  8583. handler.call(me, "serverConfigLoaded");
  8584. } else {
  8585. me.addListener("serverConfigLoaded", readyHandler);
  8586. }
  8587. };
  8588. })();
  8589. // core/ajax.js
  8590. /**
  8591. * @file
  8592. * @module UE.ajax
  8593. * @since 1.2.6.1
  8594. */
  8595. /**
  8596. * 提供对ajax请求的支持
  8597. * @module UE.ajax
  8598. */
  8599. UE.ajax = (function() {
  8600. //创建一个ajaxRequest对象
  8601. var fnStr = "XMLHttpRequest()";
  8602. try {
  8603. new ActiveXObject("Msxml2.XMLHTTP");
  8604. fnStr = "ActiveXObject('Msxml2.XMLHTTP')";
  8605. } catch (e) {
  8606. try {
  8607. new ActiveXObject("Microsoft.XMLHTTP");
  8608. fnStr = "ActiveXObject('Microsoft.XMLHTTP')";
  8609. } catch (e) {}
  8610. }
  8611. var creatAjaxRequest = new Function("return new " + fnStr);
  8612. /**
  8613. * 将json参数转化成适合ajax提交的参数列表
  8614. * @param json
  8615. */
  8616. function json2str(json) {
  8617. var strArr = [];
  8618. for (var i in json) {
  8619. //忽略默认的几个参数
  8620. if (
  8621. i == "method" ||
  8622. i == "timeout" ||
  8623. i == "async" ||
  8624. i == "dataType" ||
  8625. i == "callback"
  8626. )
  8627. continue;
  8628. //忽略控制
  8629. if (json[i] == undefined || json[i] == null) continue;
  8630. //传递过来的对象和函数不在提交之列
  8631. if (
  8632. !(
  8633. (typeof json[i]).toLowerCase() == "function" ||
  8634. (typeof json[i]).toLowerCase() == "object"
  8635. )
  8636. ) {
  8637. strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]));
  8638. } else if (utils.isArray(json[i])) {
  8639. //支持传数组内容
  8640. for (var j = 0; j < json[i].length; j++) {
  8641. strArr.push(
  8642. encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])
  8643. );
  8644. }
  8645. }
  8646. }
  8647. return strArr.join("&");
  8648. }
  8649. function doAjax(url, ajaxOptions) {
  8650. var xhr = creatAjaxRequest(),
  8651. //是否超时
  8652. timeIsOut = false,
  8653. //默认参数
  8654. defaultAjaxOptions = {
  8655. method: "POST",
  8656. timeout: 5000,
  8657. async: true,
  8658. data: {}, //需要传递对象的话只能覆盖
  8659. onsuccess: function() {},
  8660. onerror: function() {}
  8661. };
  8662. if (typeof url === "object") {
  8663. ajaxOptions = url;
  8664. url = ajaxOptions.url;
  8665. }
  8666. if (!xhr || !url) return;
  8667. var ajaxOpts = ajaxOptions
  8668. ? utils.extend(defaultAjaxOptions, ajaxOptions)
  8669. : defaultAjaxOptions;
  8670. var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  8671. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  8672. if (!utils.isEmptyObject(ajaxOpts.data)) {
  8673. submitStr += (submitStr ? "&" : "") + json2str(ajaxOpts.data);
  8674. }
  8675. //超时检测
  8676. var timerID = setTimeout(function() {
  8677. if (xhr.readyState != 4) {
  8678. timeIsOut = true;
  8679. xhr.abort();
  8680. clearTimeout(timerID);
  8681. }
  8682. }, ajaxOpts.timeout);
  8683. var method = ajaxOpts.method.toUpperCase();
  8684. var str =
  8685. url +
  8686. (url.indexOf("?") == -1 ? "?" : "&") +
  8687. (method == "POST" ? "" : submitStr + "&noCache=" + +new Date());
  8688. xhr.open(method, str, ajaxOpts.async);
  8689. xhr.onreadystatechange = function() {
  8690. if (xhr.readyState == 4) {
  8691. if (!timeIsOut && xhr.status == 200) {
  8692. ajaxOpts.onsuccess(xhr);
  8693. } else {
  8694. ajaxOpts.onerror(xhr);
  8695. }
  8696. }
  8697. };
  8698. if (method == "POST") {
  8699. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  8700. xhr.send(submitStr);
  8701. } else {
  8702. xhr.send(null);
  8703. }
  8704. }
  8705. function doJsonp(url, opts) {
  8706. var successhandler = opts.onsuccess || function() {},
  8707. scr = document.createElement("SCRIPT"),
  8708. options = opts || {},
  8709. charset = options["charset"],
  8710. callbackField = options["jsonp"] || "callback",
  8711. callbackFnName,
  8712. timeOut = options["timeOut"] || 0,
  8713. timer,
  8714. reg = new RegExp("(\\?|&)" + callbackField + "=([^&]*)"),
  8715. matches;
  8716. if (utils.isFunction(successhandler)) {
  8717. callbackFnName =
  8718. "bd__editor__" + Math.floor(Math.random() * 2147483648).toString(36);
  8719. window[callbackFnName] = getCallBack(0);
  8720. } else if (utils.isString(successhandler)) {
  8721. callbackFnName = successhandler;
  8722. } else {
  8723. if ((matches = reg.exec(url))) {
  8724. callbackFnName = matches[2];
  8725. }
  8726. }
  8727. url = url.replace(reg, "\x241" + callbackField + "=" + callbackFnName);
  8728. if (url.search(reg) < 0) {
  8729. url +=
  8730. (url.indexOf("?") < 0 ? "?" : "&") +
  8731. callbackField +
  8732. "=" +
  8733. callbackFnName;
  8734. }
  8735. var queryStr = json2str(opts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  8736. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  8737. if (!utils.isEmptyObject(opts.data)) {
  8738. queryStr += (queryStr ? "&" : "") + json2str(opts.data);
  8739. }
  8740. if (queryStr) {
  8741. url = url.replace(/\?/, "?" + queryStr + "&");
  8742. }
  8743. scr.onerror = getCallBack(1);
  8744. if (timeOut) {
  8745. timer = setTimeout(getCallBack(1), timeOut);
  8746. }
  8747. createScriptTag(scr, url, charset);
  8748. function createScriptTag(scr, url, charset) {
  8749. scr.setAttribute("type", "text/javascript");
  8750. scr.setAttribute("defer", "defer");
  8751. charset && scr.setAttribute("charset", charset);
  8752. scr.setAttribute("src", url);
  8753. document.getElementsByTagName("head")[0].appendChild(scr);
  8754. }
  8755. function getCallBack(onTimeOut) {
  8756. return function() {
  8757. try {
  8758. if (onTimeOut) {
  8759. options.onerror && options.onerror();
  8760. } else {
  8761. try {
  8762. clearTimeout(timer);
  8763. successhandler.apply(window, arguments);
  8764. } catch (e) {}
  8765. }
  8766. } catch (exception) {
  8767. options.onerror && options.onerror.call(window, exception);
  8768. } finally {
  8769. options.oncomplete && options.oncomplete.apply(window, arguments);
  8770. scr.parentNode && scr.parentNode.removeChild(scr);
  8771. window[callbackFnName] = null;
  8772. try {
  8773. delete window[callbackFnName];
  8774. } catch (e) {}
  8775. }
  8776. };
  8777. }
  8778. }
  8779. return {
  8780. /**
  8781. * 根据给定的参数项,向指定的url发起一个ajax请求。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  8782. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调
  8783. * @method request
  8784. * @param { URLString } url ajax请求的url地址
  8785. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  8786. * @example
  8787. * ```javascript
  8788. * //向sayhello.php发起一个异步的Ajax GET请求, 请求超时时间为10s, 请求完成后执行相应的回调。
  8789. * UE.ajax.requeset( 'sayhello.php', {
  8790. *
  8791. * //请求方法。可选值: 'GET', 'POST',默认值是'POST'
  8792. * method: 'GET',
  8793. *
  8794. * //超时时间。 默认为5000, 单位是ms
  8795. * timeout: 10000,
  8796. *
  8797. * //是否是异步请求。 true为异步请求, false为同步请求
  8798. * async: true,
  8799. *
  8800. * //请求携带的数据。如果请求为GET请求, data会经过stringify后附加到请求url之后。
  8801. * data: {
  8802. * name: 'neditor'
  8803. * },
  8804. *
  8805. * //请求成功后的回调, 该回调接受当前的XMLHttpRequest对象作为参数。
  8806. * onsuccess: function ( xhr ) {
  8807. * console.log( xhr.responseText );
  8808. * },
  8809. *
  8810. * //请求失败或者超时后的回调。
  8811. * onerror: function ( xhr ) {
  8812. * alert( 'Ajax请求失败' );
  8813. * }
  8814. *
  8815. * } );
  8816. * ```
  8817. */
  8818. /**
  8819. * 根据给定的参数项发起一个ajax请求, 参数项里必须包含一个url地址。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  8820. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调。
  8821. * @method request
  8822. * @warning 如果在参数项里未提供一个key为“url”的地址值,则该请求将直接退出。
  8823. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  8824. * @example
  8825. * ```javascript
  8826. *
  8827. * //向sayhello.php发起一个异步的Ajax POST请求, 请求超时时间为5s, 请求完成后不执行任何回调。
  8828. * UE.ajax.requeset( 'sayhello.php', {
  8829. *
  8830. * //请求的地址, 该项是必须的。
  8831. * url: 'sayhello.php'
  8832. *
  8833. * } );
  8834. * ```
  8835. */
  8836. request: function(url, opts) {
  8837. if (opts && opts.dataType == "jsonp") {
  8838. doJsonp(url, opts);
  8839. } else {
  8840. doAjax(url, opts);
  8841. }
  8842. },
  8843. getJSONP: function(url, data, fn) {
  8844. var opts = {
  8845. data: data,
  8846. oncomplete: fn
  8847. };
  8848. doJsonp(url, opts);
  8849. }
  8850. };
  8851. })();
  8852. // core/filterword.js
  8853. /**
  8854. * UE过滤word的静态方法
  8855. * @file
  8856. */
  8857. /**
  8858. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  8859. * @module UE
  8860. */
  8861. /**
  8862. * 根据传入html字符串过滤word
  8863. * @module UE
  8864. * @since 1.2.6.1
  8865. * @method filterWord
  8866. * @param { String } html html字符串
  8867. * @return { String } 已过滤后的结果字符串
  8868. * @example
  8869. * ```javascript
  8870. * UE.filterWord(html);
  8871. * ```
  8872. */
  8873. var filterWord = (UE.filterWord = (function() {
  8874. //是否是word过来的内容
  8875. function isWordDocument(str) {
  8876. return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/gi.test(
  8877. str
  8878. );
  8879. }
  8880. //去掉小数
  8881. function transUnit(v) {
  8882. v = v.replace(/[\d.]+\w+/g, function(m) {
  8883. return utils.transUnitToPx(m);
  8884. });
  8885. return v;
  8886. }
  8887. function filterPasteWord(str) {
  8888. return (
  8889. str
  8890. .replace(/[\t\r\n]+/g, " ")
  8891. .replace(/<!--[\s\S]*?-->/gi, "")
  8892. //转换图片
  8893. .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi, function(str) {
  8894. //opera能自己解析出image所这里直接返回空
  8895. if (browser.opera) {
  8896. return "";
  8897. }
  8898. try {
  8899. //有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中
  8900. if (/Bitmap/i.test(str)) {
  8901. return "";
  8902. }
  8903. var width = str.match(/width:([ \d.]*p[tx])/i)[1],
  8904. height = str.match(/height:([ \d.]*p[tx])/i)[1],
  8905. src = str.match(/src=\s*"([^"]*)"/i)[1];
  8906. return (
  8907. '<img width="' +
  8908. transUnit(width) +
  8909. '" height="' +
  8910. transUnit(height) +
  8911. '" src="' +
  8912. src +
  8913. '" />'
  8914. );
  8915. } catch (e) {
  8916. return "";
  8917. }
  8918. })
  8919. //针对wps添加的多余标签处理
  8920. .replace(/<\/?div[^>]*>/g, "")
  8921. //去掉多余的属性
  8922. .replace(/v:\w+=(["']?)[^'"]+\1/g, "")
  8923. .replace(
  8924. /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi,
  8925. ""
  8926. )
  8927. .replace(
  8928. /<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi,
  8929. "<p><strong>$1</strong></p>"
  8930. )
  8931. //去掉多余的属性
  8932. .replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi, function(
  8933. str,
  8934. name,
  8935. marks,
  8936. val
  8937. ) {
  8938. //保留list的标示
  8939. return name == "class" && val == "MsoListParagraph" ? str : "";
  8940. })
  8941. //清除多余的font/span不能匹配&nbsp;有可能是空格
  8942. .replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function(a, b, c) {
  8943. return c.replace(/[\t\r\n ]+/g, " ");
  8944. })
  8945. //处理style的问题
  8946. .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function(
  8947. str,
  8948. tag,
  8949. tmp,
  8950. style
  8951. ) {
  8952. var n = [],
  8953. s = style
  8954. .replace(/^\s+|\s+$/, "")
  8955. .replace(/&#39;/g, "'")
  8956. .replace(/&quot;/gi, "'")
  8957. .replace(/[\d.]+(cm|pt)/g, function(str) {
  8958. return utils.transUnitToPx(str);
  8959. })
  8960. .split(/;\s*/g);
  8961. for (var i = 0, v; (v = s[i]); i++) {
  8962. var name,
  8963. value,
  8964. parts = v.split(":");
  8965. if (parts.length == 2) {
  8966. name = parts[0].toLowerCase();
  8967. value = parts[1].toLowerCase();
  8968. if (
  8969. (/^(background)\w*/.test(name) &&
  8970. value.replace(/(initial|\s)/g, "").length == 0) ||
  8971. (/^(margin)\w*/.test(name) && /^0\w+$/.test(value))
  8972. ) {
  8973. continue;
  8974. }
  8975. switch (name) {
  8976. case "mso-padding-alt":
  8977. case "mso-padding-top-alt":
  8978. case "mso-padding-right-alt":
  8979. case "mso-padding-bottom-alt":
  8980. case "mso-padding-left-alt":
  8981. case "mso-margin-alt":
  8982. case "mso-margin-top-alt":
  8983. case "mso-margin-right-alt":
  8984. case "mso-margin-bottom-alt":
  8985. case "mso-margin-left-alt":
  8986. //ie下会出现挤到一起的情况
  8987. //case "mso-table-layout-alt":
  8988. case "mso-height":
  8989. case "mso-width":
  8990. case "mso-vertical-align-alt":
  8991. //trace:1819 ff下会解析出padding在table上
  8992. if (!/<table/.test(tag))
  8993. n[i] =
  8994. name.replace(/^mso-|-alt$/g, "") + ":" + transUnit(value);
  8995. continue;
  8996. case "horiz-align":
  8997. n[i] = "text-align:" + value;
  8998. continue;
  8999. case "vert-align":
  9000. n[i] = "vertical-align:" + value;
  9001. continue;
  9002. case "font-color":
  9003. case "mso-foreground":
  9004. n[i] = "color:" + value;
  9005. continue;
  9006. case "mso-background":
  9007. case "mso-highlight":
  9008. n[i] = "background:" + value;
  9009. continue;
  9010. case "mso-default-height":
  9011. n[i] = "min-height:" + transUnit(value);
  9012. continue;
  9013. case "mso-default-width":
  9014. n[i] = "min-width:" + transUnit(value);
  9015. continue;
  9016. case "mso-padding-between-alt":
  9017. n[i] =
  9018. "border-collapse:separate;border-spacing:" +
  9019. transUnit(value);
  9020. continue;
  9021. case "text-line-through":
  9022. if (value == "single" || value == "double") {
  9023. n[i] = "text-decoration:line-through";
  9024. }
  9025. continue;
  9026. case "mso-zero-height":
  9027. if (value == "yes") {
  9028. n[i] = "display:none";
  9029. }
  9030. continue;
  9031. // case 'background':
  9032. // break;
  9033. case "margin":
  9034. if (!/[1-9]/.test(value)) {
  9035. continue;
  9036. }
  9037. }
  9038. if (
  9039. /^(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(
  9040. name
  9041. ) ||
  9042. (/text\-indent|padding|margin/.test(name) &&
  9043. /\-[\d.]+/.test(value))
  9044. ) {
  9045. continue;
  9046. }
  9047. n[i] = name + ":" + parts[1];
  9048. }
  9049. }
  9050. return (
  9051. tag +
  9052. (n.length
  9053. ? ' style="' + n.join(";").replace(/;{2,}/g, ";") + '"'
  9054. : "")
  9055. );
  9056. })
  9057. );
  9058. }
  9059. return function(html) {
  9060. return isWordDocument(html) ? filterPasteWord(html) : html;
  9061. };
  9062. })());
  9063. // core/node.js
  9064. /**
  9065. * 编辑器模拟的节点类
  9066. * @file
  9067. * @module UE
  9068. * @class uNode
  9069. * @since 1.2.6.1
  9070. */
  9071. /**
  9072. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9073. * @unfile
  9074. * @module UE
  9075. */
  9076. ;(function() {
  9077. /**
  9078. * 编辑器模拟的节点类
  9079. * @unfile
  9080. * @module UE
  9081. * @class uNode
  9082. */
  9083. /**
  9084. * 通过一个键值对,创建一个uNode对象
  9085. * @constructor
  9086. * @param { Object } attr 传入要创建的uNode的初始属性
  9087. * @example
  9088. * ```javascript
  9089. * var node = new uNode({
  9090. * type:'element',
  9091. * tagName:'span',
  9092. * attrs:{style:'font-size:14px;'}
  9093. * })
  9094. * ```
  9095. */
  9096. var uNode = (UE.uNode = function(obj) {
  9097. this.type = obj.type;
  9098. this.data = obj.data;
  9099. this.tagName = obj.tagName;
  9100. this.parentNode = obj.parentNode;
  9101. this.attrs = obj.attrs || {};
  9102. this.children = obj.children;
  9103. });
  9104. var notTransAttrs = {
  9105. href: 1,
  9106. src: 1,
  9107. _src: 1,
  9108. _href: 1,
  9109. cdata_data: 1
  9110. };
  9111. var notTransTagName = {
  9112. style: 1,
  9113. script: 1
  9114. };
  9115. var indentChar = " ",
  9116. breakChar = "\n";
  9117. function insertLine(arr, current, begin) {
  9118. arr.push(breakChar);
  9119. return current + (begin ? 1 : -1);
  9120. }
  9121. function insertIndent(arr, current) {
  9122. //插入缩进
  9123. for (var i = 0; i < current; i++) {
  9124. arr.push(indentChar);
  9125. }
  9126. }
  9127. //创建uNode的静态方法
  9128. //支持标签和html
  9129. uNode.createElement = function(html) {
  9130. if (/[<>]/.test(html)) {
  9131. return UE.htmlparser(html).children[0];
  9132. } else {
  9133. return new uNode({
  9134. type: "element",
  9135. children: [],
  9136. tagName: html
  9137. });
  9138. }
  9139. };
  9140. uNode.createText = function(data, noTrans) {
  9141. return new UE.uNode({
  9142. type: "text",
  9143. data: noTrans ? data : utils.unhtml(data || "")
  9144. });
  9145. };
  9146. function nodeToHtml(node, arr, formatter, current) {
  9147. switch (node.type) {
  9148. case "root":
  9149. for (var i = 0, ci; (ci = node.children[i++]); ) {
  9150. //插入新行
  9151. if (
  9152. formatter &&
  9153. ci.type == "element" &&
  9154. !dtd.$inlineWithA[ci.tagName] &&
  9155. i > 1
  9156. ) {
  9157. insertLine(arr, current, true);
  9158. insertIndent(arr, current);
  9159. }
  9160. nodeToHtml(ci, arr, formatter, current);
  9161. }
  9162. break;
  9163. case "text":
  9164. isText(node, arr);
  9165. break;
  9166. case "element":
  9167. isElement(node, arr, formatter, current);
  9168. break;
  9169. case "comment":
  9170. isComment(node, arr, formatter);
  9171. }
  9172. return arr;
  9173. }
  9174. function isText(node, arr) {
  9175. if (node.parentNode.tagName == "pre") {
  9176. //源码模式下输入html标签,不能做转换处理,直接输出
  9177. arr.push(node.data);
  9178. } else {
  9179. arr.push(
  9180. notTransTagName[node.parentNode.tagName]
  9181. ? utils.html(node.data)
  9182. : node.data.replace(/[ ]{2}/g, " &nbsp;")
  9183. );
  9184. }
  9185. }
  9186. function isElement(node, arr, formatter, current) {
  9187. var attrhtml = "";
  9188. if (node.attrs) {
  9189. attrhtml = [];
  9190. var attrs = node.attrs;
  9191. for (var a in attrs) {
  9192. //这里就针对
  9193. //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
  9194. //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
  9195. //有可能做的不够
  9196. attrhtml.push(
  9197. a +
  9198. (attrs[a] !== undefined
  9199. ? '="' +
  9200. (notTransAttrs[a]
  9201. ? utils.html(attrs[a]).replace(/["]/g, function(a) {
  9202. return "&quot;";
  9203. })
  9204. : utils.unhtml(attrs[a])) +
  9205. '"'
  9206. : "")
  9207. );
  9208. }
  9209. attrhtml = attrhtml.join(" ");
  9210. }
  9211. arr.push(
  9212. "<" +
  9213. node.tagName +
  9214. (attrhtml ? " " + attrhtml : "") +
  9215. (dtd.$empty[node.tagName] ? "/" : "") +
  9216. ">"
  9217. );
  9218. //插入新行
  9219. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != "pre") {
  9220. if (node.children && node.children.length) {
  9221. current = insertLine(arr, current, true);
  9222. insertIndent(arr, current);
  9223. }
  9224. }
  9225. if (node.children && node.children.length) {
  9226. for (var i = 0, ci; (ci = node.children[i++]); ) {
  9227. if (
  9228. formatter &&
  9229. ci.type == "element" &&
  9230. !dtd.$inlineWithA[ci.tagName] &&
  9231. i > 1
  9232. ) {
  9233. insertLine(arr, current);
  9234. insertIndent(arr, current);
  9235. }
  9236. nodeToHtml(ci, arr, formatter, current);
  9237. }
  9238. }
  9239. if (!dtd.$empty[node.tagName]) {
  9240. if (
  9241. formatter &&
  9242. !dtd.$inlineWithA[node.tagName] &&
  9243. node.tagName != "pre"
  9244. ) {
  9245. if (node.children && node.children.length) {
  9246. current = insertLine(arr, current);
  9247. insertIndent(arr, current);
  9248. }
  9249. }
  9250. arr.push("</" + node.tagName + ">");
  9251. }
  9252. }
  9253. function isComment(node, arr) {
  9254. arr.push("<!--" + node.data + "-->");
  9255. }
  9256. function getNodeById(root, id) {
  9257. var node;
  9258. if (root.type == "element" && root.getAttr("id") == id) {
  9259. return root;
  9260. }
  9261. if (root.children && root.children.length) {
  9262. for (var i = 0, ci; (ci = root.children[i++]); ) {
  9263. if ((node = getNodeById(ci, id))) {
  9264. return node;
  9265. }
  9266. }
  9267. }
  9268. }
  9269. function getNodesByTagName(node, tagName, arr) {
  9270. if (node.type == "element" && node.tagName == tagName) {
  9271. arr.push(node);
  9272. }
  9273. if (node.children && node.children.length) {
  9274. for (var i = 0, ci; (ci = node.children[i++]); ) {
  9275. getNodesByTagName(ci, tagName, arr);
  9276. }
  9277. }
  9278. }
  9279. function nodeTraversal(root, fn) {
  9280. if (root.children && root.children.length) {
  9281. for (var i = 0, ci; (ci = root.children[i]); ) {
  9282. nodeTraversal(ci, fn);
  9283. //ci被替换的情况,这里就不再走 fn了
  9284. if (ci.parentNode) {
  9285. if (ci.children && ci.children.length) {
  9286. fn(ci);
  9287. }
  9288. if (ci.parentNode) i++;
  9289. }
  9290. }
  9291. } else {
  9292. fn(root);
  9293. }
  9294. }
  9295. uNode.prototype = {
  9296. /**
  9297. * 当前节点对象,转换成html文本
  9298. * @method toHtml
  9299. * @return { String } 返回转换后的html字符串
  9300. * @example
  9301. * ```javascript
  9302. * node.toHtml();
  9303. * ```
  9304. */
  9305. /**
  9306. * 当前节点对象,转换成html文本
  9307. * @method toHtml
  9308. * @param { Boolean } formatter 是否格式化返回值
  9309. * @return { String } 返回转换后的html字符串
  9310. * @example
  9311. * ```javascript
  9312. * node.toHtml( true );
  9313. * ```
  9314. */
  9315. toHtml: function(formatter) {
  9316. var arr = [];
  9317. nodeToHtml(this, arr, formatter, 0);
  9318. return arr.join("");
  9319. },
  9320. /**
  9321. * 获取节点的html内容
  9322. * @method innerHTML
  9323. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9324. * @return { String } 返回节点的html内容
  9325. * @example
  9326. * ```javascript
  9327. * var htmlstr = node.innerHTML();
  9328. * ```
  9329. */
  9330. /**
  9331. * 设置节点的html内容
  9332. * @method innerHTML
  9333. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9334. * @param { String } htmlstr 传入要设置的html内容
  9335. * @return { UE.uNode } 返回节点本身
  9336. * @example
  9337. * ```javascript
  9338. * node.innerHTML('<span>text</span>');
  9339. * ```
  9340. */
  9341. innerHTML: function(htmlstr) {
  9342. if (this.type != "element" || dtd.$empty[this.tagName]) {
  9343. return this;
  9344. }
  9345. if (utils.isString(htmlstr)) {
  9346. if (this.children) {
  9347. for (var i = 0, ci; (ci = this.children[i++]); ) {
  9348. ci.parentNode = null;
  9349. }
  9350. }
  9351. this.children = [];
  9352. var tmpRoot = UE.htmlparser(htmlstr);
  9353. for (var i = 0, ci; (ci = tmpRoot.children[i++]); ) {
  9354. this.children.push(ci);
  9355. ci.parentNode = this;
  9356. }
  9357. return this;
  9358. } else {
  9359. var tmpRoot = new UE.uNode({
  9360. type: "root",
  9361. children: this.children
  9362. });
  9363. return tmpRoot.toHtml();
  9364. }
  9365. },
  9366. /**
  9367. * 获取节点的纯文本内容
  9368. * @method innerText
  9369. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9370. * @return { String } 返回节点的存文本内容
  9371. * @example
  9372. * ```javascript
  9373. * var textStr = node.innerText();
  9374. * ```
  9375. */
  9376. /**
  9377. * 设置节点的纯文本内容
  9378. * @method innerText
  9379. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9380. * @param { String } textStr 传入要设置的文本内容
  9381. * @return { UE.uNode } 返回节点本身
  9382. * @example
  9383. * ```javascript
  9384. * node.innerText('<span>text</span>');
  9385. * ```
  9386. */
  9387. innerText: function(textStr, noTrans) {
  9388. if (this.type != "element" || dtd.$empty[this.tagName]) {
  9389. return this;
  9390. }
  9391. if (textStr) {
  9392. if (this.children) {
  9393. for (var i = 0, ci; (ci = this.children[i++]); ) {
  9394. ci.parentNode = null;
  9395. }
  9396. }
  9397. this.children = [];
  9398. this.appendChild(uNode.createText(textStr, noTrans));
  9399. return this;
  9400. } else {
  9401. return this.toHtml().replace(/<[^>]+>/g, "");
  9402. }
  9403. },
  9404. /**
  9405. * 获取当前对象的data属性
  9406. * @method getData
  9407. * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
  9408. * @example
  9409. * ```javascript
  9410. * node.getData();
  9411. * ```
  9412. */
  9413. getData: function() {
  9414. if (this.type == "element") return "";
  9415. return this.data;
  9416. },
  9417. /**
  9418. * 获取当前节点下的第一个子节点
  9419. * @method firstChild
  9420. * @return { UE.uNode } 返回第一个子节点
  9421. * @example
  9422. * ```javascript
  9423. * node.firstChild(); //返回第一个子节点
  9424. * ```
  9425. */
  9426. firstChild: function() {
  9427. // if (this.type != 'element' || dtd.$empty[this.tagName]) {
  9428. // return this;
  9429. // }
  9430. return this.children ? this.children[0] : null;
  9431. },
  9432. /**
  9433. * 获取当前节点下的最后一个子节点
  9434. * @method lastChild
  9435. * @return { UE.uNode } 返回最后一个子节点
  9436. * @example
  9437. * ```javascript
  9438. * node.lastChild(); //返回最后一个子节点
  9439. * ```
  9440. */
  9441. lastChild: function() {
  9442. // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
  9443. // return this;
  9444. // }
  9445. return this.children ? this.children[this.children.length - 1] : null;
  9446. },
  9447. /**
  9448. * 获取和当前节点有相同父亲节点的前一个节点
  9449. * @method previousSibling
  9450. * @return { UE.uNode } 返回前一个节点
  9451. * @example
  9452. * ```javascript
  9453. * node.children[2].previousSibling(); //返回子节点node.children[1]
  9454. * ```
  9455. */
  9456. previousSibling: function() {
  9457. var parent = this.parentNode;
  9458. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  9459. if (ci === this) {
  9460. return i == 0 ? null : parent.children[i - 1];
  9461. }
  9462. }
  9463. },
  9464. /**
  9465. * 获取和当前节点有相同父亲节点的后一个节点
  9466. * @method nextSibling
  9467. * @return { UE.uNode } 返回后一个节点,找不到返回null
  9468. * @example
  9469. * ```javascript
  9470. * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
  9471. * ```
  9472. */
  9473. nextSibling: function() {
  9474. var parent = this.parentNode;
  9475. for (var i = 0, ci; (ci = parent.children[i++]); ) {
  9476. if (ci === this) {
  9477. return parent.children[i];
  9478. }
  9479. }
  9480. },
  9481. /**
  9482. * 用新的节点替换当前节点
  9483. * @method replaceChild
  9484. * @param { UE.uNode } target 要替换成该节点参数
  9485. * @param { UE.uNode } source 要被替换掉的节点
  9486. * @return { UE.uNode } 返回替换之后的节点对象
  9487. * @example
  9488. * ```javascript
  9489. * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
  9490. * ```
  9491. */
  9492. replaceChild: function(target, source) {
  9493. if (this.children) {
  9494. if (target.parentNode) {
  9495. target.parentNode.removeChild(target);
  9496. }
  9497. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9498. if (ci === source) {
  9499. this.children.splice(i, 1, target);
  9500. source.parentNode = null;
  9501. target.parentNode = this;
  9502. return target;
  9503. }
  9504. }
  9505. }
  9506. },
  9507. /**
  9508. * 在节点的子节点列表最后位置插入一个节点
  9509. * @method appendChild
  9510. * @param { UE.uNode } node 要插入的节点
  9511. * @return { UE.uNode } 返回刚插入的子节点
  9512. * @example
  9513. * ```javascript
  9514. * node.appendChild( newNode ); //在node内插入子节点newNode
  9515. * ```
  9516. */
  9517. appendChild: function(node) {
  9518. if (
  9519. this.type == "root" ||
  9520. (this.type == "element" && !dtd.$empty[this.tagName])
  9521. ) {
  9522. if (!this.children) {
  9523. this.children = [];
  9524. }
  9525. if (node.parentNode) {
  9526. node.parentNode.removeChild(node);
  9527. }
  9528. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9529. if (ci === node) {
  9530. this.children.splice(i, 1);
  9531. break;
  9532. }
  9533. }
  9534. this.children.push(node);
  9535. node.parentNode = this;
  9536. return node;
  9537. }
  9538. },
  9539. /**
  9540. * 在传入节点的前面插入一个节点
  9541. * @method insertBefore
  9542. * @param { UE.uNode } target 要插入的节点
  9543. * @param { UE.uNode } source 在该参数节点前面插入
  9544. * @return { UE.uNode } 返回刚插入的子节点
  9545. * @example
  9546. * ```javascript
  9547. * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
  9548. * ```
  9549. */
  9550. insertBefore: function(target, source) {
  9551. if (this.children) {
  9552. if (target.parentNode) {
  9553. target.parentNode.removeChild(target);
  9554. }
  9555. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9556. if (ci === source) {
  9557. this.children.splice(i, 0, target);
  9558. target.parentNode = this;
  9559. return target;
  9560. }
  9561. }
  9562. }
  9563. },
  9564. /**
  9565. * 在传入节点的后面插入一个节点
  9566. * @method insertAfter
  9567. * @param { UE.uNode } target 要插入的节点
  9568. * @param { UE.uNode } source 在该参数节点后面插入
  9569. * @return { UE.uNode } 返回刚插入的子节点
  9570. * @example
  9571. * ```javascript
  9572. * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
  9573. * ```
  9574. */
  9575. insertAfter: function(target, source) {
  9576. if (this.children) {
  9577. if (target.parentNode) {
  9578. target.parentNode.removeChild(target);
  9579. }
  9580. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9581. if (ci === source) {
  9582. this.children.splice(i + 1, 0, target);
  9583. target.parentNode = this;
  9584. return target;
  9585. }
  9586. }
  9587. }
  9588. },
  9589. /**
  9590. * 从当前节点的子节点列表中,移除节点
  9591. * @method removeChild
  9592. * @param { UE.uNode } node 要移除的节点引用
  9593. * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
  9594. * @return { * } 返回刚移除的子节点
  9595. * @example
  9596. * ```javascript
  9597. * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
  9598. * ```
  9599. */
  9600. removeChild: function(node, keepChildren) {
  9601. if (this.children) {
  9602. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9603. if (ci === node) {
  9604. this.children.splice(i, 1);
  9605. ci.parentNode = null;
  9606. if (keepChildren && ci.children && ci.children.length) {
  9607. for (var j = 0, cj; (cj = ci.children[j]); j++) {
  9608. this.children.splice(i + j, 0, cj);
  9609. cj.parentNode = this;
  9610. }
  9611. }
  9612. return ci;
  9613. }
  9614. }
  9615. }
  9616. },
  9617. /**
  9618. * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
  9619. * @method getAttr
  9620. * @param { String } attrName 要获取的属性名称
  9621. * @return { * } 返回attrs对象下的属性值
  9622. * @example
  9623. * ```javascript
  9624. * node.getAttr('title');
  9625. * ```
  9626. */
  9627. getAttr: function(attrName) {
  9628. return this.attrs && this.attrs[attrName.toLowerCase()];
  9629. },
  9630. /**
  9631. * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
  9632. * @method setAttr
  9633. * @param { String } attrName 要设置的属性名称
  9634. * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
  9635. * @return { * } 返回attrs对象下的属性值
  9636. * @example
  9637. * ```javascript
  9638. * node.setAttr('title','标题');
  9639. * ```
  9640. */
  9641. setAttr: function(attrName, attrVal) {
  9642. if (!attrName) {
  9643. delete this.attrs;
  9644. return;
  9645. }
  9646. if (!this.attrs) {
  9647. this.attrs = {};
  9648. }
  9649. if (utils.isObject(attrName)) {
  9650. for (var a in attrName) {
  9651. if (!attrName[a]) {
  9652. delete this.attrs[a];
  9653. } else {
  9654. this.attrs[a.toLowerCase()] = attrName[a];
  9655. }
  9656. }
  9657. } else {
  9658. if (!attrVal) {
  9659. delete this.attrs[attrName];
  9660. } else {
  9661. this.attrs[attrName.toLowerCase()] = attrVal;
  9662. }
  9663. }
  9664. },
  9665. /**
  9666. * 获取当前节点在父节点下的位置索引
  9667. * @method getIndex
  9668. * @return { Number } 返回索引数值,如果没有父节点,返回-1
  9669. * @example
  9670. * ```javascript
  9671. * node.getIndex();
  9672. * ```
  9673. */
  9674. getIndex: function() {
  9675. var parent = this.parentNode;
  9676. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  9677. if (ci === this) {
  9678. return i;
  9679. }
  9680. }
  9681. return -1;
  9682. },
  9683. /**
  9684. * 在当前节点下,根据id查找节点
  9685. * @method getNodeById
  9686. * @param { String } id 要查找的id
  9687. * @return { UE.uNode } 返回找到的节点
  9688. * @example
  9689. * ```javascript
  9690. * node.getNodeById('textId');
  9691. * ```
  9692. */
  9693. getNodeById: function(id) {
  9694. var node;
  9695. if (this.children && this.children.length) {
  9696. for (var i = 0, ci; (ci = this.children[i++]); ) {
  9697. if ((node = getNodeById(ci, id))) {
  9698. return node;
  9699. }
  9700. }
  9701. }
  9702. },
  9703. /**
  9704. * 在当前节点下,根据元素名称查找节点列表
  9705. * @method getNodesByTagName
  9706. * @param { String } tagNames 要查找的元素名称
  9707. * @return { Array } 返回找到的节点列表
  9708. * @example
  9709. * ```javascript
  9710. * node.getNodesByTagName('span');
  9711. * ```
  9712. */
  9713. getNodesByTagName: function(tagNames) {
  9714. tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, " ").split(" ");
  9715. var arr = [],
  9716. me = this;
  9717. utils.each(tagNames, function(tagName) {
  9718. if (me.children && me.children.length) {
  9719. for (var i = 0, ci; (ci = me.children[i++]); ) {
  9720. getNodesByTagName(ci, tagName, arr);
  9721. }
  9722. }
  9723. });
  9724. return arr;
  9725. },
  9726. /**
  9727. * 根据样式名称,获取节点的样式值
  9728. * @method getStyle
  9729. * @param { String } name 要获取的样式名称
  9730. * @return { String } 返回样式值
  9731. * @example
  9732. * ```javascript
  9733. * node.getStyle('font-size');
  9734. * ```
  9735. */
  9736. getStyle: function(name) {
  9737. var cssStyle = this.getAttr("style");
  9738. if (!cssStyle) {
  9739. return "";
  9740. }
  9741. var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+)", "i");
  9742. var match = cssStyle.match(reg);
  9743. if (match && match[0]) {
  9744. return match[2];
  9745. }
  9746. return "";
  9747. },
  9748. /**
  9749. * 给节点设置样式
  9750. * @method setStyle
  9751. * @param { String } name 要设置的的样式名称
  9752. * @param { String } val 要设置的的样值
  9753. * @example
  9754. * ```javascript
  9755. * node.setStyle('font-size', '12px');
  9756. * ```
  9757. */
  9758. setStyle: function(name, val) {
  9759. function exec(name, val) {
  9760. var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+;?)", "gi");
  9761. cssStyle = cssStyle.replace(reg, "$1");
  9762. if (val) {
  9763. cssStyle = name + ":" + utils.unhtml(val) + ";" + cssStyle;
  9764. }
  9765. }
  9766. var cssStyle = this.getAttr("style");
  9767. if (!cssStyle) {
  9768. cssStyle = "";
  9769. }
  9770. if (utils.isObject(name)) {
  9771. for (var a in name) {
  9772. exec(a, name[a]);
  9773. }
  9774. } else {
  9775. exec(name, val);
  9776. }
  9777. this.setAttr("style", utils.trim(cssStyle));
  9778. },
  9779. /**
  9780. * 传入一个函数,递归遍历当前节点下的所有节点
  9781. * @method traversal
  9782. * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
  9783. * @example
  9784. * ```javascript
  9785. * traversal(node, function(){
  9786. * console.log(node.type);
  9787. * });
  9788. * ```
  9789. */
  9790. traversal: function(fn) {
  9791. if (this.children && this.children.length) {
  9792. nodeTraversal(this, fn);
  9793. }
  9794. return this;
  9795. }
  9796. };
  9797. })();
  9798. // core/htmlparser.js
  9799. /**
  9800. * html字符串转换成uNode节点
  9801. * @file
  9802. * @module UE
  9803. * @since 1.2.6.1
  9804. */
  9805. /**
  9806. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9807. * @unfile
  9808. * @module UE
  9809. */
  9810. /**
  9811. * html字符串转换成uNode节点的静态方法
  9812. * @method htmlparser
  9813. * @param { String } htmlstr 要转换的html代码
  9814. * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
  9815. * @return { uNode } 给定的html片段转换形成的uNode对象
  9816. * @example
  9817. * ```javascript
  9818. * var root = UE.htmlparser('<p><b>htmlparser</b></p>', true);
  9819. * ```
  9820. */
  9821. var htmlparser = (UE.htmlparser = function(htmlstr, ignoreBlank) {
  9822. //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 <TD vAlign=top background=../AAA.JPG> 这样的标签了
  9823. //先去掉了,加上的原因忘了,这里先记录
  9824. //var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  9825. //以上的正则表达式无法匹配:<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>
  9826. //修改为如下正则表达式:
  9827. var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g,
  9828. re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
  9829. //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
  9830. var allowEmptyTags = {
  9831. b: 1,
  9832. code: 1,
  9833. i: 1,
  9834. u: 1,
  9835. strike: 1,
  9836. s: 1,
  9837. tt: 1,
  9838. strong: 1,
  9839. q: 1,
  9840. samp: 1,
  9841. em: 1,
  9842. span: 1,
  9843. sub: 1,
  9844. img: 1,
  9845. sup: 1,
  9846. font: 1,
  9847. big: 1,
  9848. small: 1,
  9849. iframe: 1,
  9850. a: 1,
  9851. br: 1,
  9852. pre: 1
  9853. };
  9854. htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, "g"), "");
  9855. if (!ignoreBlank) {
  9856. htmlstr = htmlstr.replace(
  9857. new RegExp(
  9858. "[\\r\\t\\n" +
  9859. (ignoreBlank ? "" : " ") +
  9860. "]*</?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n" +
  9861. (ignoreBlank ? "" : " ") +
  9862. "]*",
  9863. "g"
  9864. ),
  9865. function(a, b) {
  9866. //br暂时单独处理
  9867. if (b && allowEmptyTags[b.toLowerCase()]) {
  9868. return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, "");
  9869. }
  9870. return a
  9871. .replace(new RegExp("^[\\r\\n" + (ignoreBlank ? "" : " ") + "]+"), "")
  9872. .replace(
  9873. new RegExp("[\\r\\n" + (ignoreBlank ? "" : " ") + "]+$"),
  9874. ""
  9875. );
  9876. }
  9877. );
  9878. }
  9879. var notTransAttrs = {
  9880. href: 1,
  9881. src: 1
  9882. };
  9883. var uNode = UE.uNode,
  9884. needParentNode = {
  9885. td: "tr",
  9886. tr: ["tbody", "thead", "tfoot"],
  9887. tbody: "table",
  9888. th: "tr",
  9889. thead: "table",
  9890. tfoot: "table",
  9891. caption: "table",
  9892. li: ["ul", "ol"],
  9893. dt: "dl",
  9894. dd: "dl",
  9895. option: "select"
  9896. },
  9897. needChild = {
  9898. ol: "li",
  9899. ul: "li"
  9900. };
  9901. function text(parent, data) {
  9902. if (needChild[parent.tagName]) {
  9903. var tmpNode = uNode.createElement(needChild[parent.tagName]);
  9904. parent.appendChild(tmpNode);
  9905. tmpNode.appendChild(uNode.createText(data));
  9906. parent = tmpNode;
  9907. } else {
  9908. parent.appendChild(uNode.createText(data));
  9909. }
  9910. }
  9911. function element(parent, tagName, htmlattr) {
  9912. var needParentTag;
  9913. if ((needParentTag = needParentNode[tagName])) {
  9914. var tmpParent = parent,
  9915. hasParent;
  9916. while (tmpParent.type != "root") {
  9917. if (
  9918. utils.isArray(needParentTag)
  9919. ? utils.indexOf(needParentTag, tmpParent.tagName) != -1
  9920. : needParentTag == tmpParent.tagName
  9921. ) {
  9922. parent = tmpParent;
  9923. hasParent = true;
  9924. break;
  9925. }
  9926. tmpParent = tmpParent.parentNode;
  9927. }
  9928. if (!hasParent) {
  9929. parent = element(
  9930. parent,
  9931. utils.isArray(needParentTag) ? needParentTag[0] : needParentTag
  9932. );
  9933. }
  9934. }
  9935. //按dtd处理嵌套
  9936. // if(parent.type != 'root' && !dtd[parent.tagName][tagName])
  9937. // parent = parent.parentNode;
  9938. var elm = new uNode({
  9939. parentNode: parent,
  9940. type: "element",
  9941. tagName: tagName.toLowerCase(),
  9942. //是自闭合的处理一下
  9943. children: dtd.$empty[tagName] ? null : []
  9944. });
  9945. //如果属性存在,处理属性
  9946. if (htmlattr) {
  9947. var attrs = {},
  9948. match;
  9949. while ((match = re_attr.exec(htmlattr))) {
  9950. attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()]
  9951. ? match[2] || match[3] || match[4]
  9952. : utils.unhtml(match[2] || match[3] || match[4]);
  9953. }
  9954. elm.attrs = attrs;
  9955. }
  9956. //trace:3970
  9957. // //如果parent下不能放elm
  9958. // if(dtd.$inline[parent.tagName] && dtd.$block[elm.tagName] && !dtd[parent.tagName][elm.tagName]){
  9959. // parent = parent.parentNode;
  9960. // elm.parentNode = parent;
  9961. // }
  9962. parent.children.push(elm);
  9963. //如果是自闭合节点返回父亲节点
  9964. return dtd.$empty[tagName] ? parent : elm;
  9965. }
  9966. function comment(parent, data) {
  9967. parent.children.push(
  9968. new uNode({
  9969. type: "comment",
  9970. data: data,
  9971. parentNode: parent
  9972. })
  9973. );
  9974. }
  9975. var match,
  9976. currentIndex = 0,
  9977. nextIndex = 0;
  9978. //设置根节点
  9979. var root = new uNode({
  9980. type: "root",
  9981. children: []
  9982. });
  9983. var currentParent = root;
  9984. while ((match = re_tag.exec(htmlstr))) {
  9985. currentIndex = match.index;
  9986. try {
  9987. if (currentIndex > nextIndex) {
  9988. //text node
  9989. text(currentParent, htmlstr.slice(nextIndex, currentIndex));
  9990. }
  9991. if (match[3]) {
  9992. if (dtd.$cdata[currentParent.tagName]) {
  9993. text(currentParent, match[0]);
  9994. } else {
  9995. //start tag
  9996. currentParent = element(
  9997. currentParent,
  9998. match[3].toLowerCase(),
  9999. match[4]
  10000. );
  10001. }
  10002. } else if (match[1]) {
  10003. if (currentParent.type != "root") {
  10004. if (dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) {
  10005. text(currentParent, match[0]);
  10006. } else {
  10007. var tmpParent = currentParent;
  10008. while (
  10009. currentParent.type == "element" &&
  10010. currentParent.tagName != match[1].toLowerCase()
  10011. ) {
  10012. currentParent = currentParent.parentNode;
  10013. if (currentParent.type == "root") {
  10014. currentParent = tmpParent;
  10015. throw "break";
  10016. }
  10017. }
  10018. //end tag
  10019. currentParent = currentParent.parentNode;
  10020. }
  10021. }
  10022. } else if (match[2]) {
  10023. //comment
  10024. comment(currentParent, match[2]);
  10025. }
  10026. } catch (e) {}
  10027. nextIndex = re_tag.lastIndex;
  10028. }
  10029. //如果结束是文本,就有可能丢掉,所以这里手动判断一下
  10030. //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
  10031. if (nextIndex < htmlstr.length) {
  10032. text(currentParent, htmlstr.slice(nextIndex));
  10033. }
  10034. return root;
  10035. });
  10036. // core/filternode.js
  10037. /**
  10038. * UE过滤节点的静态方法
  10039. * @file
  10040. */
  10041. /**
  10042. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  10043. * @module UE
  10044. */
  10045. /**
  10046. * 根据传入节点和过滤规则过滤相应节点
  10047. * @module UE
  10048. * @since 1.2.6.1
  10049. * @method filterNode
  10050. * @param { Object } root 指定root节点
  10051. * @param { Object } rules 过滤规则json对象
  10052. * @example
  10053. * ```javascript
  10054. * UE.filterNode(root,editor.options.filterRules);
  10055. * ```
  10056. */
  10057. var filterNode = (UE.filterNode = (function() {
  10058. function filterNode(node, rules) {
  10059. switch (node.type) {
  10060. case "text":
  10061. break;
  10062. case "element":
  10063. var val;
  10064. if ((val = rules[node.tagName])) {
  10065. if (val === "-") {
  10066. node.parentNode.removeChild(node);
  10067. } else if (utils.isFunction(val)) {
  10068. var parentNode = node.parentNode,
  10069. index = node.getIndex();
  10070. val(node);
  10071. if (node.parentNode) {
  10072. if (node.children) {
  10073. for (var i = 0, ci; (ci = node.children[i]); ) {
  10074. filterNode(ci, rules);
  10075. if (ci.parentNode) {
  10076. i++;
  10077. }
  10078. }
  10079. }
  10080. } else {
  10081. for (var i = index, ci; (ci = parentNode.children[i]); ) {
  10082. filterNode(ci, rules);
  10083. if (ci.parentNode) {
  10084. i++;
  10085. }
  10086. }
  10087. }
  10088. } else {
  10089. var attrs = val["$"];
  10090. if (attrs && node.attrs) {
  10091. var tmpAttrs = {},
  10092. tmpVal;
  10093. for (var a in attrs) {
  10094. tmpVal = node.getAttr(a);
  10095. //todo 只先对style单独处理
  10096. if (a == "style" && utils.isArray(attrs[a])) {
  10097. var tmpCssStyle = [];
  10098. utils.each(attrs[a], function(v) {
  10099. var tmp;
  10100. if ((tmp = node.getStyle(v))) {
  10101. tmpCssStyle.push(v + ":" + tmp);
  10102. }
  10103. });
  10104. tmpVal = tmpCssStyle.join(";");
  10105. }
  10106. if (tmpVal) {
  10107. tmpAttrs[a] = tmpVal;
  10108. }
  10109. }
  10110. node.attrs = tmpAttrs;
  10111. }
  10112. if (node.children) {
  10113. for (var i = 0, ci; (ci = node.children[i]); ) {
  10114. filterNode(ci, rules);
  10115. if (ci.parentNode) {
  10116. i++;
  10117. }
  10118. }
  10119. }
  10120. }
  10121. } else {
  10122. //如果不在名单里扣出子节点并删除该节点,cdata除外
  10123. if (dtd.$cdata[node.tagName]) {
  10124. node.parentNode.removeChild(node);
  10125. } else {
  10126. var parentNode = node.parentNode,
  10127. index = node.getIndex();
  10128. node.parentNode.removeChild(node, true);
  10129. for (var i = index, ci; (ci = parentNode.children[i]); ) {
  10130. filterNode(ci, rules);
  10131. if (ci.parentNode) {
  10132. i++;
  10133. }
  10134. }
  10135. }
  10136. }
  10137. break;
  10138. case "comment":
  10139. node.parentNode.removeChild(node);
  10140. }
  10141. }
  10142. return function(root, rules) {
  10143. if (utils.isEmptyObject(rules)) {
  10144. return root;
  10145. }
  10146. var val;
  10147. if ((val = rules["-"])) {
  10148. utils.each(val.split(" "), function(k) {
  10149. rules[k] = "-";
  10150. });
  10151. }
  10152. for (var i = 0, ci; (ci = root.children[i]); ) {
  10153. filterNode(ci, rules);
  10154. if (ci.parentNode) {
  10155. i++;
  10156. }
  10157. }
  10158. return root;
  10159. };
  10160. })());
  10161. // core/plugin.js
  10162. /**
  10163. * Created with JetBrains PhpStorm.
  10164. * User: campaign
  10165. * Date: 10/8/13
  10166. * Time: 6:15 PM
  10167. * To change this template use File | Settings | File Templates.
  10168. */
  10169. UE.plugin = (function() {
  10170. var _plugins = {};
  10171. return {
  10172. register: function(pluginName, fn, oldOptionName, afterDisabled) {
  10173. if (oldOptionName && utils.isFunction(oldOptionName)) {
  10174. afterDisabled = oldOptionName;
  10175. oldOptionName = null;
  10176. }
  10177. _plugins[pluginName] = {
  10178. optionName: oldOptionName || pluginName,
  10179. execFn: fn,
  10180. //当插件被禁用时执行
  10181. afterDisabled: afterDisabled
  10182. };
  10183. },
  10184. load: function(editor) {
  10185. utils.each(_plugins, function(plugin) {
  10186. var _export = plugin.execFn.call(editor);
  10187. if (editor.options[plugin.optionName] !== false) {
  10188. if (_export) {
  10189. //后边需要再做扩展
  10190. utils.each(_export, function(v, k) {
  10191. switch (k.toLowerCase()) {
  10192. case "shortcutkey":
  10193. editor.addshortcutkey(v);
  10194. break;
  10195. case "bindevents":
  10196. utils.each(v, function(fn, eventName) {
  10197. editor.addListener(eventName, fn);
  10198. });
  10199. break;
  10200. case "bindmultievents":
  10201. utils.each(utils.isArray(v) ? v : [v], function(event) {
  10202. var types = utils.trim(event.type).split(/\s+/);
  10203. utils.each(types, function(eventName) {
  10204. editor.addListener(eventName, event.handler);
  10205. });
  10206. });
  10207. break;
  10208. case "commands":
  10209. utils.each(v, function(execFn, execName) {
  10210. editor.commands[execName] = execFn;
  10211. });
  10212. break;
  10213. case "outputrule":
  10214. editor.addOutputRule(v);
  10215. break;
  10216. case "inputrule":
  10217. editor.addInputRule(v);
  10218. break;
  10219. case "defaultoptions":
  10220. editor.setOpt(v);
  10221. }
  10222. });
  10223. }
  10224. } else if (plugin.afterDisabled) {
  10225. plugin.afterDisabled.call(editor);
  10226. }
  10227. });
  10228. //向下兼容
  10229. utils.each(UE.plugins, function(plugin) {
  10230. plugin.call(editor);
  10231. });
  10232. },
  10233. run: function(pluginName, editor) {
  10234. var plugin = _plugins[pluginName];
  10235. if (plugin) {
  10236. plugin.exeFn.call(editor);
  10237. }
  10238. }
  10239. };
  10240. })();
  10241. // core/keymap.js
  10242. var keymap = (UE.keymap = {
  10243. Backspace: 8,
  10244. Tab: 9,
  10245. Enter: 13,
  10246. Shift: 16,
  10247. Control: 17,
  10248. Alt: 18,
  10249. CapsLock: 20,
  10250. Esc: 27,
  10251. Spacebar: 32,
  10252. PageUp: 33,
  10253. PageDown: 34,
  10254. End: 35,
  10255. Home: 36,
  10256. Left: 37,
  10257. Up: 38,
  10258. Right: 39,
  10259. Down: 40,
  10260. Insert: 45,
  10261. Del: 46,
  10262. NumLock: 144,
  10263. Cmd: 91,
  10264. "=": 187,
  10265. "-": 189,
  10266. b: 66,
  10267. i: 73,
  10268. //回退
  10269. z: 90,
  10270. y: 89,
  10271. //粘贴
  10272. v: 86,
  10273. x: 88,
  10274. s: 83,
  10275. n: 78
  10276. });
  10277. // core/localstorage.js
  10278. //存储媒介封装
  10279. var LocalStorage = (UE.LocalStorage = (function() {
  10280. var storage = window.localStorage || getUserData() || null,
  10281. LOCAL_FILE = "localStorage";
  10282. return {
  10283. saveLocalData: function(key, data) {
  10284. if (storage && data) {
  10285. storage.setItem(key, data);
  10286. return true;
  10287. }
  10288. return false;
  10289. },
  10290. getLocalData: function(key) {
  10291. if (storage) {
  10292. return storage.getItem(key);
  10293. }
  10294. return null;
  10295. },
  10296. removeItem: function(key) {
  10297. storage && storage.removeItem(key);
  10298. }
  10299. };
  10300. function getUserData() {
  10301. var container = document.createElement("div");
  10302. container.style.display = "none";
  10303. if (!container.addBehavior) {
  10304. return null;
  10305. }
  10306. container.addBehavior("#default#userdata");
  10307. return {
  10308. getItem: function(key) {
  10309. var result = null;
  10310. try {
  10311. document.body.appendChild(container);
  10312. container.load(LOCAL_FILE);
  10313. result = container.getAttribute(key);
  10314. document.body.removeChild(container);
  10315. } catch (e) {}
  10316. return result;
  10317. },
  10318. setItem: function(key, value) {
  10319. document.body.appendChild(container);
  10320. container.setAttribute(key, value);
  10321. container.save(LOCAL_FILE);
  10322. document.body.removeChild(container);
  10323. },
  10324. //// 暂时没有用到
  10325. //clear: function () {
  10326. //
  10327. // var expiresTime = new Date();
  10328. // expiresTime.setFullYear(expiresTime.getFullYear() - 1);
  10329. // document.body.appendChild(container);
  10330. // container.expires = expiresTime.toUTCString();
  10331. // container.save(LOCAL_FILE);
  10332. // document.body.removeChild(container);
  10333. //
  10334. //},
  10335. removeItem: function(key) {
  10336. document.body.appendChild(container);
  10337. container.removeAttribute(key);
  10338. container.save(LOCAL_FILE);
  10339. document.body.removeChild(container);
  10340. }
  10341. };
  10342. }
  10343. })());
  10344. ;(function() {
  10345. var ROOTKEY = "ueditor_preference";
  10346. UE.Editor.prototype.setPreferences = function(key, value) {
  10347. var obj = {};
  10348. if (utils.isString(key)) {
  10349. obj[key] = value;
  10350. } else {
  10351. obj = key;
  10352. }
  10353. var data = LocalStorage.getLocalData(ROOTKEY);
  10354. if (data && (data = utils.str2json(data))) {
  10355. utils.extend(data, obj);
  10356. } else {
  10357. data = obj;
  10358. }
  10359. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  10360. };
  10361. UE.Editor.prototype.getPreferences = function(key) {
  10362. var data = LocalStorage.getLocalData(ROOTKEY);
  10363. if (data && (data = utils.str2json(data))) {
  10364. return key ? data[key] : data;
  10365. }
  10366. return null;
  10367. };
  10368. UE.Editor.prototype.removePreferences = function(key) {
  10369. var data = LocalStorage.getLocalData(ROOTKEY);
  10370. if (data && (data = utils.str2json(data))) {
  10371. data[key] = undefined;
  10372. delete data[key];
  10373. }
  10374. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  10375. };
  10376. })();
  10377. // plugins/defaultfilter.js
  10378. ///import core
  10379. ///plugin 编辑器默认的过滤转换机制
  10380. UE.plugins["defaultfilter"] = function() {
  10381. var me = this;
  10382. me.setOpt({
  10383. allowDivTransToP: true,
  10384. disabledTableInTable: true,
  10385. rgb2Hex: true
  10386. });
  10387. //默认的过滤处理
  10388. //进入编辑器的内容处理
  10389. me.addInputRule(function(root) {
  10390. var allowDivTransToP = this.options.allowDivTransToP;
  10391. var val;
  10392. function tdParent(node) {
  10393. while (node && node.type == "element") {
  10394. if (node.tagName == "td") {
  10395. return true;
  10396. }
  10397. node = node.parentNode;
  10398. }
  10399. return false;
  10400. }
  10401. //进行默认的处理
  10402. root.traversal(function(node) {
  10403. if (node.type == "element") {
  10404. if (
  10405. !dtd.$cdata[node.tagName] &&
  10406. me.options.autoClearEmptyNode &&
  10407. dtd.$inline[node.tagName] &&
  10408. !dtd.$empty[node.tagName] &&
  10409. (!node.attrs || utils.isEmptyObject(node.attrs))
  10410. ) {
  10411. if (!node.firstChild()) node.parentNode.removeChild(node);
  10412. else if (
  10413. node.tagName == "span" &&
  10414. (!node.attrs || utils.isEmptyObject(node.attrs))
  10415. ) {
  10416. node.parentNode.removeChild(node, true);
  10417. }
  10418. return;
  10419. }
  10420. switch (node.tagName) {
  10421. case "style":
  10422. case "script":
  10423. node.setAttr({
  10424. cdata_tag: node.tagName,
  10425. cdata_data: node.innerHTML() || "",
  10426. _ue_custom_node_: "true"
  10427. });
  10428. node.tagName = "div";
  10429. node.innerHTML("");
  10430. break;
  10431. case "a":
  10432. if ((val = node.getAttr("href"))) {
  10433. node.setAttr("_href", val);
  10434. }
  10435. break;
  10436. case "img":
  10437. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  10438. if ((val = node.getAttr("src"))) {
  10439. if (/^data:/.test(val)) {
  10440. node.parentNode.removeChild(node);
  10441. break;
  10442. }
  10443. }
  10444. node.setAttr("_src", node.getAttr("src"));
  10445. break;
  10446. case "span":
  10447. if (browser.webkit && (val = node.getStyle("white-space"))) {
  10448. if (/nowrap|normal/.test(val)) {
  10449. node.setStyle("white-space", "");
  10450. if (
  10451. me.options.autoClearEmptyNode &&
  10452. utils.isEmptyObject(node.attrs)
  10453. ) {
  10454. node.parentNode.removeChild(node, true);
  10455. }
  10456. }
  10457. }
  10458. val = node.getAttr("id");
  10459. if (val && /^_baidu_bookmark_/i.test(val)) {
  10460. node.parentNode.removeChild(node);
  10461. }
  10462. break;
  10463. case "p":
  10464. if ((val = node.getAttr("align"))) {
  10465. node.setAttr("align");
  10466. node.setStyle("text-align", val);
  10467. }
  10468. //trace:3431
  10469. // var cssStyle = node.getAttr('style');
  10470. // if (cssStyle) {
  10471. // cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
  10472. // node.setAttr('style', cssStyle)
  10473. //
  10474. // }
  10475. //p标签不允许嵌套
  10476. utils.each(node.children, function(n) {
  10477. if (n.type == "element" && n.tagName == "p") {
  10478. var next = n.nextSibling();
  10479. node.parentNode.insertAfter(n, node);
  10480. var last = n;
  10481. while (next) {
  10482. var tmp = next.nextSibling();
  10483. node.parentNode.insertAfter(next, last);
  10484. last = next;
  10485. next = tmp;
  10486. }
  10487. return false;
  10488. }
  10489. });
  10490. if (!node.firstChild()) {
  10491. node.innerHTML(browser.ie ? "&nbsp;" : "<br/>");
  10492. }
  10493. break;
  10494. case "div":
  10495. if (node.getAttr("cdata_tag")) {
  10496. break;
  10497. }
  10498. //针对代码这里不处理插入代码的div
  10499. val = node.getAttr("class");
  10500. if (val && /^line number\d+/.test(val)) {
  10501. break;
  10502. }
  10503. if (!allowDivTransToP) {
  10504. break;
  10505. }
  10506. var tmpNode,
  10507. p = UE.uNode.createElement("p");
  10508. while ((tmpNode = node.firstChild())) {
  10509. if (
  10510. tmpNode.type == "text" ||
  10511. !UE.dom.dtd.$block[tmpNode.tagName]
  10512. ) {
  10513. p.appendChild(tmpNode);
  10514. } else {
  10515. if (p.firstChild()) {
  10516. node.parentNode.insertBefore(p, node);
  10517. p = UE.uNode.createElement("p");
  10518. } else {
  10519. node.parentNode.insertBefore(tmpNode, node);
  10520. }
  10521. }
  10522. }
  10523. if (p.firstChild()) {
  10524. node.parentNode.insertBefore(p, node);
  10525. }
  10526. node.parentNode.removeChild(node);
  10527. break;
  10528. case "dl":
  10529. node.tagName = "ul";
  10530. break;
  10531. case "dt":
  10532. case "dd":
  10533. node.tagName = "li";
  10534. break;
  10535. case "li":
  10536. var className = node.getAttr("class");
  10537. if (!className || !/list\-/.test(className)) {
  10538. node.setAttr();
  10539. }
  10540. var tmpNodes = node.getNodesByTagName("ol ul");
  10541. UE.utils.each(tmpNodes, function(n) {
  10542. node.parentNode.insertAfter(n, node);
  10543. });
  10544. break;
  10545. case "td":
  10546. case "th":
  10547. case "caption":
  10548. if (!node.children || !node.children.length) {
  10549. node.appendChild(
  10550. browser.ie11below
  10551. ? UE.uNode.createText(" ")
  10552. : UE.uNode.createElement("br")
  10553. );
  10554. }
  10555. break;
  10556. case "table":
  10557. if (me.options.disabledTableInTable && tdParent(node)) {
  10558. node.parentNode.insertBefore(
  10559. UE.uNode.createText(node.innerText()),
  10560. node
  10561. );
  10562. node.parentNode.removeChild(node);
  10563. }
  10564. }
  10565. }
  10566. // if(node.type == 'comment'){
  10567. // node.parentNode.removeChild(node);
  10568. // }
  10569. });
  10570. });
  10571. //从编辑器出去的内容处理
  10572. me.addOutputRule(function(root) {
  10573. var val;
  10574. root.traversal(function(node) {
  10575. if (node.type == "element") {
  10576. if (
  10577. me.options.autoClearEmptyNode &&
  10578. dtd.$inline[node.tagName] &&
  10579. !dtd.$empty[node.tagName] &&
  10580. (!node.attrs || utils.isEmptyObject(node.attrs))
  10581. ) {
  10582. if (!node.firstChild()) node.parentNode.removeChild(node);
  10583. else if (
  10584. node.tagName == "span" &&
  10585. (!node.attrs || utils.isEmptyObject(node.attrs))
  10586. ) {
  10587. node.parentNode.removeChild(node, true);
  10588. }
  10589. return;
  10590. }
  10591. switch (node.tagName) {
  10592. case "div":
  10593. if ((val = node.getAttr("cdata_tag"))) {
  10594. node.tagName = val;
  10595. node.appendChild(UE.uNode.createText(node.getAttr("cdata_data")));
  10596. node.setAttr({
  10597. cdata_tag: "",
  10598. cdata_data: "",
  10599. _ue_custom_node_: ""
  10600. });
  10601. }
  10602. break;
  10603. case "a":
  10604. if ((val = node.getAttr("_href"))) {
  10605. node.setAttr({
  10606. href: utils.html(val),
  10607. _href: ""
  10608. });
  10609. }
  10610. break;
  10611. break;
  10612. case "span":
  10613. val = node.getAttr("id");
  10614. if (val && /^_baidu_bookmark_/i.test(val)) {
  10615. node.parentNode.removeChild(node);
  10616. }
  10617. //将color的rgb格式转换为#16进制格式
  10618. if (me.getOpt("rgb2Hex")) {
  10619. var cssStyle = node.getAttr("style");
  10620. if (cssStyle) {
  10621. node.setAttr(
  10622. "style",
  10623. cssStyle.replace(/rgba?\(([\d,\s]+)\)/g, function(a, value) {
  10624. var array = value.split(",");
  10625. if (array.length > 3) return "";
  10626. value = "#";
  10627. for (var i = 0, color; (color = array[i++]); ) {
  10628. color = parseInt(
  10629. color.replace(/[^\d]/gi, ""),
  10630. 10
  10631. ).toString(16);
  10632. value += color.length == 1 ? "0" + color : color;
  10633. }
  10634. return value.toUpperCase();
  10635. })
  10636. );
  10637. }
  10638. }
  10639. break;
  10640. case "img":
  10641. if ((val = node.getAttr("_src"))) {
  10642. node.setAttr({
  10643. src: node.getAttr("_src"),
  10644. _src: ""
  10645. });
  10646. }
  10647. }
  10648. }
  10649. });
  10650. });
  10651. };
  10652. // plugins/inserthtml.js
  10653. /**
  10654. * 插入html字符串插件
  10655. * @file
  10656. * @since 1.2.6.1
  10657. */
  10658. /**
  10659. * 插入html代码
  10660. * @command inserthtml
  10661. * @method execCommand
  10662. * @param { String } cmd 命令字符串
  10663. * @param { String } html 插入的html字符串
  10664. * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
  10665. * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
  10666. * @example
  10667. * ```javascript
  10668. * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
  10669. * //执行命令,插入<b>CC</b>
  10670. * //插入后的效果 xxx<b>CC</b>xxx
  10671. * //<p>xx|xxx</p> 当前选区为闭合状态
  10672. * //插入<p>CC</p>
  10673. * //结果 <p>xx</p><p>CC</p><p>xxx</p>
  10674. * //<p>xxxx</p>|</p>xxx</p> 当前选区在两个p标签之间
  10675. * //插入 xxxx
  10676. * //结果 <p>xxxx</p><p>xxxx</p></p>xxx</p>
  10677. * ```
  10678. */
  10679. UE.commands["inserthtml"] = {
  10680. execCommand: function(command, html, notNeedFilter) {
  10681. var me = this,
  10682. range,
  10683. div;
  10684. if (!html) {
  10685. return;
  10686. }
  10687. if (me.fireEvent("beforeinserthtml", html) === true) {
  10688. return;
  10689. }
  10690. range = me.selection.getRange();
  10691. div = range.document.createElement("div");
  10692. div.style.display = "inline";
  10693. if (!notNeedFilter) {
  10694. var root = UE.htmlparser(html);
  10695. //如果给了过滤规则就先进行过滤
  10696. if (me.options.filterRules) {
  10697. UE.filterNode(root, me.options.filterRules);
  10698. }
  10699. //执行默认的处理
  10700. me.filterInputRule(root);
  10701. html = root.toHtml();
  10702. }
  10703. div.innerHTML = utils.trim(html);
  10704. if (!range.collapsed) {
  10705. var tmpNode = range.startContainer;
  10706. if (domUtils.isFillChar(tmpNode)) {
  10707. range.setStartBefore(tmpNode);
  10708. }
  10709. tmpNode = range.endContainer;
  10710. if (domUtils.isFillChar(tmpNode)) {
  10711. range.setEndAfter(tmpNode);
  10712. }
  10713. range.txtToElmBoundary();
  10714. //结束边界可能放到了br的前边,要把br包含进来
  10715. // x[xxx]<br/>
  10716. if (range.endContainer && range.endContainer.nodeType == 1) {
  10717. tmpNode = range.endContainer.childNodes[range.endOffset];
  10718. if (tmpNode && domUtils.isBr(tmpNode)) {
  10719. range.setEndAfter(tmpNode);
  10720. }
  10721. }
  10722. if (range.startOffset == 0) {
  10723. tmpNode = range.startContainer;
  10724. if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
  10725. tmpNode = range.endContainer;
  10726. if (
  10727. range.endOffset ==
  10728. (tmpNode.nodeType == 3
  10729. ? tmpNode.nodeValue.length
  10730. : tmpNode.childNodes.length) &&
  10731. domUtils.isBoundaryNode(tmpNode, "lastChild")
  10732. ) {
  10733. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  10734. range.setStart(me.body.firstChild, 0).collapse(true);
  10735. }
  10736. }
  10737. }
  10738. !range.collapsed && range.deleteContents();
  10739. if (range.startContainer.nodeType == 1) {
  10740. var child = range.startContainer.childNodes[range.startOffset],
  10741. pre;
  10742. if (
  10743. child &&
  10744. domUtils.isBlockElm(child) &&
  10745. (pre = child.previousSibling) &&
  10746. domUtils.isBlockElm(pre)
  10747. ) {
  10748. range.setEnd(pre, pre.childNodes.length).collapse();
  10749. while (child.firstChild) {
  10750. pre.appendChild(child.firstChild);
  10751. }
  10752. domUtils.remove(child);
  10753. }
  10754. }
  10755. }
  10756. var child,
  10757. parent,
  10758. pre,
  10759. tmp,
  10760. hadBreak = 0,
  10761. nextNode;
  10762. //如果当前位置选中了fillchar要干掉,要不会产生空行
  10763. if (range.inFillChar()) {
  10764. child = range.startContainer;
  10765. if (domUtils.isFillChar(child)) {
  10766. range.setStartBefore(child).collapse(true);
  10767. domUtils.remove(child);
  10768. } else if (domUtils.isFillChar(child, true)) {
  10769. child.nodeValue = child.nodeValue.replace(fillCharReg, "");
  10770. range.startOffset--;
  10771. range.collapsed && range.collapse(true);
  10772. }
  10773. }
  10774. //列表单独处理
  10775. var li = domUtils.findParentByTagName(range.startContainer, "li", true);
  10776. if (li) {
  10777. var next, last;
  10778. while ((child = div.firstChild)) {
  10779. //针对hr单独处理一下先
  10780. while (
  10781. child &&
  10782. (child.nodeType == 3 ||
  10783. !domUtils.isBlockElm(child) ||
  10784. child.tagName == "HR")
  10785. ) {
  10786. next = child.nextSibling;
  10787. range.insertNode(child).collapse();
  10788. last = child;
  10789. child = next;
  10790. }
  10791. if (child) {
  10792. if (/^(ol|ul)$/i.test(child.tagName)) {
  10793. while (child.firstChild) {
  10794. last = child.firstChild;
  10795. domUtils.insertAfter(li, child.firstChild);
  10796. li = li.nextSibling;
  10797. }
  10798. domUtils.remove(child);
  10799. } else {
  10800. var tmpLi;
  10801. next = child.nextSibling;
  10802. tmpLi = me.document.createElement("li");
  10803. domUtils.insertAfter(li, tmpLi);
  10804. tmpLi.appendChild(child);
  10805. last = child;
  10806. child = next;
  10807. li = tmpLi;
  10808. }
  10809. }
  10810. }
  10811. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  10812. if (domUtils.isEmptyBlock(li)) {
  10813. domUtils.remove(li);
  10814. }
  10815. if (last) {
  10816. range.setStartAfter(last).collapse(true).select(true);
  10817. }
  10818. } else {
  10819. while ((child = div.firstChild)) {
  10820. if (hadBreak) {
  10821. var p = me.document.createElement("p");
  10822. while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
  10823. nextNode = child.nextSibling;
  10824. p.appendChild(child);
  10825. child = nextNode;
  10826. }
  10827. if (p.firstChild) {
  10828. child = p;
  10829. }
  10830. }
  10831. range.insertNode(child);
  10832. nextNode = child.nextSibling;
  10833. if (
  10834. !hadBreak &&
  10835. child.nodeType == domUtils.NODE_ELEMENT &&
  10836. domUtils.isBlockElm(child)
  10837. ) {
  10838. parent = domUtils.findParent(child, function(node) {
  10839. return domUtils.isBlockElm(node);
  10840. });
  10841. if (
  10842. parent &&
  10843. parent.tagName.toLowerCase() != "body" &&
  10844. !(
  10845. dtd[parent.tagName][child.nodeName] && child.parentNode === parent
  10846. )
  10847. ) {
  10848. if (!dtd[parent.tagName][child.nodeName]) {
  10849. pre = parent;
  10850. } else {
  10851. tmp = child.parentNode;
  10852. while (tmp !== parent) {
  10853. pre = tmp;
  10854. tmp = tmp.parentNode;
  10855. }
  10856. }
  10857. domUtils.breakParent(child, pre || tmp);
  10858. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  10859. var pre = child.previousSibling;
  10860. domUtils.trimWhiteTextNode(pre);
  10861. if (!pre.childNodes.length) {
  10862. domUtils.remove(pre);
  10863. }
  10864. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  10865. if (
  10866. !browser.ie &&
  10867. (next = child.nextSibling) &&
  10868. domUtils.isBlockElm(next) &&
  10869. next.lastChild &&
  10870. !domUtils.isBr(next.lastChild)
  10871. ) {
  10872. next.appendChild(me.document.createElement("br"));
  10873. }
  10874. hadBreak = 1;
  10875. }
  10876. }
  10877. var next = child.nextSibling;
  10878. if (!div.firstChild && next && domUtils.isBlockElm(next)) {
  10879. range.setStart(next, 0).collapse(true);
  10880. break;
  10881. }
  10882. range.setEndAfter(child).collapse();
  10883. }
  10884. child = range.startContainer;
  10885. if (nextNode && domUtils.isBr(nextNode)) {
  10886. domUtils.remove(nextNode);
  10887. }
  10888. //用chrome可能有空白展位符
  10889. if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
  10890. if ((nextNode = child.nextSibling)) {
  10891. domUtils.remove(child);
  10892. if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
  10893. range.setStart(nextNode, 0).collapse(true).shrinkBoundary();
  10894. }
  10895. } else {
  10896. try {
  10897. child.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
  10898. } catch (e) {
  10899. range.setStartBefore(child);
  10900. domUtils.remove(child);
  10901. }
  10902. }
  10903. }
  10904. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  10905. try {
  10906. range.select(true);
  10907. } catch (e) {}
  10908. }
  10909. setTimeout(function() {
  10910. range = me.selection.getRange();
  10911. range.scrollToView(
  10912. me.autoHeightEnabled,
  10913. me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0
  10914. );
  10915. me.fireEvent("afterinserthtml", html);
  10916. }, 200);
  10917. }
  10918. };
  10919. // plugins/autotypeset.js
  10920. /**
  10921. * 自动排版
  10922. * @file
  10923. * @since 1.2.6.1
  10924. */
  10925. /**
  10926. * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
  10927. * @command autotypeset
  10928. * @method execCommand
  10929. * @param { String } cmd 命令字符串
  10930. * @example
  10931. * ```javascript
  10932. * editor.execCommand( 'autotypeset' );
  10933. * ```
  10934. */
  10935. UE.plugins["autotypeset"] = function() {
  10936. this.setOpt({
  10937. autotypeset: {
  10938. mergeEmptyline: true, //合并空行
  10939. removeClass: true, //去掉冗余的class
  10940. removeEmptyline: false, //去掉空行
  10941. textAlign: "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  10942. imageBlockLine: "center", //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  10943. pasteFilter: false, //根据规则过滤没事粘贴进来的内容
  10944. clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
  10945. clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
  10946. removeEmptyNode: false, // 去掉空节点
  10947. //可以去掉的标签
  10948. removeTagNames: utils.extend({ div: 1 }, dtd.$removeEmpty),
  10949. indent: false, // 行首缩进
  10950. indentValue: "2em", //行首缩进的大小
  10951. bdc2sb: false,
  10952. tobdc: false
  10953. }
  10954. });
  10955. var me = this,
  10956. opt = me.options.autotypeset,
  10957. remainClass = {
  10958. selectTdClass: 1,
  10959. pagebreak: 1,
  10960. anchorclass: 1
  10961. },
  10962. remainTag = {
  10963. li: 1
  10964. },
  10965. tags = {
  10966. div: 1,
  10967. p: 1,
  10968. //trace:2183 这些也认为是行
  10969. blockquote: 1,
  10970. center: 1,
  10971. h1: 1,
  10972. h2: 1,
  10973. h3: 1,
  10974. h4: 1,
  10975. h5: 1,
  10976. h6: 1,
  10977. span: 1
  10978. },
  10979. highlightCont;
  10980. //升级了版本,但配置项目里没有autotypeset
  10981. if (!opt) {
  10982. return;
  10983. }
  10984. readLocalOpts();
  10985. function isLine(node, notEmpty) {
  10986. if (!node || node.nodeType == 3) return 0;
  10987. if (domUtils.isBr(node)) return 1;
  10988. if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
  10989. if (
  10990. (highlightCont && highlightCont.contains(node)) ||
  10991. node.getAttribute("pagebreak")
  10992. ) {
  10993. return 0;
  10994. }
  10995. return notEmpty
  10996. ? !domUtils.isEmptyBlock(node)
  10997. : domUtils.isEmptyBlock(
  10998. node,
  10999. new RegExp("[\\s" + domUtils.fillChar + "]", "g")
  11000. );
  11001. }
  11002. }
  11003. function removeNotAttributeSpan(node) {
  11004. if (!node.style.cssText) {
  11005. domUtils.removeAttributes(node, ["style"]);
  11006. if (
  11007. node.tagName.toLowerCase() == "span" &&
  11008. domUtils.hasNoAttributes(node)
  11009. ) {
  11010. domUtils.remove(node, true);
  11011. }
  11012. }
  11013. }
  11014. function autotype(type, html) {
  11015. var me = this,
  11016. cont;
  11017. if (html) {
  11018. if (!opt.pasteFilter) {
  11019. return;
  11020. }
  11021. cont = me.document.createElement("div");
  11022. cont.innerHTML = html.html;
  11023. } else {
  11024. cont = me.document.body;
  11025. }
  11026. var nodes = domUtils.getElementsByTagName(cont, "*");
  11027. // 行首缩进,段落方向,段间距,段内间距
  11028. for (var i = 0, ci; (ci = nodes[i++]); ) {
  11029. if (me.fireEvent("excludeNodeinautotype", ci) === true) {
  11030. continue;
  11031. }
  11032. //font-size
  11033. if (opt.clearFontSize && ci.style.fontSize) {
  11034. domUtils.removeStyle(ci, "font-size");
  11035. removeNotAttributeSpan(ci);
  11036. }
  11037. //font-family
  11038. if (opt.clearFontFamily && ci.style.fontFamily) {
  11039. domUtils.removeStyle(ci, "font-family");
  11040. removeNotAttributeSpan(ci);
  11041. }
  11042. if (isLine(ci)) {
  11043. //合并空行
  11044. if (opt.mergeEmptyline) {
  11045. var next = ci.nextSibling,
  11046. tmpNode,
  11047. isBr = domUtils.isBr(ci);
  11048. while (isLine(next)) {
  11049. tmpNode = next;
  11050. next = tmpNode.nextSibling;
  11051. if (isBr && (!next || (next && !domUtils.isBr(next)))) {
  11052. break;
  11053. }
  11054. domUtils.remove(tmpNode);
  11055. }
  11056. }
  11057. //去掉空行,保留占位的空行
  11058. if (
  11059. opt.removeEmptyline &&
  11060. domUtils.inDoc(ci, cont) &&
  11061. !remainTag[ci.parentNode.tagName.toLowerCase()]
  11062. ) {
  11063. if (domUtils.isBr(ci)) {
  11064. next = ci.nextSibling;
  11065. if (next && !domUtils.isBr(next)) {
  11066. continue;
  11067. }
  11068. }
  11069. domUtils.remove(ci);
  11070. continue;
  11071. }
  11072. }
  11073. if (isLine(ci, true) && ci.tagName != "SPAN") {
  11074. if (opt.indent) {
  11075. ci.style.textIndent = opt.indentValue;
  11076. }
  11077. if (opt.textAlign) {
  11078. ci.style.textAlign = opt.textAlign;
  11079. }
  11080. // if(opt.lineHeight)
  11081. // ci.style.lineHeight = opt.lineHeight + 'cm';
  11082. }
  11083. //去掉class,保留的class不去掉
  11084. if (
  11085. opt.removeClass &&
  11086. ci.className &&
  11087. !remainClass[ci.className.toLowerCase()]
  11088. ) {
  11089. if (highlightCont && highlightCont.contains(ci)) {
  11090. continue;
  11091. }
  11092. domUtils.removeAttributes(ci, ["class"]);
  11093. }
  11094. //表情不处理
  11095. if (
  11096. opt.imageBlockLine &&
  11097. ci.tagName.toLowerCase() == "img" &&
  11098. !ci.getAttribute("emotion")
  11099. ) {
  11100. if (html) {
  11101. var img = ci;
  11102. switch (opt.imageBlockLine) {
  11103. case "left":
  11104. case "right":
  11105. case "none":
  11106. var pN = img.parentNode,
  11107. tmpNode,
  11108. pre,
  11109. next;
  11110. while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
  11111. pN = pN.parentNode;
  11112. }
  11113. tmpNode = pN;
  11114. if (
  11115. tmpNode.tagName == "P" &&
  11116. domUtils.getStyle(tmpNode, "text-align") == "center"
  11117. ) {
  11118. if (
  11119. !domUtils.isBody(tmpNode) &&
  11120. domUtils.getChildCount(tmpNode, function(node) {
  11121. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11122. }) == 1
  11123. ) {
  11124. pre = tmpNode.previousSibling;
  11125. next = tmpNode.nextSibling;
  11126. if (
  11127. pre &&
  11128. next &&
  11129. pre.nodeType == 1 &&
  11130. next.nodeType == 1 &&
  11131. pre.tagName == next.tagName &&
  11132. domUtils.isBlockElm(pre)
  11133. ) {
  11134. pre.appendChild(tmpNode.firstChild);
  11135. while (next.firstChild) {
  11136. pre.appendChild(next.firstChild);
  11137. }
  11138. domUtils.remove(tmpNode);
  11139. domUtils.remove(next);
  11140. } else {
  11141. domUtils.setStyle(tmpNode, "text-align", "");
  11142. }
  11143. }
  11144. }
  11145. domUtils.setStyle(img, "float", opt.imageBlockLine);
  11146. break;
  11147. case "center":
  11148. if (me.queryCommandValue("imagefloat") != "center") {
  11149. pN = img.parentNode;
  11150. domUtils.setStyle(img, "float", "none");
  11151. tmpNode = img;
  11152. while (
  11153. pN &&
  11154. domUtils.getChildCount(pN, function(node) {
  11155. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11156. }) == 1 &&
  11157. (dtd.$inline[pN.tagName] || pN.tagName == "A")
  11158. ) {
  11159. tmpNode = pN;
  11160. pN = pN.parentNode;
  11161. }
  11162. var pNode = me.document.createElement("p");
  11163. domUtils.setAttributes(pNode, {
  11164. style: "text-align:center"
  11165. });
  11166. tmpNode.parentNode.insertBefore(pNode, tmpNode);
  11167. pNode.appendChild(tmpNode);
  11168. domUtils.setStyle(tmpNode, "float", "");
  11169. }
  11170. }
  11171. } else {
  11172. var range = me.selection.getRange();
  11173. range.selectNode(ci).select();
  11174. me.execCommand("imagefloat", opt.imageBlockLine);
  11175. }
  11176. }
  11177. //去掉冗余的标签
  11178. if (opt.removeEmptyNode) {
  11179. if (
  11180. opt.removeTagNames[ci.tagName.toLowerCase()] &&
  11181. domUtils.hasNoAttributes(ci) &&
  11182. domUtils.isEmptyBlock(ci)
  11183. ) {
  11184. domUtils.remove(ci);
  11185. }
  11186. }
  11187. }
  11188. if (opt.tobdc) {
  11189. var root = UE.htmlparser(cont.innerHTML);
  11190. root.traversal(function(node) {
  11191. if (node.type == "text") {
  11192. node.data = ToDBC(node.data);
  11193. }
  11194. });
  11195. cont.innerHTML = root.toHtml();
  11196. }
  11197. if (opt.bdc2sb) {
  11198. var root = UE.htmlparser(cont.innerHTML);
  11199. root.traversal(function(node) {
  11200. if (node.type == "text") {
  11201. node.data = DBC2SB(node.data);
  11202. }
  11203. });
  11204. cont.innerHTML = root.toHtml();
  11205. }
  11206. if (html) {
  11207. html.html = cont.innerHTML;
  11208. }
  11209. }
  11210. if (opt.pasteFilter) {
  11211. me.addListener("beforepaste", autotype);
  11212. }
  11213. function DBC2SB(str) {
  11214. var result = "";
  11215. for (var i = 0; i < str.length; i++) {
  11216. var code = str.charCodeAt(i); //获取当前字符的unicode编码
  11217. if (code >= 65281 && code <= 65373) {
  11218. //在这个unicode编码范围中的是所有的英文字母已经各种字符
  11219. result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码
  11220. } else if (code == 12288) {
  11221. //空格
  11222. result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
  11223. } else {
  11224. result += str.charAt(i);
  11225. }
  11226. }
  11227. return result;
  11228. }
  11229. function ToDBC(txtstring) {
  11230. txtstring = utils.html(txtstring);
  11231. var tmp = "";
  11232. var mark = ""; /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
  11233. for (var i = 0; i < txtstring.length; i++) {
  11234. if (txtstring.charCodeAt(i) == 32) {
  11235. tmp = tmp + String.fromCharCode(12288);
  11236. } else if (txtstring.charCodeAt(i) < 127) {
  11237. tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248);
  11238. } else {
  11239. tmp += txtstring.charAt(i);
  11240. }
  11241. }
  11242. return tmp;
  11243. }
  11244. function readLocalOpts() {
  11245. var cookieOpt = me.getPreferences("autotypeset");
  11246. utils.extend(me.options.autotypeset, cookieOpt);
  11247. }
  11248. me.commands["autotypeset"] = {
  11249. execCommand: function() {
  11250. me.removeListener("beforepaste", autotype);
  11251. if (opt.pasteFilter) {
  11252. me.addListener("beforepaste", autotype);
  11253. }
  11254. autotype.call(me);
  11255. }
  11256. };
  11257. };
  11258. // plugins/autosubmit.js
  11259. /**
  11260. * 快捷键提交
  11261. * @file
  11262. * @since 1.2.6.1
  11263. */
  11264. /**
  11265. * 提交表单
  11266. * @command autosubmit
  11267. * @method execCommand
  11268. * @param { String } cmd 命令字符串
  11269. * @example
  11270. * ```javascript
  11271. * editor.execCommand( 'autosubmit' );
  11272. * ```
  11273. */
  11274. UE.plugin.register("autosubmit", function() {
  11275. return {
  11276. shortcutkey: {
  11277. autosubmit: "ctrl+13" //手动提交
  11278. },
  11279. commands: {
  11280. autosubmit: {
  11281. execCommand: function() {
  11282. var me = this,
  11283. form = domUtils.findParentByTagName(me.iframe, "form", false);
  11284. if (form) {
  11285. if (me.fireEvent("beforesubmit") === false) {
  11286. return;
  11287. }
  11288. me.sync();
  11289. form.submit();
  11290. }
  11291. }
  11292. }
  11293. }
  11294. };
  11295. });
  11296. // plugins/background.js
  11297. /**
  11298. * 背景插件,为UEditor提供设置背景功能
  11299. * @file
  11300. * @since 1.2.6.1
  11301. */
  11302. UE.plugin.register("background", function() {
  11303. var me = this,
  11304. cssRuleId = "editor_background",
  11305. isSetColored,
  11306. reg = new RegExp("body[\\s]*\\{(.+)\\}", "i");
  11307. function stringToObj(str) {
  11308. var obj = {},
  11309. styles = str.split(";");
  11310. utils.each(styles, function(v) {
  11311. var index = v.indexOf(":"),
  11312. key = utils.trim(v.substr(0, index)).toLowerCase();
  11313. key && (obj[key] = utils.trim(v.substr(index + 1) || ""));
  11314. });
  11315. return obj;
  11316. }
  11317. function setBackground(obj) {
  11318. if (obj) {
  11319. var styles = [];
  11320. for (var name in obj) {
  11321. if (obj.hasOwnProperty(name)) {
  11322. styles.push(name + ":" + obj[name] + "; ");
  11323. }
  11324. }
  11325. utils.cssRule(
  11326. cssRuleId,
  11327. styles.length ? "body{" + styles.join("") + "}" : "",
  11328. me.document
  11329. );
  11330. } else {
  11331. utils.cssRule(cssRuleId, "", me.document);
  11332. }
  11333. }
  11334. //重写editor.hasContent方法
  11335. var orgFn = me.hasContents;
  11336. me.hasContents = function() {
  11337. if (me.queryCommandValue("background")) {
  11338. return true;
  11339. }
  11340. return orgFn.apply(me, arguments);
  11341. };
  11342. return {
  11343. bindEvents: {
  11344. getAllHtml: function(type, headHtml) {
  11345. var body = this.body,
  11346. su = domUtils.getComputedStyle(body, "background-image"),
  11347. url = "";
  11348. if (su.indexOf(me.options.imagePath) > 0) {
  11349. url = su
  11350. .substring(su.indexOf(me.options.imagePath), su.length - 1)
  11351. .replace(/"|\(|\)/gi, "");
  11352. } else {
  11353. url = su != "none" ? su.replace(/url\("?|"?\)/gi, "") : "";
  11354. }
  11355. var html = '<style type="text/css">body{';
  11356. var bgObj = {
  11357. "background-color":
  11358. domUtils.getComputedStyle(body, "background-color") || "#ffffff",
  11359. "background-image": url ? "url(" + url + ")" : "",
  11360. "background-repeat":
  11361. domUtils.getComputedStyle(body, "background-repeat") || "",
  11362. "background-position": browser.ie
  11363. ? domUtils.getComputedStyle(body, "background-position-x") +
  11364. " " +
  11365. domUtils.getComputedStyle(body, "background-position-y")
  11366. : domUtils.getComputedStyle(body, "background-position"),
  11367. height: domUtils.getComputedStyle(body, "height")
  11368. };
  11369. for (var name in bgObj) {
  11370. if (bgObj.hasOwnProperty(name)) {
  11371. html += name + ":" + bgObj[name] + "; ";
  11372. }
  11373. }
  11374. html += "}</style> ";
  11375. headHtml.push(html);
  11376. },
  11377. aftersetcontent: function() {
  11378. if (isSetColored == false) setBackground();
  11379. }
  11380. },
  11381. inputRule: function(root) {
  11382. isSetColored = false;
  11383. utils.each(root.getNodesByTagName("p"), function(p) {
  11384. var styles = p.getAttr("data-background");
  11385. if (styles) {
  11386. isSetColored = true;
  11387. setBackground(stringToObj(styles));
  11388. p.parentNode.removeChild(p);
  11389. }
  11390. });
  11391. },
  11392. outputRule: function(root) {
  11393. var me = this,
  11394. styles = (utils.cssRule(cssRuleId, me.document) || "")
  11395. .replace(/[\n\r]+/g, "")
  11396. .match(reg);
  11397. if (styles) {
  11398. root.appendChild(
  11399. UE.uNode.createElement(
  11400. '<p style="display:none;" data-background="' +
  11401. utils.trim(styles[1].replace(/"/g, "").replace(/[\s]+/g, " ")) +
  11402. '"><br/></p>'
  11403. )
  11404. );
  11405. }
  11406. },
  11407. commands: {
  11408. background: {
  11409. execCommand: function(cmd, obj) {
  11410. setBackground(obj);
  11411. },
  11412. queryCommandValue: function() {
  11413. var me = this,
  11414. styles = (utils.cssRule(cssRuleId, me.document) || "")
  11415. .replace(/[\n\r]+/g, "")
  11416. .match(reg);
  11417. return styles ? stringToObj(styles[1]) : null;
  11418. },
  11419. notNeedUndo: true
  11420. }
  11421. }
  11422. };
  11423. });
  11424. // plugins/image.js
  11425. /**
  11426. * 图片插入、排版插件
  11427. * @file
  11428. * @since 1.2.6.1
  11429. */
  11430. /**
  11431. * 图片对齐方式
  11432. * @command imagefloat
  11433. * @method execCommand
  11434. * @remind 值center为独占一行居中
  11435. * @param { String } cmd 命令字符串
  11436. * @param { String } align 对齐方式,可传left、right、none、center
  11437. * @remaind center表示图片独占一行
  11438. * @example
  11439. * ```javascript
  11440. * editor.execCommand( 'imagefloat', 'center' );
  11441. * ```
  11442. */
  11443. /**
  11444. * 如果选区所在位置是图片区域
  11445. * @command imagefloat
  11446. * @method queryCommandValue
  11447. * @param { String } cmd 命令字符串
  11448. * @return { String } 返回图片对齐方式
  11449. * @example
  11450. * ```javascript
  11451. * editor.queryCommandValue( 'imagefloat' );
  11452. * ```
  11453. */
  11454. UE.commands["imagefloat"] = {
  11455. execCommand: function(cmd, align) {
  11456. var me = this,
  11457. range = me.selection.getRange();
  11458. if (!range.collapsed) {
  11459. var img = range.getClosedNode();
  11460. if (img && img.tagName == "IMG") {
  11461. switch (align) {
  11462. case "left":
  11463. case "right":
  11464. case "none":
  11465. var pN = img.parentNode,
  11466. tmpNode,
  11467. pre,
  11468. next;
  11469. while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
  11470. pN = pN.parentNode;
  11471. }
  11472. tmpNode = pN;
  11473. if (
  11474. tmpNode.tagName == "P" &&
  11475. domUtils.getStyle(tmpNode, "text-align") == "center"
  11476. ) {
  11477. if (
  11478. !domUtils.isBody(tmpNode) &&
  11479. domUtils.getChildCount(tmpNode, function(node) {
  11480. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11481. }) == 1
  11482. ) {
  11483. pre = tmpNode.previousSibling;
  11484. next = tmpNode.nextSibling;
  11485. if (
  11486. pre &&
  11487. next &&
  11488. pre.nodeType == 1 &&
  11489. next.nodeType == 1 &&
  11490. pre.tagName == next.tagName &&
  11491. domUtils.isBlockElm(pre)
  11492. ) {
  11493. pre.appendChild(tmpNode.firstChild);
  11494. while (next.firstChild) {
  11495. pre.appendChild(next.firstChild);
  11496. }
  11497. domUtils.remove(tmpNode);
  11498. domUtils.remove(next);
  11499. } else {
  11500. domUtils.setStyle(tmpNode, "text-align", "");
  11501. }
  11502. }
  11503. range.selectNode(img).select();
  11504. }
  11505. domUtils.setStyle(img, "float", align == "none" ? "" : align);
  11506. if (align == "none") {
  11507. domUtils.removeAttributes(img, "align");
  11508. }
  11509. break;
  11510. case "center":
  11511. if (me.queryCommandValue("imagefloat") != "center") {
  11512. var pN = img.parentNode;
  11513. domUtils.setStyle(img, "float", "");
  11514. domUtils.removeAttributes(img, "align");
  11515. tmpNode = img;
  11516. while (
  11517. pN &&
  11518. domUtils.getChildCount(pN, function(node) {
  11519. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  11520. }) == 1 &&
  11521. (dtd.$inline[pN.tagName] || pN.tagName == "A")
  11522. ) {
  11523. tmpNode = pN;
  11524. pN = pN.parentNode;
  11525. }
  11526. range.setStartBefore(tmpNode).setCursor(false);
  11527. pN = me.document.createElement("div");
  11528. pN.appendChild(tmpNode);
  11529. domUtils.setStyle(tmpNode, "float", "");
  11530. me.execCommand(
  11531. "insertHtml",
  11532. '<p class="_img_parent_tmp" style="text-align:center">' +
  11533. pN.innerHTML +
  11534. "</p>"
  11535. );
  11536. tmpNode = me.document.getElementsByClassName("_img_parent_tmp")[0];
  11537. tmpNode.removeAttribute("class");
  11538. tmpNode = tmpNode.firstChild;
  11539. range.selectNode(tmpNode).select();
  11540. //去掉后边多余的元素
  11541. next = tmpNode.parentNode.nextSibling;
  11542. if (next && domUtils.isEmptyNode(next)) {
  11543. domUtils.remove(next);
  11544. }
  11545. }
  11546. break;
  11547. }
  11548. }
  11549. }
  11550. },
  11551. queryCommandValue: function() {
  11552. var range = this.selection.getRange(),
  11553. startNode,
  11554. floatStyle;
  11555. if (range.collapsed) {
  11556. return "none";
  11557. }
  11558. startNode = range.getClosedNode();
  11559. if (startNode && startNode.nodeType == 1 && startNode.tagName == "IMG") {
  11560. floatStyle =
  11561. domUtils.getComputedStyle(startNode, "float") ||
  11562. startNode.getAttribute("align");
  11563. if (floatStyle == "none") {
  11564. floatStyle = domUtils.getComputedStyle(
  11565. startNode.parentNode,
  11566. "text-align"
  11567. ) == "center"
  11568. ? "center"
  11569. : floatStyle;
  11570. }
  11571. return {
  11572. left: 1,
  11573. right: 1,
  11574. center: 1
  11575. }[floatStyle]
  11576. ? floatStyle
  11577. : "none";
  11578. }
  11579. return "none";
  11580. },
  11581. queryCommandState: function() {
  11582. var range = this.selection.getRange(),
  11583. startNode;
  11584. if (range.collapsed) return -1;
  11585. startNode = range.getClosedNode();
  11586. if (startNode && startNode.nodeType == 1 && startNode.tagName == "IMG") {
  11587. return 0;
  11588. }
  11589. return -1;
  11590. }
  11591. };
  11592. /**
  11593. * 插入图片
  11594. * @command insertimage
  11595. * @method execCommand
  11596. * @param { String } cmd 命令字符串
  11597. * @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片
  11598. * @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片,
  11599. * 此时数组的每一个元素都是一个Object类型的图片属性集合。
  11600. * @example
  11601. * ```javascript
  11602. * editor.execCommand( 'insertimage', {
  11603. * src:'a/b/c.jpg',
  11604. * width:'100',
  11605. * height:'100'
  11606. * } );
  11607. * ```
  11608. * @example
  11609. * ```javascript
  11610. * editor.execCommand( 'insertimage', [{
  11611. * src:'a/b/c.jpg',
  11612. * width:'100',
  11613. * height:'100'
  11614. * },{
  11615. * src:'a/b/d.jpg',
  11616. * width:'100',
  11617. * height:'100'
  11618. * }] );
  11619. * ```
  11620. */
  11621. UE.commands["insertimage"] = {
  11622. execCommand: function(cmd, opt) {
  11623. opt = utils.isArray(opt) ? opt : [opt];
  11624. if (!opt.length) {
  11625. return;
  11626. }
  11627. var me = this,
  11628. range = me.selection.getRange(),
  11629. img = range.getClosedNode();
  11630. if (me.fireEvent("beforeinsertimage", opt) === true) {
  11631. return;
  11632. }
  11633. if (
  11634. img &&
  11635. /img/i.test(img.tagName) &&
  11636. (img.className != "edui-faked-video" ||
  11637. img.className.indexOf("edui-upload-video") != -1) &&
  11638. !img.getAttribute("word_img")
  11639. ) {
  11640. var first = opt.shift();
  11641. var floatStyle = first["floatStyle"];
  11642. delete first["floatStyle"];
  11643. //// img.style.border = (first.border||0) +"px solid #000";
  11644. //// img.style.margin = (first.margin||0) +"px";
  11645. // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
  11646. domUtils.setAttributes(img, first);
  11647. me.execCommand("imagefloat", floatStyle);
  11648. if (opt.length > 0) {
  11649. range.setStartAfter(img).setCursor(false, true);
  11650. me.execCommand("insertimage", opt);
  11651. }
  11652. } else {
  11653. var html = [],
  11654. str = "",
  11655. ci;
  11656. ci = opt[0];
  11657. if (opt.length == 1) {
  11658. str =
  11659. '<img src="' +
  11660. ci.src +
  11661. '" ' +
  11662. (ci._src ? ' _src="' + ci._src + '" ' : "") +
  11663. (ci.width ? 'width="' + ci.width + '" ' : "") +
  11664. (ci.height ? ' height="' + ci.height + '" ' : "") +
  11665. (ci["floatStyle"] == "left" || ci["floatStyle"] == "right"
  11666. ? ' style="float:' + ci["floatStyle"] + ';"'
  11667. : "") +
  11668. (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : "") +
  11669. (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : "") +
  11670. (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : "") +
  11671. (ci.hspace && ci.hspace != "0"
  11672. ? ' hspace = "' + ci.hspace + '"'
  11673. : "") +
  11674. (ci.vspace && ci.vspace != "0"
  11675. ? ' vspace = "' + ci.vspace + '"'
  11676. : "") +
  11677. "/>";
  11678. if (ci["floatStyle"] == "center") {
  11679. str = '<p style="text-align: center">' + str + "</p>";
  11680. }
  11681. html.push(str);
  11682. } else {
  11683. for (var i = 0; (ci = opt[i++]); ) {
  11684. str =
  11685. "<p " +
  11686. (ci["floatStyle"] == "center"
  11687. ? 'style="text-align: center" '
  11688. : "") +
  11689. '><img src="' +
  11690. ci.src +
  11691. '" ' +
  11692. (ci.width ? 'width="' + ci.width + '" ' : "") +
  11693. (ci._src ? ' _src="' + ci._src + '" ' : "") +
  11694. (ci.height ? ' height="' + ci.height + '" ' : "") +
  11695. ' style="' +
  11696. (ci["floatStyle"] && ci["floatStyle"] != "center"
  11697. ? "float:" + ci["floatStyle"] + ";"
  11698. : "") +
  11699. (ci.border || "") +
  11700. '" ' +
  11701. (ci.title ? ' title="' + ci.title + '"' : "") +
  11702. " /></p>";
  11703. html.push(str);
  11704. }
  11705. }
  11706. me.execCommand("insertHtml", html.join(""));
  11707. }
  11708. me.fireEvent("afterinsertimage", opt);
  11709. }
  11710. };
  11711. // plugins/justify.js
  11712. /**
  11713. * 段落格式
  11714. * @file
  11715. * @since 1.2.6.1
  11716. */
  11717. /**
  11718. * 段落对齐方式
  11719. * @command justify
  11720. * @method execCommand
  11721. * @param { String } cmd 命令字符串
  11722. * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐
  11723. * @example
  11724. * ```javascript
  11725. * editor.execCommand( 'justify', 'center' );
  11726. * ```
  11727. */
  11728. /**
  11729. * 如果选区所在位置是段落区域,返回当前段落对齐方式
  11730. * @command justify
  11731. * @method queryCommandValue
  11732. * @param { String } cmd 命令字符串
  11733. * @return { String } 返回段落对齐方式
  11734. * @example
  11735. * ```javascript
  11736. * editor.queryCommandValue( 'justify' );
  11737. * ```
  11738. */
  11739. UE.plugins["justify"] = function() {
  11740. var me = this,
  11741. block = domUtils.isBlockElm,
  11742. defaultValue = {
  11743. left: 1,
  11744. right: 1,
  11745. center: 1,
  11746. justify: 1
  11747. },
  11748. doJustify = function(range, style) {
  11749. var bookmark = range.createBookmark(),
  11750. filterFn = function(node) {
  11751. return node.nodeType == 1
  11752. ? node.tagName.toLowerCase() != "br" &&
  11753. !domUtils.isBookmarkNode(node)
  11754. : !domUtils.isWhitespace(node);
  11755. };
  11756. range.enlarge(true);
  11757. var bookmark2 = range.createBookmark(),
  11758. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  11759. tmpRange = range.cloneRange(),
  11760. tmpNode;
  11761. while (
  11762. current &&
  11763. !(
  11764. domUtils.getPosition(current, bookmark2.end) &
  11765. domUtils.POSITION_FOLLOWING
  11766. )
  11767. ) {
  11768. if (current.nodeType == 3 || !block(current)) {
  11769. tmpRange.setStartBefore(current);
  11770. while (current && current !== bookmark2.end && !block(current)) {
  11771. tmpNode = current;
  11772. current = domUtils.getNextDomNode(current, false, null, function(
  11773. node
  11774. ) {
  11775. return !block(node);
  11776. });
  11777. }
  11778. tmpRange.setEndAfter(tmpNode);
  11779. var common = tmpRange.getCommonAncestor();
  11780. if (!domUtils.isBody(common) && block(common)) {
  11781. domUtils.setStyles(
  11782. common,
  11783. utils.isString(style) ? { "text-align": style } : style
  11784. );
  11785. current = common;
  11786. } else {
  11787. var p = range.document.createElement("p");
  11788. domUtils.setStyles(
  11789. p,
  11790. utils.isString(style) ? { "text-align": style } : style
  11791. );
  11792. var frag = tmpRange.extractContents();
  11793. p.appendChild(frag);
  11794. tmpRange.insertNode(p);
  11795. current = p;
  11796. }
  11797. current = domUtils.getNextDomNode(current, false, filterFn);
  11798. } else {
  11799. current = domUtils.getNextDomNode(current, true, filterFn);
  11800. }
  11801. }
  11802. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  11803. };
  11804. UE.commands["justify"] = {
  11805. execCommand: function(cmdName, align) {
  11806. var range = this.selection.getRange(),
  11807. txt;
  11808. //闭合时单独处理
  11809. if (range.collapsed) {
  11810. txt = this.document.createTextNode("p");
  11811. range.insertNode(txt);
  11812. }
  11813. doJustify(range, align);
  11814. if (txt) {
  11815. range.setStartBefore(txt).collapse(true);
  11816. domUtils.remove(txt);
  11817. }
  11818. range.select();
  11819. return true;
  11820. },
  11821. queryCommandValue: function() {
  11822. var startNode = this.selection.getStart(),
  11823. value = domUtils.getComputedStyle(startNode, "text-align");
  11824. return defaultValue[value] ? value : "left";
  11825. },
  11826. queryCommandState: function() {
  11827. var start = this.selection.getStart(),
  11828. cell =
  11829. start &&
  11830. domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  11831. return cell ? -1 : 0;
  11832. }
  11833. };
  11834. };
  11835. // plugins/font.js
  11836. /**
  11837. * 字体颜色,背景色,字号,字体,下划线,删除线
  11838. * @file
  11839. * @since 1.2.6.1
  11840. */
  11841. /**
  11842. * 字体颜色
  11843. * @command forecolor
  11844. * @method execCommand
  11845. * @param { String } cmd 命令字符串
  11846. * @param { String } value 色值(必须十六进制)
  11847. * @example
  11848. * ```javascript
  11849. * editor.execCommand( 'forecolor', '#000' );
  11850. * ```
  11851. */
  11852. /**
  11853. * 返回选区字体颜色
  11854. * @command forecolor
  11855. * @method queryCommandValue
  11856. * @param { String } cmd 命令字符串
  11857. * @return { String } 返回字体颜色
  11858. * @example
  11859. * ```javascript
  11860. * editor.queryCommandValue( 'forecolor' );
  11861. * ```
  11862. */
  11863. /**
  11864. * 字体背景颜色
  11865. * @command backcolor
  11866. * @method execCommand
  11867. * @param { String } cmd 命令字符串
  11868. * @param { String } value 色值(必须十六进制)
  11869. * @example
  11870. * ```javascript
  11871. * editor.execCommand( 'backcolor', '#000' );
  11872. * ```
  11873. */
  11874. /**
  11875. * 返回选区字体颜色
  11876. * @command backcolor
  11877. * @method queryCommandValue
  11878. * @param { String } cmd 命令字符串
  11879. * @return { String } 返回字体背景颜色
  11880. * @example
  11881. * ```javascript
  11882. * editor.queryCommandValue( 'backcolor' );
  11883. * ```
  11884. */
  11885. /**
  11886. * 字体大小
  11887. * @command fontsize
  11888. * @method execCommand
  11889. * @param { String } cmd 命令字符串
  11890. * @param { String } value 字体大小
  11891. * @example
  11892. * ```javascript
  11893. * editor.execCommand( 'fontsize', '14px' );
  11894. * ```
  11895. */
  11896. /**
  11897. * 返回选区字体大小
  11898. * @command fontsize
  11899. * @method queryCommandValue
  11900. * @param { String } cmd 命令字符串
  11901. * @return { String } 返回字体大小
  11902. * @example
  11903. * ```javascript
  11904. * editor.queryCommandValue( 'fontsize' );
  11905. * ```
  11906. */
  11907. /**
  11908. * 字体样式
  11909. * @command fontfamily
  11910. * @method execCommand
  11911. * @param { String } cmd 命令字符串
  11912. * @param { String } value 字体样式
  11913. * @example
  11914. * ```javascript
  11915. * editor.execCommand( 'fontfamily', '微软雅黑' );
  11916. * ```
  11917. */
  11918. /**
  11919. * 返回选区字体样式
  11920. * @command fontfamily
  11921. * @method queryCommandValue
  11922. * @param { String } cmd 命令字符串
  11923. * @return { String } 返回字体样式
  11924. * @example
  11925. * ```javascript
  11926. * editor.queryCommandValue( 'fontfamily' );
  11927. * ```
  11928. */
  11929. /**
  11930. * 字体下划线,与删除线互斥
  11931. * @command underline
  11932. * @method execCommand
  11933. * @param { String } cmd 命令字符串
  11934. * @example
  11935. * ```javascript
  11936. * editor.execCommand( 'underline' );
  11937. * ```
  11938. */
  11939. /**
  11940. * 字体删除线,与下划线互斥
  11941. * @command strikethrough
  11942. * @method execCommand
  11943. * @param { String } cmd 命令字符串
  11944. * @example
  11945. * ```javascript
  11946. * editor.execCommand( 'strikethrough' );
  11947. * ```
  11948. */
  11949. /**
  11950. * 字体边框
  11951. * @command fontborder
  11952. * @method execCommand
  11953. * @param { String } cmd 命令字符串
  11954. * @example
  11955. * ```javascript
  11956. * editor.execCommand( 'fontborder' );
  11957. * ```
  11958. */
  11959. UE.plugins["font"] = function() {
  11960. var me = this,
  11961. fonts = {
  11962. forecolor: "color",
  11963. backcolor: "background-color",
  11964. fontsize: "font-size",
  11965. fontfamily: "font-family",
  11966. underline: "text-decoration",
  11967. strikethrough: "text-decoration",
  11968. fontborder: "border"
  11969. },
  11970. needCmd = { underline: 1, strikethrough: 1, fontborder: 1 },
  11971. needSetChild = {
  11972. forecolor: "color",
  11973. backcolor: "background-color",
  11974. fontsize: "font-size",
  11975. fontfamily: "font-family"
  11976. };
  11977. me.setOpt({
  11978. fontfamily: [
  11979. { name: "songti", val: "宋体,SimSun" },
  11980. { name: "yahei", val: "微软雅黑,Microsoft YaHei" },
  11981. { name: "kaiti", val: "楷体,楷体_GB2312, SimKai" },
  11982. { name: "heiti", val: "黑体, SimHei" },
  11983. { name: "lishu", val: "隶书, SimLi" },
  11984. { name: "andaleMono", val: "andale mono" },
  11985. { name: "arial", val: "arial, helvetica,sans-serif" },
  11986. { name: "arialBlack", val: "arial black,avant garde" },
  11987. { name: "comicSansMs", val: "comic sans ms" },
  11988. { name: "impact", val: "impact,chicago" },
  11989. { name: "timesNewRoman", val: "times new roman" }
  11990. ],
  11991. fontsize: [10, 11, 12, 14, 16, 18, 20, 24, 36]
  11992. });
  11993. function mergeWithParent(node) {
  11994. var parent;
  11995. while ((parent = node.parentNode)) {
  11996. if (
  11997. parent.tagName == "SPAN" &&
  11998. domUtils.getChildCount(parent, function(child) {
  11999. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child);
  12000. }) == 1
  12001. ) {
  12002. parent.style.cssText += node.style.cssText;
  12003. domUtils.remove(node, true);
  12004. node = parent;
  12005. } else {
  12006. break;
  12007. }
  12008. }
  12009. }
  12010. function mergeChild(rng, cmdName, value) {
  12011. if (needSetChild[cmdName]) {
  12012. rng.adjustmentBoundary();
  12013. if (!rng.collapsed && rng.startContainer.nodeType == 1) {
  12014. rng.traversal(function(node){
  12015. var start;
  12016. if(domUtils.isTagNode(node,'span')){
  12017. start = node;
  12018. }else{
  12019. start = domUtils.getElementsByTagName(node,'span')[0];
  12020. }
  12021. if (start && domUtils.isTagNode(start, "span")) {
  12022. var bk = rng.createBookmark();
  12023. utils.each(domUtils.getElementsByTagName(start, "span"), function(
  12024. span
  12025. ) {
  12026. if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
  12027. if (
  12028. cmdName == "backcolor" &&
  12029. domUtils
  12030. .getComputedStyle(span, "background-color")
  12031. .toLowerCase() === value
  12032. ) {
  12033. return;
  12034. }
  12035. domUtils.removeStyle(span, needSetChild[cmdName]);
  12036. if (span.style.cssText.replace(/^\s+$/, "").length == 0) {
  12037. domUtils.remove(span, true);
  12038. }
  12039. });
  12040. rng.moveToBookmark(bk);
  12041. }
  12042. });
  12043. }
  12044. }
  12045. }
  12046. function mergesibling(rng, cmdName, value) {
  12047. var collapsed = rng.collapsed,
  12048. bk = rng.createBookmark(),
  12049. common;
  12050. if (collapsed) {
  12051. common = bk.start.parentNode;
  12052. while (dtd.$inline[common.tagName]) {
  12053. common = common.parentNode;
  12054. }
  12055. } else {
  12056. common = domUtils.getCommonAncestor(bk.start, bk.end);
  12057. }
  12058. utils.each(domUtils.getElementsByTagName(common, "span"), function(span) {
  12059. if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
  12060. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  12061. if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
  12062. domUtils.remove(span, true);
  12063. } else {
  12064. domUtils.removeStyle(span, "border");
  12065. }
  12066. return;
  12067. }
  12068. if (
  12069. /border/i.test(span.style.cssText) &&
  12070. span.parentNode.tagName == "SPAN" &&
  12071. /border/i.test(span.parentNode.style.cssText)
  12072. ) {
  12073. span.style.cssText = span.style.cssText.replace(
  12074. /border[^:]*:[^;]+;?/gi,
  12075. ""
  12076. );
  12077. }
  12078. if (!(cmdName == "fontborder" && value == "none")) {
  12079. var next = span.nextSibling;
  12080. while (next && next.nodeType == 1 && next.tagName == "SPAN") {
  12081. if (domUtils.isBookmarkNode(next) && cmdName == "fontborder") {
  12082. span.appendChild(next);
  12083. next = span.nextSibling;
  12084. continue;
  12085. }
  12086. if (next.style.cssText == span.style.cssText) {
  12087. domUtils.moveChild(next, span);
  12088. domUtils.remove(next);
  12089. }
  12090. if (span.nextSibling === next) break;
  12091. next = span.nextSibling;
  12092. }
  12093. }
  12094. mergeWithParent(span);
  12095. if (browser.ie && browser.version > 8) {
  12096. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  12097. var parent = domUtils.findParent(span, function(n) {
  12098. return (
  12099. n.tagName == "SPAN" && /background-color/.test(n.style.cssText)
  12100. );
  12101. });
  12102. if (parent && !/background-color/.test(span.style.cssText)) {
  12103. span.style.backgroundColor = parent.style.backgroundColor;
  12104. }
  12105. }
  12106. });
  12107. rng.moveToBookmark(bk);
  12108. mergeChild(rng, cmdName, value);
  12109. }
  12110. me.addInputRule(function(root) {
  12111. utils.each(root.getNodesByTagName("u s del font strike"), function(node) {
  12112. if (node.tagName == "font") {
  12113. var cssStyle = [];
  12114. for (var p in node.attrs) {
  12115. switch (p) {
  12116. case "size":
  12117. cssStyle.push(
  12118. "font-size:" +
  12119. ({
  12120. "1": "10",
  12121. "2": "12",
  12122. "3": "16",
  12123. "4": "18",
  12124. "5": "24",
  12125. "6": "32",
  12126. "7": "48"
  12127. }[node.attrs[p]] || node.attrs[p]) +
  12128. "px"
  12129. );
  12130. break;
  12131. case "color":
  12132. cssStyle.push("color:" + node.attrs[p]);
  12133. break;
  12134. case "face":
  12135. cssStyle.push("font-family:" + node.attrs[p]);
  12136. break;
  12137. case "style":
  12138. cssStyle.push(node.attrs[p]);
  12139. }
  12140. }
  12141. node.attrs = {
  12142. style: cssStyle.join(";")
  12143. };
  12144. } else {
  12145. var val = node.tagName == "u" ? "underline" : "line-through";
  12146. node.attrs = {
  12147. style: (node.getAttr("style") || "") + "text-decoration:" + val + ";"
  12148. };
  12149. }
  12150. node.tagName = "span";
  12151. });
  12152. // utils.each(root.getNodesByTagName('span'), function (node) {
  12153. // var val;
  12154. // if(val = node.getAttr('class')){
  12155. // if(/fontstrikethrough/.test(val)){
  12156. // node.setStyle('text-decoration','line-through');
  12157. // if(node.attrs['class']){
  12158. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  12159. // }else{
  12160. // node.setAttr('class')
  12161. // }
  12162. // }
  12163. // if(/fontborder/.test(val)){
  12164. // node.setStyle('border','1px solid #000');
  12165. // if(node.attrs['class']){
  12166. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  12167. // }else{
  12168. // node.setAttr('class')
  12169. // }
  12170. // }
  12171. // }
  12172. // });
  12173. });
  12174. // me.addOutputRule(function(root){
  12175. // utils.each(root.getNodesByTagName('span'), function (node) {
  12176. // var val;
  12177. // if(val = node.getStyle('text-decoration')){
  12178. // if(/line-through/.test(val)){
  12179. // if(node.attrs['class']){
  12180. // node.attrs['class'] += ' fontstrikethrough';
  12181. // }else{
  12182. // node.setAttr('class','fontstrikethrough')
  12183. // }
  12184. // }
  12185. //
  12186. // node.setStyle('text-decoration')
  12187. // }
  12188. // if(val = node.getStyle('border')){
  12189. // if(/1px/.test(val) && /solid/.test(val)){
  12190. // if(node.attrs['class']){
  12191. // node.attrs['class'] += ' fontborder';
  12192. //
  12193. // }else{
  12194. // node.setAttr('class','fontborder')
  12195. // }
  12196. // }
  12197. // node.setStyle('border')
  12198. //
  12199. // }
  12200. // });
  12201. // });
  12202. for (var p in fonts) {
  12203. (function(cmd, style) {
  12204. UE.commands[cmd] = {
  12205. execCommand: function(cmdName, value) {
  12206. value =
  12207. value ||
  12208. (this.queryCommandState(cmdName)
  12209. ? "none"
  12210. : cmdName == "underline"
  12211. ? "underline"
  12212. : cmdName == "fontborder" ? "1px solid #000" : "line-through");
  12213. var me = this,
  12214. range = this.selection.getRange(),
  12215. text;
  12216. if (value == "default") {
  12217. if (range.collapsed) {
  12218. text = me.document.createTextNode("font");
  12219. range.insertNode(text).select();
  12220. }
  12221. me.execCommand("removeFormat", "span,a", style);
  12222. if (text) {
  12223. range.setStartBefore(text).collapse(true);
  12224. domUtils.remove(text);
  12225. }
  12226. mergesibling(range, cmdName, value);
  12227. range.select();
  12228. } else {
  12229. if (!range.collapsed) {
  12230. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  12231. me.execCommand("removeFormat", "span,a", style);
  12232. }
  12233. range = me.selection.getRange();
  12234. range.applyInlineStyle("span", { style: style + ":" + value });
  12235. mergesibling(range, cmdName, value);
  12236. range.select();
  12237. } else {
  12238. var span = domUtils.findParentByTagName(
  12239. range.startContainer,
  12240. "span",
  12241. true
  12242. );
  12243. text = me.document.createTextNode("font");
  12244. if (
  12245. span &&
  12246. !span.children.length &&
  12247. !span[browser.ie ? "innerText" : "textContent"].replace(
  12248. fillCharReg,
  12249. ""
  12250. ).length
  12251. ) {
  12252. //for ie hack when enter
  12253. range.insertNode(text);
  12254. if (needCmd[cmd]) {
  12255. range.selectNode(text).select();
  12256. me.execCommand("removeFormat", "span,a", style, null);
  12257. span = domUtils.findParentByTagName(text, "span", true);
  12258. range.setStartBefore(text);
  12259. }
  12260. span && (span.style.cssText += ";" + style + ":" + value);
  12261. range.collapse(true).select();
  12262. } else {
  12263. range.insertNode(text);
  12264. range.selectNode(text).select();
  12265. span = range.document.createElement("span");
  12266. if (needCmd[cmd]) {
  12267. //a标签内的不处理跳过
  12268. if (domUtils.findParentByTagName(text, "a", true)) {
  12269. range.setStartBefore(text).setCursor();
  12270. domUtils.remove(text);
  12271. return;
  12272. }
  12273. me.execCommand("removeFormat", "span,a", style);
  12274. }
  12275. span.style.cssText = style + ":" + value;
  12276. text.parentNode.insertBefore(span, text);
  12277. //修复,span套span 但样式不继承的问题
  12278. if (!browser.ie || (browser.ie && browser.version == 9)) {
  12279. var spanParent = span.parentNode;
  12280. while (!domUtils.isBlockElm(spanParent)) {
  12281. if (spanParent.tagName == "SPAN") {
  12282. //opera合并style不会加入";"
  12283. span.style.cssText =
  12284. spanParent.style.cssText + ";" + span.style.cssText;
  12285. }
  12286. spanParent = spanParent.parentNode;
  12287. }
  12288. }
  12289. if (opera) {
  12290. setTimeout(function() {
  12291. range.setStart(span, 0).collapse(true);
  12292. mergesibling(range, cmdName, value);
  12293. range.select();
  12294. });
  12295. } else {
  12296. range.setStart(span, 0).collapse(true);
  12297. mergesibling(range, cmdName, value);
  12298. range.select();
  12299. }
  12300. //trace:981
  12301. //domUtils.mergeToParent(span)
  12302. }
  12303. domUtils.remove(text);
  12304. }
  12305. }
  12306. return true;
  12307. },
  12308. queryCommandValue: function(cmdName) {
  12309. var startNode = this.selection.getStart();
  12310. //trace:946
  12311. if (cmdName == "underline" || cmdName == "strikethrough") {
  12312. var tmpNode = startNode,
  12313. value;
  12314. while (
  12315. tmpNode &&
  12316. !domUtils.isBlockElm(tmpNode) &&
  12317. !domUtils.isBody(tmpNode)
  12318. ) {
  12319. if (tmpNode.nodeType == 1) {
  12320. value = domUtils.getComputedStyle(tmpNode, style);
  12321. if (value != "none") {
  12322. return value;
  12323. }
  12324. }
  12325. tmpNode = tmpNode.parentNode;
  12326. }
  12327. return "none";
  12328. }
  12329. if (cmdName == "fontborder") {
  12330. var tmp = startNode,
  12331. val;
  12332. while (tmp && dtd.$inline[tmp.tagName]) {
  12333. if ((val = domUtils.getComputedStyle(tmp, "border"))) {
  12334. if (/1px/.test(val) && /solid/.test(val)) {
  12335. return val;
  12336. }
  12337. }
  12338. tmp = tmp.parentNode;
  12339. }
  12340. return "";
  12341. }
  12342. if (cmdName == "FontSize") {
  12343. var styleVal = domUtils.getComputedStyle(startNode, style),
  12344. tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);
  12345. if (tmp) {
  12346. return Math.floor(tmp[1]) + tmp[2];
  12347. }
  12348. return styleVal;
  12349. }
  12350. return domUtils.getComputedStyle(startNode, style);
  12351. },
  12352. queryCommandState: function(cmdName) {
  12353. if (!needCmd[cmdName]) return 0;
  12354. var val = this.queryCommandValue(cmdName);
  12355. if (cmdName == "fontborder") {
  12356. return /1px/.test(val) && /solid/.test(val);
  12357. } else {
  12358. return cmdName == "underline"
  12359. ? /underline/.test(val)
  12360. : /line\-through/.test(val);
  12361. }
  12362. }
  12363. };
  12364. })(p, fonts[p]);
  12365. }
  12366. };
  12367. // plugins/link.js
  12368. /**
  12369. * 超链接
  12370. * @file
  12371. * @since 1.2.6.1
  12372. */
  12373. /**
  12374. * 插入超链接
  12375. * @command link
  12376. * @method execCommand
  12377. * @param { String } cmd 命令字符串
  12378. * @param { Object } options 设置自定义属性,例如:url、title、target
  12379. * @example
  12380. * ```javascript
  12381. * editor.execCommand( 'link', '{
  12382. * url:'neditor.baidu.com',
  12383. * title:'neditor',
  12384. * target:'_blank'
  12385. * }' );
  12386. * ```
  12387. */
  12388. /**
  12389. * 返回当前选中的第一个超链接节点
  12390. * @command link
  12391. * @method queryCommandValue
  12392. * @param { String } cmd 命令字符串
  12393. * @return { Element } 超链接节点
  12394. * @example
  12395. * ```javascript
  12396. * editor.queryCommandValue( 'link' );
  12397. * ```
  12398. */
  12399. /**
  12400. * 取消超链接
  12401. * @command unlink
  12402. * @method execCommand
  12403. * @param { String } cmd 命令字符串
  12404. * @example
  12405. * ```javascript
  12406. * editor.execCommand( 'unlink');
  12407. * ```
  12408. */
  12409. UE.plugins["link"] = function() {
  12410. function optimize(range) {
  12411. var start = range.startContainer,
  12412. end = range.endContainer;
  12413. if ((start = domUtils.findParentByTagName(start, "a", true))) {
  12414. range.setStartBefore(start);
  12415. }
  12416. if ((end = domUtils.findParentByTagName(end, "a", true))) {
  12417. range.setEndAfter(end);
  12418. }
  12419. }
  12420. UE.commands["unlink"] = {
  12421. execCommand: function() {
  12422. var range = this.selection.getRange(),
  12423. bookmark;
  12424. if (
  12425. range.collapsed &&
  12426. !domUtils.findParentByTagName(range.startContainer, "a", true)
  12427. ) {
  12428. return;
  12429. }
  12430. bookmark = range.createBookmark();
  12431. optimize(range);
  12432. range.removeInlineStyle("a").moveToBookmark(bookmark).select();
  12433. },
  12434. queryCommandState: function() {
  12435. return !this.highlight && this.queryCommandValue("link") ? 0 : -1;
  12436. }
  12437. };
  12438. function doLink(range, opt, me) {
  12439. var rngClone = range.cloneRange(),
  12440. link = me.queryCommandValue("link");
  12441. optimize((range = range.adjustmentBoundary()));
  12442. var start = range.startContainer;
  12443. if (start.nodeType == 1 && link) {
  12444. start = start.childNodes[range.startOffset];
  12445. if (
  12446. start &&
  12447. start.nodeType == 1 &&
  12448. start.tagName == "A" &&
  12449. /^(?:https?|ftp|file)\s*:\s*\/\//.test(
  12450. start[browser.ie ? "innerText" : "textContent"]
  12451. )
  12452. ) {
  12453. start[browser.ie ? "innerText" : "textContent"] = utils.html(
  12454. opt.textValue || opt.href
  12455. );
  12456. }
  12457. }
  12458. if (!rngClone.collapsed || link) {
  12459. range.removeInlineStyle("a");
  12460. rngClone = range.cloneRange();
  12461. }
  12462. if (rngClone.collapsed) {
  12463. var a = range.document.createElement("a"),
  12464. text = "";
  12465. if (opt.textValue) {
  12466. text = utils.html(opt.textValue);
  12467. delete opt.textValue;
  12468. } else {
  12469. text = utils.html(opt.href);
  12470. }
  12471. domUtils.setAttributes(a, opt);
  12472. start = domUtils.findParentByTagName(rngClone.startContainer, "a", true);
  12473. if (start && domUtils.isInNodeEndBoundary(rngClone, start)) {
  12474. range.setStartAfter(start).collapse(true);
  12475. }
  12476. a[browser.ie ? "innerText" : "textContent"] = text;
  12477. range.insertNode(a).selectNode(a);
  12478. } else {
  12479. range.applyInlineStyle("a", opt);
  12480. }
  12481. }
  12482. UE.commands["link"] = {
  12483. execCommand: function(cmdName, opt) {
  12484. var range;
  12485. opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g));
  12486. opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g));
  12487. opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g));
  12488. doLink((range = this.selection.getRange()), opt, this);
  12489. //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
  12490. range.collapse().select(true);
  12491. },
  12492. queryCommandValue: function() {
  12493. var range = this.selection.getRange(),
  12494. node;
  12495. if (range.collapsed) {
  12496. // node = this.selection.getStart();
  12497. //在ie下getstart()取值偏上了
  12498. node = range.startContainer;
  12499. node = node.nodeType == 1 ? node : node.parentNode;
  12500. if (
  12501. node &&
  12502. (node = domUtils.findParentByTagName(node, "a", true)) &&
  12503. !domUtils.isInNodeEndBoundary(range, node)
  12504. ) {
  12505. return node;
  12506. }
  12507. } else {
  12508. //trace:1111 如果是<p><a>xx</a></p> startContainer是p就会找不到a
  12509. range.shrinkBoundary();
  12510. var start = range.startContainer.nodeType == 3 ||
  12511. !range.startContainer.childNodes[range.startOffset]
  12512. ? range.startContainer
  12513. : range.startContainer.childNodes[range.startOffset],
  12514. end = range.endContainer.nodeType == 3 || range.endOffset == 0
  12515. ? range.endContainer
  12516. : range.endContainer.childNodes[range.endOffset - 1],
  12517. common = range.getCommonAncestor();
  12518. node = domUtils.findParentByTagName(common, "a", true);
  12519. if (!node && common.nodeType == 1) {
  12520. var as = common.getElementsByTagName("a"),
  12521. ps,
  12522. pe;
  12523. for (var i = 0, ci; (ci = as[i++]); ) {
  12524. (ps = domUtils.getPosition(ci, start)), (pe = domUtils.getPosition(
  12525. ci,
  12526. end
  12527. ));
  12528. if (
  12529. (ps & domUtils.POSITION_FOLLOWING ||
  12530. ps & domUtils.POSITION_CONTAINS) &&
  12531. (pe & domUtils.POSITION_PRECEDING ||
  12532. pe & domUtils.POSITION_CONTAINS)
  12533. ) {
  12534. node = ci;
  12535. break;
  12536. }
  12537. }
  12538. }
  12539. return node;
  12540. }
  12541. },
  12542. queryCommandState: function() {
  12543. //判断如果是视频的话连接不可用
  12544. //fix 853
  12545. var img = this.selection.getRange().getClosedNode(),
  12546. flag =
  12547. img &&
  12548. (img.className == "edui-faked-video" ||
  12549. img.className.indexOf("edui-upload-video") != -1);
  12550. return flag ? -1 : 0;
  12551. }
  12552. };
  12553. };
  12554. // plugins/iframe.js
  12555. ///import core
  12556. ///import plugins\inserthtml.js
  12557. ///commands 插入框架
  12558. ///commandsName InsertFrame
  12559. ///commandsTitle 插入Iframe
  12560. ///commandsDialog dialogs\insertframe
  12561. UE.plugins["insertframe"] = function() {
  12562. var me = this;
  12563. function deleteIframe() {
  12564. me._iframe && delete me._iframe;
  12565. }
  12566. me.addListener("selectionchange", function() {
  12567. deleteIframe();
  12568. });
  12569. };
  12570. // plugins/scrawl.js
  12571. ///import core
  12572. ///commands 涂鸦
  12573. ///commandsName Scrawl
  12574. ///commandsTitle 涂鸦
  12575. ///commandsDialog dialogs\scrawl
  12576. UE.commands["scrawl"] = {
  12577. queryCommandState: function() {
  12578. return browser.ie && browser.version <= 8 ? -1 : 0;
  12579. }
  12580. };
  12581. // plugins/removeformat.js
  12582. /**
  12583. * 清除格式
  12584. * @file
  12585. * @since 1.2.6.1
  12586. */
  12587. /**
  12588. * 清除文字样式
  12589. * @command removeformat
  12590. * @method execCommand
  12591. * @param { String } cmd 命令字符串
  12592. * @param {String} tags 以逗号隔开的标签。如:strong
  12593. * @param {String} style 样式如:color
  12594. * @param {String} attrs 属性如:width
  12595. * @example
  12596. * ```javascript
  12597. * editor.execCommand( 'removeformat', 'strong','color','width' );
  12598. * ```
  12599. */
  12600. UE.plugins["removeformat"] = function() {
  12601. var me = this;
  12602. me.setOpt({
  12603. removeFormatTags:
  12604. "b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var",
  12605. removeFormatAttributes: "class,style,lang,width,height,align,hspace,valign"
  12606. });
  12607. me.commands["removeformat"] = {
  12608. execCommand: function(cmdName, tags, style, attrs, notIncludeA) {
  12609. var tagReg = new RegExp(
  12610. "^(?:" +
  12611. (tags || this.options.removeFormatTags).replace(/,/g, "|") +
  12612. ")$",
  12613. "i"
  12614. ),
  12615. removeFormatAttributes = style
  12616. ? []
  12617. : (attrs || this.options.removeFormatAttributes).split(","),
  12618. range = new dom.Range(this.document),
  12619. bookmark,
  12620. node,
  12621. parent,
  12622. filter = function(node) {
  12623. return node.nodeType == 1;
  12624. };
  12625. function isRedundantSpan(node) {
  12626. if (node.nodeType == 3 || node.tagName.toLowerCase() != "span") {
  12627. return 0;
  12628. }
  12629. if (browser.ie) {
  12630. //ie 下判断实效,所以只能简单用style来判断
  12631. //return node.style.cssText == '' ? 1 : 0;
  12632. var attrs = node.attributes;
  12633. if (attrs.length) {
  12634. for (var i = 0, l = attrs.length; i < l; i++) {
  12635. if (attrs[i].specified) {
  12636. return 0;
  12637. }
  12638. }
  12639. return 1;
  12640. }
  12641. }
  12642. return !node.attributes.length;
  12643. }
  12644. function doRemove(range) {
  12645. var bookmark1 = range.createBookmark();
  12646. if (range.collapsed) {
  12647. range.enlarge(true);
  12648. }
  12649. //不能把a标签切了
  12650. if (!notIncludeA) {
  12651. var aNode = domUtils.findParentByTagName(
  12652. range.startContainer,
  12653. "a",
  12654. true
  12655. );
  12656. if (aNode) {
  12657. range.setStartBefore(aNode);
  12658. }
  12659. aNode = domUtils.findParentByTagName(range.endContainer, "a", true);
  12660. if (aNode) {
  12661. range.setEndAfter(aNode);
  12662. }
  12663. }
  12664. bookmark = range.createBookmark();
  12665. node = bookmark.start;
  12666. //切开始
  12667. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  12668. domUtils.breakParent(node, parent);
  12669. domUtils.clearEmptySibling(node);
  12670. }
  12671. if (bookmark.end) {
  12672. //切结束
  12673. node = bookmark.end;
  12674. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  12675. domUtils.breakParent(node, parent);
  12676. domUtils.clearEmptySibling(node);
  12677. }
  12678. //开始去除样式
  12679. var current = domUtils.getNextDomNode(bookmark.start, false, filter),
  12680. next;
  12681. while (current) {
  12682. if (current == bookmark.end) {
  12683. break;
  12684. }
  12685. next = domUtils.getNextDomNode(current, true, filter);
  12686. if (
  12687. !dtd.$empty[current.tagName.toLowerCase()] &&
  12688. !domUtils.isBookmarkNode(current)
  12689. ) {
  12690. if (tagReg.test(current.tagName)) {
  12691. if (style) {
  12692. domUtils.removeStyle(current, style);
  12693. if (isRedundantSpan(current) && style != "text-decoration") {
  12694. domUtils.remove(current, true);
  12695. }
  12696. } else {
  12697. domUtils.remove(current, true);
  12698. }
  12699. } else {
  12700. //trace:939 不能把list上的样式去掉
  12701. if (
  12702. !dtd.$tableContent[current.tagName] &&
  12703. !dtd.$list[current.tagName]
  12704. ) {
  12705. domUtils.removeAttributes(current, removeFormatAttributes);
  12706. if (isRedundantSpan(current)) {
  12707. domUtils.remove(current, true);
  12708. }
  12709. }
  12710. }
  12711. }
  12712. current = next;
  12713. }
  12714. }
  12715. //trace:1035
  12716. //trace:1096 不能把td上的样式去掉,比如边框
  12717. var pN = bookmark.start.parentNode;
  12718. if (
  12719. domUtils.isBlockElm(pN) &&
  12720. !dtd.$tableContent[pN.tagName] &&
  12721. !dtd.$list[pN.tagName]
  12722. ) {
  12723. domUtils.removeAttributes(pN, removeFormatAttributes);
  12724. }
  12725. pN = bookmark.end.parentNode;
  12726. if (
  12727. bookmark.end &&
  12728. domUtils.isBlockElm(pN) &&
  12729. !dtd.$tableContent[pN.tagName] &&
  12730. !dtd.$list[pN.tagName]
  12731. ) {
  12732. domUtils.removeAttributes(pN, removeFormatAttributes);
  12733. }
  12734. range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
  12735. //清除冗余的代码 <b><bookmark></b>
  12736. var node = range.startContainer,
  12737. tmp,
  12738. collapsed = range.collapsed;
  12739. while (
  12740. node.nodeType == 1 &&
  12741. domUtils.isEmptyNode(node) &&
  12742. dtd.$removeEmpty[node.tagName]
  12743. ) {
  12744. tmp = node.parentNode;
  12745. range.setStartBefore(node);
  12746. //trace:937
  12747. //更新结束边界
  12748. if (range.startContainer === range.endContainer) {
  12749. range.endOffset--;
  12750. }
  12751. domUtils.remove(node);
  12752. node = tmp;
  12753. }
  12754. if (!collapsed) {
  12755. node = range.endContainer;
  12756. while (
  12757. node.nodeType == 1 &&
  12758. domUtils.isEmptyNode(node) &&
  12759. dtd.$removeEmpty[node.tagName]
  12760. ) {
  12761. tmp = node.parentNode;
  12762. range.setEndBefore(node);
  12763. domUtils.remove(node);
  12764. node = tmp;
  12765. }
  12766. }
  12767. }
  12768. range = this.selection.getRange();
  12769. doRemove(range);
  12770. range.select();
  12771. }
  12772. };
  12773. };
  12774. // plugins/blockquote.js
  12775. /**
  12776. * 添加引用
  12777. * @file
  12778. * @since 1.2.6.1
  12779. */
  12780. /**
  12781. * 添加引用
  12782. * @command blockquote
  12783. * @method execCommand
  12784. * @param { String } cmd 命令字符串
  12785. * @example
  12786. * ```javascript
  12787. * editor.execCommand( 'blockquote' );
  12788. * ```
  12789. */
  12790. /**
  12791. * 添加引用
  12792. * @command blockquote
  12793. * @method execCommand
  12794. * @param { String } cmd 命令字符串
  12795. * @param { Object } attrs 节点属性
  12796. * @example
  12797. * ```javascript
  12798. * editor.execCommand( 'blockquote',{
  12799. * style: "color: red;"
  12800. * } );
  12801. * ```
  12802. */
  12803. UE.plugins["blockquote"] = function() {
  12804. var me = this;
  12805. function getObj(editor) {
  12806. return domUtils.filterNodeList(
  12807. editor.selection.getStartElementPath(),
  12808. "blockquote"
  12809. );
  12810. }
  12811. me.commands["blockquote"] = {
  12812. execCommand: function(cmdName, attrs) {
  12813. var range = this.selection.getRange(),
  12814. obj = getObj(this),
  12815. blockquote = dtd.blockquote,
  12816. bookmark = range.createBookmark();
  12817. if (obj) {
  12818. var start = range.startContainer,
  12819. startBlock = domUtils.isBlockElm(start)
  12820. ? start
  12821. : domUtils.findParent(start, function(node) {
  12822. return domUtils.isBlockElm(node);
  12823. }),
  12824. end = range.endContainer,
  12825. endBlock = domUtils.isBlockElm(end)
  12826. ? end
  12827. : domUtils.findParent(end, function(node) {
  12828. return domUtils.isBlockElm(node);
  12829. });
  12830. //处理一下li
  12831. startBlock =
  12832. domUtils.findParentByTagName(startBlock, "li", true) || startBlock;
  12833. endBlock =
  12834. domUtils.findParentByTagName(endBlock, "li", true) || endBlock;
  12835. if (
  12836. startBlock.tagName == "LI" ||
  12837. startBlock.tagName == "TD" ||
  12838. startBlock === obj ||
  12839. domUtils.isBody(startBlock)
  12840. ) {
  12841. domUtils.remove(obj, true);
  12842. } else {
  12843. domUtils.breakParent(startBlock, obj);
  12844. }
  12845. if (startBlock !== endBlock) {
  12846. obj = domUtils.findParentByTagName(endBlock, "blockquote");
  12847. if (obj) {
  12848. if (
  12849. endBlock.tagName == "LI" ||
  12850. endBlock.tagName == "TD" ||
  12851. domUtils.isBody(endBlock)
  12852. ) {
  12853. obj.parentNode && domUtils.remove(obj, true);
  12854. } else {
  12855. domUtils.breakParent(endBlock, obj);
  12856. }
  12857. }
  12858. }
  12859. var blockquotes = domUtils.getElementsByTagName(
  12860. this.document,
  12861. "blockquote"
  12862. );
  12863. for (var i = 0, bi; (bi = blockquotes[i++]); ) {
  12864. if (!bi.childNodes.length) {
  12865. domUtils.remove(bi);
  12866. } else if (
  12867. domUtils.getPosition(bi, startBlock) &
  12868. domUtils.POSITION_FOLLOWING &&
  12869. domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING
  12870. ) {
  12871. domUtils.remove(bi, true);
  12872. }
  12873. }
  12874. } else {
  12875. var tmpRange = range.cloneRange(),
  12876. node = tmpRange.startContainer.nodeType == 1
  12877. ? tmpRange.startContainer
  12878. : tmpRange.startContainer.parentNode,
  12879. preNode = node,
  12880. doEnd = 1;
  12881. //调整开始
  12882. while (1) {
  12883. if (domUtils.isBody(node)) {
  12884. if (preNode !== node) {
  12885. if (range.collapsed) {
  12886. tmpRange.selectNode(preNode);
  12887. doEnd = 0;
  12888. } else {
  12889. tmpRange.setStartBefore(preNode);
  12890. }
  12891. } else {
  12892. tmpRange.setStart(node, 0);
  12893. }
  12894. break;
  12895. }
  12896. if (!blockquote[node.tagName]) {
  12897. if (range.collapsed) {
  12898. tmpRange.selectNode(preNode);
  12899. } else {
  12900. tmpRange.setStartBefore(preNode);
  12901. }
  12902. break;
  12903. }
  12904. preNode = node;
  12905. node = node.parentNode;
  12906. }
  12907. //调整结束
  12908. if (doEnd) {
  12909. preNode = node = node = tmpRange.endContainer.nodeType == 1
  12910. ? tmpRange.endContainer
  12911. : tmpRange.endContainer.parentNode;
  12912. while (1) {
  12913. if (domUtils.isBody(node)) {
  12914. if (preNode !== node) {
  12915. tmpRange.setEndAfter(preNode);
  12916. } else {
  12917. tmpRange.setEnd(node, node.childNodes.length);
  12918. }
  12919. break;
  12920. }
  12921. if (!blockquote[node.tagName]) {
  12922. tmpRange.setEndAfter(preNode);
  12923. break;
  12924. }
  12925. preNode = node;
  12926. node = node.parentNode;
  12927. }
  12928. }
  12929. node = range.document.createElement("blockquote");
  12930. domUtils.setAttributes(node, attrs);
  12931. node.appendChild(tmpRange.extractContents());
  12932. tmpRange.insertNode(node);
  12933. //去除重复的
  12934. var childs = domUtils.getElementsByTagName(node, "blockquote");
  12935. for (var i = 0, ci; (ci = childs[i++]); ) {
  12936. if (ci.parentNode) {
  12937. domUtils.remove(ci, true);
  12938. }
  12939. }
  12940. }
  12941. range.moveToBookmark(bookmark).select();
  12942. },
  12943. queryCommandState: function() {
  12944. return getObj(this) ? 1 : 0;
  12945. }
  12946. };
  12947. };
  12948. // plugins/convertcase.js
  12949. /**
  12950. * 大小写转换
  12951. * @file
  12952. * @since 1.2.6.1
  12953. */
  12954. /**
  12955. * 把选区内文本变大写,与“tolowercase”命令互斥
  12956. * @command touppercase
  12957. * @method execCommand
  12958. * @param { String } cmd 命令字符串
  12959. * @example
  12960. * ```javascript
  12961. * editor.execCommand( 'touppercase' );
  12962. * ```
  12963. */
  12964. /**
  12965. * 把选区内文本变小写,与“touppercase”命令互斥
  12966. * @command tolowercase
  12967. * @method execCommand
  12968. * @param { String } cmd 命令字符串
  12969. * @example
  12970. * ```javascript
  12971. * editor.execCommand( 'tolowercase' );
  12972. * ```
  12973. */
  12974. UE.commands["touppercase"] = UE.commands["tolowercase"] = {
  12975. execCommand: function(cmd) {
  12976. var me = this;
  12977. var rng = me.selection.getRange();
  12978. if (rng.collapsed) {
  12979. return rng;
  12980. }
  12981. var bk = rng.createBookmark(),
  12982. bkEnd = bk.end,
  12983. filterFn = function(node) {
  12984. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  12985. },
  12986. curNode = domUtils.getNextDomNode(bk.start, false, filterFn);
  12987. while (
  12988. curNode &&
  12989. domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING
  12990. ) {
  12991. if (curNode.nodeType == 3) {
  12992. curNode.nodeValue = curNode.nodeValue[
  12993. cmd == "touppercase" ? "toUpperCase" : "toLowerCase"
  12994. ]();
  12995. }
  12996. curNode = domUtils.getNextDomNode(curNode, true, filterFn);
  12997. if (curNode === bkEnd) {
  12998. break;
  12999. }
  13000. }
  13001. rng.moveToBookmark(bk).select();
  13002. }
  13003. };
  13004. // plugins/indent.js
  13005. /**
  13006. * 首行缩进
  13007. * @file
  13008. * @since 1.2.6.1
  13009. */
  13010. /**
  13011. * 缩进
  13012. * @command indent
  13013. * @method execCommand
  13014. * @param { String } cmd 命令字符串
  13015. * @example
  13016. * ```javascript
  13017. * editor.execCommand( 'indent' );
  13018. * ```
  13019. */
  13020. UE.commands["indent"] = {
  13021. execCommand: function() {
  13022. var me = this,
  13023. value = me.queryCommandState("indent")
  13024. ? "0em"
  13025. : me.options.indentValue || "2em";
  13026. me.execCommand("Paragraph", "p", { style: "text-indent:" + value });
  13027. },
  13028. queryCommandState: function() {
  13029. var pN = domUtils.filterNodeList(
  13030. this.selection.getStartElementPath(),
  13031. "p h1 h2 h3 h4 h5 h6"
  13032. );
  13033. return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
  13034. }
  13035. };
  13036. // plugins/print.js
  13037. /**
  13038. * 打印
  13039. * @file
  13040. * @since 1.2.6.1
  13041. */
  13042. /**
  13043. * 打印
  13044. * @command print
  13045. * @method execCommand
  13046. * @param { String } cmd 命令字符串
  13047. * @example
  13048. * ```javascript
  13049. * editor.execCommand( 'print' );
  13050. * ```
  13051. */
  13052. UE.commands["print"] = {
  13053. execCommand: function() {
  13054. this.window.print();
  13055. },
  13056. notNeedUndo: 1
  13057. };
  13058. // plugins/preview.js
  13059. /**
  13060. * 预览
  13061. * @file
  13062. * @since 1.2.6.1
  13063. */
  13064. /**
  13065. * 预览
  13066. * @command preview
  13067. * @method execCommand
  13068. * @param { String } cmd 命令字符串
  13069. * @example
  13070. * ```javascript
  13071. * editor.execCommand( 'preview' );
  13072. * ```
  13073. */
  13074. UE.commands["preview"] = {
  13075. execCommand: function() {
  13076. var w = window.open("", "_blank", ""),
  13077. d = w.document;
  13078. d.open();
  13079. d.write(
  13080. '<!DOCTYPE html><html><head><meta charset="utf-8"/><script src="' +
  13081. this.options.UEDITOR_HOME_URL +
  13082. 'neditor.parse.js"></script><script>' +
  13083. "setTimeout(function(){uParse('div',{rootPath: '" +
  13084. this.options.UEDITOR_HOME_URL +
  13085. "'})},300)" +
  13086. "</script></head><body><div>" +
  13087. this.getContent(null, null, true) +
  13088. "</div></body></html>"
  13089. );
  13090. d.close();
  13091. },
  13092. notNeedUndo: 1
  13093. };
  13094. // plugins/selectall.js
  13095. /**
  13096. * 全选
  13097. * @file
  13098. * @since 1.2.6.1
  13099. */
  13100. /**
  13101. * 选中所有内容
  13102. * @command selectall
  13103. * @method execCommand
  13104. * @param { String } cmd 命令字符串
  13105. * @example
  13106. * ```javascript
  13107. * editor.execCommand( 'selectall' );
  13108. * ```
  13109. */
  13110. UE.plugins["selectall"] = function() {
  13111. var me = this;
  13112. me.commands["selectall"] = {
  13113. execCommand: function() {
  13114. //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
  13115. var me = this,
  13116. body = me.body,
  13117. range = me.selection.getRange();
  13118. range.selectNodeContents(body);
  13119. if (domUtils.isEmptyBlock(body)) {
  13120. //opera不能自动合并到元素的里边,要手动处理一下
  13121. if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
  13122. range.setStartAtFirst(body.firstChild);
  13123. }
  13124. range.collapse(true);
  13125. }
  13126. range.select(true);
  13127. },
  13128. notNeedUndo: 1
  13129. };
  13130. //快捷键
  13131. me.addshortcutkey({
  13132. selectAll: "ctrl+65"
  13133. });
  13134. };
  13135. // plugins/paragraph.js
  13136. /**
  13137. * 段落样式
  13138. * @file
  13139. * @since 1.2.6.1
  13140. */
  13141. /**
  13142. * 段落格式
  13143. * @command paragraph
  13144. * @method execCommand
  13145. * @param { String } cmd 命令字符串
  13146. * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
  13147. * @param {Object} attrs 标签的属性
  13148. * @example
  13149. * ```javascript
  13150. * editor.execCommand( 'Paragraph','h1','{
  13151. * class:'test'
  13152. * }' );
  13153. * ```
  13154. */
  13155. /**
  13156. * 返回选区内节点标签名
  13157. * @command paragraph
  13158. * @method queryCommandValue
  13159. * @param { String } cmd 命令字符串
  13160. * @return { String } 节点标签名
  13161. * @example
  13162. * ```javascript
  13163. * editor.queryCommandValue( 'Paragraph' );
  13164. * ```
  13165. */
  13166. UE.plugins["paragraph"] = function() {
  13167. var me = this,
  13168. block = domUtils.isBlockElm,
  13169. notExchange = ["TD", "LI", "PRE"],
  13170. doParagraph = function(range, style, attrs, sourceCmdName) {
  13171. var bookmark = range.createBookmark(),
  13172. filterFn = function(node) {
  13173. return node.nodeType == 1
  13174. ? node.tagName.toLowerCase() != "br" &&
  13175. !domUtils.isBookmarkNode(node)
  13176. : !domUtils.isWhitespace(node);
  13177. },
  13178. para;
  13179. range.enlarge(true);
  13180. var bookmark2 = range.createBookmark(),
  13181. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  13182. tmpRange = range.cloneRange(),
  13183. tmpNode;
  13184. while (
  13185. current &&
  13186. !(
  13187. domUtils.getPosition(current, bookmark2.end) &
  13188. domUtils.POSITION_FOLLOWING
  13189. )
  13190. ) {
  13191. if (current.nodeType == 3 || !block(current)) {
  13192. tmpRange.setStartBefore(current);
  13193. while (current && current !== bookmark2.end && !block(current)) {
  13194. tmpNode = current;
  13195. current = domUtils.getNextDomNode(current, false, null, function(
  13196. node
  13197. ) {
  13198. return !block(node);
  13199. });
  13200. }
  13201. tmpRange.setEndAfter(tmpNode);
  13202. para = range.document.createElement(style);
  13203. if (attrs) {
  13204. domUtils.setAttributes(para, attrs);
  13205. if (
  13206. sourceCmdName &&
  13207. sourceCmdName == "customstyle" &&
  13208. attrs.style
  13209. ) {
  13210. para.style.cssText = attrs.style;
  13211. }
  13212. }
  13213. para.appendChild(tmpRange.extractContents());
  13214. //需要内容占位
  13215. if (domUtils.isEmptyNode(para)) {
  13216. domUtils.fillChar(range.document, para);
  13217. }
  13218. tmpRange.insertNode(para);
  13219. var parent = para.parentNode;
  13220. //如果para上一级是一个block元素且不是body,td就删除它
  13221. if (
  13222. block(parent) &&
  13223. !domUtils.isBody(para.parentNode) &&
  13224. utils.indexOf(notExchange, parent.tagName) == -1
  13225. ) {
  13226. //存储dir,style
  13227. if (!(sourceCmdName && sourceCmdName == "customstyle")) {
  13228. parent.getAttribute("dir") &&
  13229. para.setAttribute("dir", parent.getAttribute("dir"));
  13230. //trace:1070
  13231. parent.style.cssText &&
  13232. (para.style.cssText =
  13233. parent.style.cssText + ";" + para.style.cssText);
  13234. //trace:1030
  13235. parent.style.textAlign &&
  13236. !para.style.textAlign &&
  13237. (para.style.textAlign = parent.style.textAlign);
  13238. parent.style.textIndent &&
  13239. !para.style.textIndent &&
  13240. (para.style.textIndent = parent.style.textIndent);
  13241. parent.style.padding &&
  13242. !para.style.padding &&
  13243. (para.style.padding = parent.style.padding);
  13244. }
  13245. //trace:1706 选择的就是h1-6要删除
  13246. if (
  13247. attrs &&
  13248. /h\d/i.test(parent.tagName) &&
  13249. !/h\d/i.test(para.tagName)
  13250. ) {
  13251. domUtils.setAttributes(parent, attrs);
  13252. if (
  13253. sourceCmdName &&
  13254. sourceCmdName == "customstyle" &&
  13255. attrs.style
  13256. ) {
  13257. parent.style.cssText = attrs.style;
  13258. }
  13259. domUtils.remove(para.parentNode, true);
  13260. para = parent;
  13261. } else {
  13262. domUtils.remove(para.parentNode, true);
  13263. }
  13264. }
  13265. if (utils.indexOf(notExchange, parent.tagName) != -1) {
  13266. current = parent;
  13267. } else {
  13268. current = para;
  13269. }
  13270. current = domUtils.getNextDomNode(current, false, filterFn);
  13271. } else {
  13272. current = domUtils.getNextDomNode(current, true, filterFn);
  13273. }
  13274. }
  13275. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  13276. };
  13277. me.setOpt("paragraph", {
  13278. p: "",
  13279. h1: "",
  13280. h2: "",
  13281. h3: "",
  13282. h4: "",
  13283. h5: "",
  13284. h6: ""
  13285. });
  13286. me.commands["paragraph"] = {
  13287. execCommand: function(cmdName, style, attrs, sourceCmdName) {
  13288. var range = this.selection.getRange();
  13289. //闭合时单独处理
  13290. if (range.collapsed) {
  13291. var txt = this.document.createTextNode("p");
  13292. range.insertNode(txt);
  13293. //去掉冗余的fillchar
  13294. if (browser.ie) {
  13295. var node = txt.previousSibling;
  13296. if (node && domUtils.isWhitespace(node)) {
  13297. domUtils.remove(node);
  13298. }
  13299. node = txt.nextSibling;
  13300. if (node && domUtils.isWhitespace(node)) {
  13301. domUtils.remove(node);
  13302. }
  13303. }
  13304. }
  13305. range = doParagraph(range, style, attrs, sourceCmdName);
  13306. if (txt) {
  13307. range.setStartBefore(txt).collapse(true);
  13308. pN = txt.parentNode;
  13309. domUtils.remove(txt);
  13310. if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
  13311. domUtils.fillNode(this.document, pN);
  13312. }
  13313. }
  13314. if (
  13315. browser.gecko &&
  13316. range.collapsed &&
  13317. range.startContainer.nodeType == 1
  13318. ) {
  13319. var child = range.startContainer.childNodes[range.startOffset];
  13320. if (
  13321. child &&
  13322. child.nodeType == 1 &&
  13323. child.tagName.toLowerCase() == style
  13324. ) {
  13325. range.setStart(child, 0).collapse(true);
  13326. }
  13327. }
  13328. //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
  13329. range.select();
  13330. return true;
  13331. },
  13332. queryCommandValue: function() {
  13333. var node = domUtils.filterNodeList(
  13334. this.selection.getStartElementPath(),
  13335. "p h1 h2 h3 h4 h5 h6"
  13336. );
  13337. return node ? node.tagName.toLowerCase() : "";
  13338. }
  13339. };
  13340. };
  13341. // plugins/directionality.js
  13342. /**
  13343. * 设置文字输入的方向的插件
  13344. * @file
  13345. * @since 1.2.6.1
  13346. */
  13347. ;(function() {
  13348. var block = domUtils.isBlockElm,
  13349. getObj = function(editor) {
  13350. // var startNode = editor.selection.getStart(),
  13351. // parents;
  13352. // if ( startNode ) {
  13353. // //查找所有的是block的父亲节点
  13354. // parents = domUtils.findParents( startNode, true, block, true );
  13355. // for ( var i = 0,ci; ci = parents[i++]; ) {
  13356. // if ( ci.getAttribute( 'dir' ) ) {
  13357. // return ci;
  13358. // }
  13359. // }
  13360. // }
  13361. return domUtils.filterNodeList(
  13362. editor.selection.getStartElementPath(),
  13363. function(n) {
  13364. return n && n.nodeType == 1 && n.getAttribute("dir");
  13365. }
  13366. );
  13367. },
  13368. doDirectionality = function(range, editor, forward) {
  13369. var bookmark,
  13370. filterFn = function(node) {
  13371. return node.nodeType == 1
  13372. ? !domUtils.isBookmarkNode(node)
  13373. : !domUtils.isWhitespace(node);
  13374. },
  13375. obj = getObj(editor);
  13376. if (obj && range.collapsed) {
  13377. obj.setAttribute("dir", forward);
  13378. return range;
  13379. }
  13380. bookmark = range.createBookmark();
  13381. range.enlarge(true);
  13382. var bookmark2 = range.createBookmark(),
  13383. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  13384. tmpRange = range.cloneRange(),
  13385. tmpNode;
  13386. while (
  13387. current &&
  13388. !(
  13389. domUtils.getPosition(current, bookmark2.end) &
  13390. domUtils.POSITION_FOLLOWING
  13391. )
  13392. ) {
  13393. if (current.nodeType == 3 || !block(current)) {
  13394. tmpRange.setStartBefore(current);
  13395. while (current && current !== bookmark2.end && !block(current)) {
  13396. tmpNode = current;
  13397. current = domUtils.getNextDomNode(current, false, null, function(
  13398. node
  13399. ) {
  13400. return !block(node);
  13401. });
  13402. }
  13403. tmpRange.setEndAfter(tmpNode);
  13404. var common = tmpRange.getCommonAncestor();
  13405. if (!domUtils.isBody(common) && block(common)) {
  13406. //遍历到了block节点
  13407. common.setAttribute("dir", forward);
  13408. current = common;
  13409. } else {
  13410. //没有遍历到,添加一个block节点
  13411. var p = range.document.createElement("p");
  13412. p.setAttribute("dir", forward);
  13413. var frag = tmpRange.extractContents();
  13414. p.appendChild(frag);
  13415. tmpRange.insertNode(p);
  13416. current = p;
  13417. }
  13418. current = domUtils.getNextDomNode(current, false, filterFn);
  13419. } else {
  13420. current = domUtils.getNextDomNode(current, true, filterFn);
  13421. }
  13422. }
  13423. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  13424. };
  13425. /**
  13426. * 文字输入方向
  13427. * @command directionality
  13428. * @method execCommand
  13429. * @param { String } cmdName 命令字符串
  13430. * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入
  13431. * @example
  13432. * ```javascript
  13433. * editor.execCommand( 'directionality', 'ltr');
  13434. * ```
  13435. */
  13436. /**
  13437. * 查询当前选区的文字输入方向
  13438. * @command directionality
  13439. * @method queryCommandValue
  13440. * @param { String } cmdName 命令字符串
  13441. * @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入
  13442. * @example
  13443. * ```javascript
  13444. * editor.queryCommandValue( 'directionality');
  13445. * ```
  13446. */
  13447. UE.commands["directionality"] = {
  13448. execCommand: function(cmdName, forward) {
  13449. var range = this.selection.getRange();
  13450. //闭合时单独处理
  13451. if (range.collapsed) {
  13452. var txt = this.document.createTextNode("d");
  13453. range.insertNode(txt);
  13454. }
  13455. doDirectionality(range, this, forward);
  13456. if (txt) {
  13457. range.setStartBefore(txt).collapse(true);
  13458. domUtils.remove(txt);
  13459. }
  13460. range.select();
  13461. return true;
  13462. },
  13463. queryCommandValue: function() {
  13464. var node = getObj(this);
  13465. return node ? node.getAttribute("dir") : "ltr";
  13466. }
  13467. };
  13468. })();
  13469. // plugins/horizontal.js
  13470. /**
  13471. * 插入分割线插件
  13472. * @file
  13473. * @since 1.2.6.1
  13474. */
  13475. /**
  13476. * 插入分割线
  13477. * @command horizontal
  13478. * @method execCommand
  13479. * @param { String } cmdName 命令字符串
  13480. * @example
  13481. * ```javascript
  13482. * editor.execCommand( 'horizontal' );
  13483. * ```
  13484. */
  13485. UE.plugins["horizontal"] = function() {
  13486. var me = this;
  13487. me.commands["horizontal"] = {
  13488. execCommand: function(cmdName) {
  13489. var me = this;
  13490. if (me.queryCommandState(cmdName) !== -1) {
  13491. me.execCommand("insertHtml", "<hr>");
  13492. var range = me.selection.getRange(),
  13493. start = range.startContainer;
  13494. if (start.nodeType == 1 && !start.childNodes[range.startOffset]) {
  13495. var tmp;
  13496. if ((tmp = start.childNodes[range.startOffset - 1])) {
  13497. if (tmp.nodeType == 1 && tmp.tagName == "HR") {
  13498. if (me.options.enterTag == "p") {
  13499. tmp = me.document.createElement("p");
  13500. range.insertNode(tmp);
  13501. range.setStart(tmp, 0).setCursor();
  13502. } else {
  13503. tmp = me.document.createElement("br");
  13504. range.insertNode(tmp);
  13505. range.setStartBefore(tmp).setCursor();
  13506. }
  13507. }
  13508. }
  13509. }
  13510. return true;
  13511. }
  13512. },
  13513. //边界在table里不能加分隔线
  13514. queryCommandState: function() {
  13515. return domUtils.filterNodeList(
  13516. this.selection.getStartElementPath(),
  13517. "table"
  13518. )
  13519. ? -1
  13520. : 0;
  13521. }
  13522. };
  13523. // me.addListener('delkeyup',function(){
  13524. // var rng = this.selection.getRange();
  13525. // if(browser.ie && browser.version > 8){
  13526. // rng.txtToElmBoundary(true);
  13527. // if(domUtils.isStartInblock(rng)){
  13528. // var tmpNode = rng.startContainer;
  13529. // var pre = tmpNode.previousSibling;
  13530. // if(pre && domUtils.isTagNode(pre,'hr')){
  13531. // domUtils.remove(pre);
  13532. // rng.select();
  13533. // return;
  13534. // }
  13535. // }
  13536. // }
  13537. // if(domUtils.isBody(rng.startContainer)){
  13538. // var hr = rng.startContainer.childNodes[rng.startOffset -1];
  13539. // if(hr && hr.nodeName == 'HR'){
  13540. // var next = hr.nextSibling;
  13541. // if(next){
  13542. // rng.setStart(next,0)
  13543. // }else if(hr.previousSibling){
  13544. // rng.setStartAtLast(hr.previousSibling)
  13545. // }else{
  13546. // var p = this.document.createElement('p');
  13547. // hr.parentNode.insertBefore(p,hr);
  13548. // domUtils.fillNode(this.document,p);
  13549. // rng.setStart(p,0);
  13550. // }
  13551. // domUtils.remove(hr);
  13552. // rng.setCursor(false,true);
  13553. // }
  13554. // }
  13555. // })
  13556. me.addListener("delkeydown", function(name, evt) {
  13557. var rng = this.selection.getRange();
  13558. rng.txtToElmBoundary(true);
  13559. if (domUtils.isStartInblock(rng)) {
  13560. var tmpNode = rng.startContainer;
  13561. var pre = tmpNode.previousSibling;
  13562. if (pre && domUtils.isTagNode(pre, "hr")) {
  13563. domUtils.remove(pre);
  13564. rng.select();
  13565. domUtils.preventDefault(evt);
  13566. return true;
  13567. }
  13568. }
  13569. });
  13570. };
  13571. // plugins/time.js
  13572. /**
  13573. * 插入时间和日期
  13574. * @file
  13575. * @since 1.2.6.1
  13576. */
  13577. /**
  13578. * 插入时间,默认格式:12:59:59
  13579. * @command time
  13580. * @method execCommand
  13581. * @param { String } cmd 命令字符串
  13582. * @example
  13583. * ```javascript
  13584. * editor.execCommand( 'time');
  13585. * ```
  13586. */
  13587. /**
  13588. * 插入日期,默认格式:2013-08-30
  13589. * @command date
  13590. * @method execCommand
  13591. * @param { String } cmd 命令字符串
  13592. * @example
  13593. * ```javascript
  13594. * editor.execCommand( 'date');
  13595. * ```
  13596. */
  13597. UE.commands["time"] = UE.commands["date"] = {
  13598. execCommand: function(cmd, format) {
  13599. var date = new Date();
  13600. function formatTime(date, format) {
  13601. var hh = ("0" + date.getHours()).slice(-2),
  13602. ii = ("0" + date.getMinutes()).slice(-2),
  13603. ss = ("0" + date.getSeconds()).slice(-2);
  13604. format = format || "hh:ii:ss";
  13605. return format.replace(/hh/gi, hh).replace(/ii/gi, ii).replace(/ss/gi, ss);
  13606. }
  13607. function formatDate(date, format) {
  13608. var yyyy = ("000" + date.getFullYear()).slice(-4),
  13609. yy = yyyy.slice(-2),
  13610. mm = ("0" + (date.getMonth() + 1)).slice(-2),
  13611. dd = ("0" + date.getDate()).slice(-2);
  13612. format = format || "yyyy-mm-dd";
  13613. return format
  13614. .replace(/yyyy/gi, yyyy)
  13615. .replace(/yy/gi, yy)
  13616. .replace(/mm/gi, mm)
  13617. .replace(/dd/gi, dd);
  13618. }
  13619. this.execCommand(
  13620. "insertHtml",
  13621. cmd == "time" ? formatTime(date, format) : formatDate(date, format)
  13622. );
  13623. }
  13624. };
  13625. // plugins/rowspacing.js
  13626. /**
  13627. * 段前段后间距插件
  13628. * @file
  13629. * @since 1.2.6.1
  13630. */
  13631. /**
  13632. * 设置段间距
  13633. * @command rowspacing
  13634. * @method execCommand
  13635. * @param { String } cmd 命令字符串
  13636. * @param { String } value 段间距的值,以px为单位
  13637. * @param { String } dir 间距位置,top或bottom,分别表示段前和段后
  13638. * @example
  13639. * ```javascript
  13640. * editor.execCommand( 'rowspacing', '10', 'top' );
  13641. * ```
  13642. */
  13643. UE.plugins["rowspacing"] = function() {
  13644. var me = this;
  13645. me.setOpt({
  13646. rowspacingtop: ["5", "10", "15", "20", "25"],
  13647. rowspacingbottom: ["5", "10", "15", "20", "25"]
  13648. });
  13649. me.commands["rowspacing"] = {
  13650. execCommand: function(cmdName, value, dir) {
  13651. this.execCommand("paragraph", "p", {
  13652. style: "margin-" + dir + ":" + value + "px"
  13653. });
  13654. return true;
  13655. },
  13656. queryCommandValue: function(cmdName, dir) {
  13657. var pN = domUtils.filterNodeList(
  13658. this.selection.getStartElementPath(),
  13659. function(node) {
  13660. return domUtils.isBlockElm(node);
  13661. }
  13662. ),
  13663. value;
  13664. //trace:1026
  13665. if (pN) {
  13666. value = domUtils
  13667. .getComputedStyle(pN, "margin-" + dir)
  13668. .replace(/[^\d]/g, "");
  13669. return !value ? 0 : value;
  13670. }
  13671. return 0;
  13672. }
  13673. };
  13674. };
  13675. // plugins/lineheight.js
  13676. /**
  13677. * 设置行内间距
  13678. * @file
  13679. * @since 1.2.6.1
  13680. */
  13681. UE.plugins["lineheight"] = function() {
  13682. var me = this;
  13683. me.setOpt({ lineheight: ["1", "1.5", "1.75", "2", "3", "4", "5"] });
  13684. /**
  13685. * 行距
  13686. * @command lineheight
  13687. * @method execCommand
  13688. * @param { String } cmdName 命令字符串
  13689. * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75
  13690. * @example
  13691. * ```javascript
  13692. * editor.execCommand( 'lineheight', 1.5);
  13693. * ```
  13694. */
  13695. /**
  13696. * 查询当前选区内容的行高大小
  13697. * @command lineheight
  13698. * @method queryCommandValue
  13699. * @param { String } cmd 命令字符串
  13700. * @return { String } 返回当前行高大小
  13701. * @example
  13702. * ```javascript
  13703. * editor.queryCommandValue( 'lineheight' );
  13704. * ```
  13705. */
  13706. me.commands["lineheight"] = {
  13707. execCommand: function(cmdName, value) {
  13708. this.execCommand("paragraph", "p", {
  13709. style: "line-height:" + (value == "1" ? "normal" : value + "em")
  13710. });
  13711. return true;
  13712. },
  13713. queryCommandValue: function() {
  13714. var pN = domUtils.filterNodeList(
  13715. this.selection.getStartElementPath(),
  13716. function(node) {
  13717. return domUtils.isBlockElm(node);
  13718. }
  13719. );
  13720. if (pN) {
  13721. var value = domUtils.getComputedStyle(pN, "line-height");
  13722. return value == "normal" ? 1 : value.replace(/[^\d.]*/gi, "");
  13723. }
  13724. }
  13725. };
  13726. };
  13727. // plugins/insertcode.js
  13728. /**
  13729. * 插入代码插件
  13730. * @file
  13731. * @since 1.2.6.1
  13732. */
  13733. UE.plugins["insertcode"] = function() {
  13734. var me = this;
  13735. me.ready(function() {
  13736. utils.cssRule(
  13737. "pre",
  13738. "pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}",
  13739. me.document
  13740. );
  13741. });
  13742. me.setOpt("insertcode", {
  13743. as3: "ActionScript3",
  13744. bash: "Bash/Shell",
  13745. cpp: "C/C++",
  13746. css: "Css",
  13747. cf: "CodeFunction",
  13748. "c#": "C#",
  13749. delphi: "Delphi",
  13750. diff: "Diff",
  13751. erlang: "Erlang",
  13752. groovy: "Groovy",
  13753. html: "Html",
  13754. java: "Java",
  13755. jfx: "JavaFx",
  13756. js: "Javascript",
  13757. pl: "Perl",
  13758. php: "Php",
  13759. plain: "Plain Text",
  13760. ps: "PowerShell",
  13761. python: "Python",
  13762. ruby: "Ruby",
  13763. scala: "Scala",
  13764. sql: "Sql",
  13765. vb: "Vb",
  13766. xml: "Xml"
  13767. });
  13768. /**
  13769. * 插入代码
  13770. * @command insertcode
  13771. * @method execCommand
  13772. * @param { String } cmd 命令字符串
  13773. * @param { String } lang 插入代码的语言
  13774. * @example
  13775. * ```javascript
  13776. * editor.execCommand( 'insertcode', 'javascript' );
  13777. * ```
  13778. */
  13779. /**
  13780. * 如果选区所在位置是插入插入代码区域,返回代码的语言
  13781. * @command insertcode
  13782. * @method queryCommandValue
  13783. * @param { String } cmd 命令字符串
  13784. * @return { String } 返回代码的语言
  13785. * @example
  13786. * ```javascript
  13787. * editor.queryCommandValue( 'insertcode' );
  13788. * ```
  13789. */
  13790. me.commands["insertcode"] = {
  13791. execCommand: function(cmd, lang) {
  13792. var me = this,
  13793. rng = me.selection.getRange(),
  13794. pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  13795. if (pre) {
  13796. pre.className = "brush:" + lang + ";toolbar:false;";
  13797. } else {
  13798. var code = "";
  13799. if (rng.collapsed) {
  13800. code = browser.ie && browser.ie11below
  13801. ? browser.version <= 8 ? "&nbsp;" : ""
  13802. : "<br/>";
  13803. } else {
  13804. var frag = rng.extractContents();
  13805. var div = me.document.createElement("div");
  13806. div.appendChild(frag);
  13807. utils.each(
  13808. UE.filterNode(
  13809. UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, "")),
  13810. me.options.filterTxtRules
  13811. ).children,
  13812. function(node) {
  13813. if (browser.ie && browser.ie11below && browser.version > 8) {
  13814. if (node.type == "element") {
  13815. if (node.tagName == "br") {
  13816. code += "\n";
  13817. } else if (!dtd.$empty[node.tagName]) {
  13818. utils.each(node.children, function(cn) {
  13819. if (cn.type == "element") {
  13820. if (cn.tagName == "br") {
  13821. code += "\n";
  13822. } else if (!dtd.$empty[node.tagName]) {
  13823. code += cn.innerText();
  13824. }
  13825. } else {
  13826. code += cn.data;
  13827. }
  13828. });
  13829. if (!/\n$/.test(code)) {
  13830. code += "\n";
  13831. }
  13832. }
  13833. } else {
  13834. code += node.data + "\n";
  13835. }
  13836. if (!node.nextSibling() && /\n$/.test(code)) {
  13837. code = code.replace(/\n$/, "");
  13838. }
  13839. } else {
  13840. if (browser.ie && browser.ie11below) {
  13841. if (node.type == "element") {
  13842. if (node.tagName == "br") {
  13843. code += "<br>";
  13844. } else if (!dtd.$empty[node.tagName]) {
  13845. utils.each(node.children, function(cn) {
  13846. if (cn.type == "element") {
  13847. if (cn.tagName == "br") {
  13848. code += "<br>";
  13849. } else if (!dtd.$empty[node.tagName]) {
  13850. code += cn.innerText();
  13851. }
  13852. } else {
  13853. code += cn.data;
  13854. }
  13855. });
  13856. if (!/br>$/.test(code)) {
  13857. code += "<br>";
  13858. }
  13859. }
  13860. } else {
  13861. code += node.data + "<br>";
  13862. }
  13863. if (!node.nextSibling() && /<br>$/.test(code)) {
  13864. code = code.replace(/<br>$/, "");
  13865. }
  13866. } else {
  13867. code += node.type == "element"
  13868. ? dtd.$empty[node.tagName] ? "" : node.innerText()
  13869. : node.data;
  13870. if (!/br\/?\s*>$/.test(code)) {
  13871. if (!node.nextSibling()) return;
  13872. code += "<br>";
  13873. }
  13874. }
  13875. }
  13876. }
  13877. );
  13878. }
  13879. me.execCommand(
  13880. "inserthtml",
  13881. '<pre id="coder"class="brush:' +
  13882. lang +
  13883. ';toolbar:false">' +
  13884. code +
  13885. "</pre>",
  13886. true
  13887. );
  13888. pre = me.document.getElementById("coder");
  13889. domUtils.removeAttributes(pre, "id");
  13890. var tmpNode = pre.previousSibling;
  13891. if (
  13892. tmpNode &&
  13893. ((tmpNode.nodeType == 3 &&
  13894. tmpNode.nodeValue.length == 1 &&
  13895. browser.ie &&
  13896. browser.version == 6) ||
  13897. domUtils.isEmptyBlock(tmpNode))
  13898. ) {
  13899. domUtils.remove(tmpNode);
  13900. }
  13901. var rng = me.selection.getRange();
  13902. if (domUtils.isEmptyBlock(pre)) {
  13903. rng.setStart(pre, 0).setCursor(false, true);
  13904. } else {
  13905. rng.selectNodeContents(pre).select();
  13906. }
  13907. }
  13908. },
  13909. queryCommandValue: function() {
  13910. var path = this.selection.getStartElementPath();
  13911. var lang = "";
  13912. utils.each(path, function(node) {
  13913. if (node.nodeName == "PRE") {
  13914. var match = node.className.match(/brush:([^;]+)/);
  13915. lang = match && match[1] ? match[1] : "";
  13916. return false;
  13917. }
  13918. });
  13919. return lang;
  13920. }
  13921. };
  13922. me.addInputRule(function(root) {
  13923. utils.each(root.getNodesByTagName("pre"), function(pre) {
  13924. var brs = pre.getNodesByTagName("br");
  13925. if (brs.length) {
  13926. browser.ie &&
  13927. browser.ie11below &&
  13928. browser.version > 8 &&
  13929. utils.each(brs, function(br) {
  13930. var txt = UE.uNode.createText("\n");
  13931. br.parentNode.insertBefore(txt, br);
  13932. br.parentNode.removeChild(br);
  13933. });
  13934. return;
  13935. }
  13936. if (browser.ie && browser.ie11below && browser.version > 8) return;
  13937. var code = pre.innerText().split(/\n/);
  13938. pre.innerHTML("");
  13939. utils.each(code, function(c) {
  13940. if (c.length) {
  13941. pre.appendChild(UE.uNode.createText(c));
  13942. }
  13943. pre.appendChild(UE.uNode.createElement("br"));
  13944. });
  13945. });
  13946. });
  13947. me.addOutputRule(function(root) {
  13948. utils.each(root.getNodesByTagName("pre"), function(pre) {
  13949. var code = "";
  13950. utils.each(pre.children, function(n) {
  13951. if (n.type == "text") {
  13952. //在ie下文本内容有可能末尾带有\n要去掉
  13953. //trace:3396
  13954. code += n.data.replace(/[ ]/g, "&nbsp;").replace(/\n$/, "");
  13955. } else {
  13956. if (n.tagName == "br") {
  13957. code += "\n";
  13958. } else {
  13959. code += !dtd.$empty[n.tagName] ? "" : n.innerText();
  13960. }
  13961. }
  13962. });
  13963. pre.innerText(code.replace(/(&nbsp;|\n)+$/, ""));
  13964. });
  13965. });
  13966. //不需要判断highlight的command列表
  13967. me.notNeedCodeQuery = {
  13968. help: 1,
  13969. undo: 1,
  13970. redo: 1,
  13971. source: 1,
  13972. print: 1,
  13973. searchreplace: 1,
  13974. fullscreen: 1,
  13975. preview: 1,
  13976. insertparagraph: 1,
  13977. elementpath: 1,
  13978. insertcode: 1,
  13979. inserthtml: 1,
  13980. selectall: 1
  13981. };
  13982. //将queyCommamndState重置
  13983. var orgQuery = me.queryCommandState;
  13984. me.queryCommandState = function(cmd) {
  13985. var me = this;
  13986. if (
  13987. !me.notNeedCodeQuery[cmd.toLowerCase()] &&
  13988. me.selection &&
  13989. me.queryCommandValue("insertcode")
  13990. ) {
  13991. return -1;
  13992. }
  13993. return UE.Editor.prototype.queryCommandState.apply(this, arguments);
  13994. };
  13995. me.addListener("beforeenterkeydown", function() {
  13996. var rng = me.selection.getRange();
  13997. var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  13998. if (pre) {
  13999. me.fireEvent("saveScene");
  14000. if (!rng.collapsed) {
  14001. rng.deleteContents();
  14002. }
  14003. if (!browser.ie || browser.ie9above) {
  14004. var tmpNode = me.document.createElement("br"),
  14005. pre;
  14006. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
  14007. var next = tmpNode.nextSibling;
  14008. if (!next && (!browser.ie || browser.version > 10)) {
  14009. rng.insertNode(tmpNode.cloneNode(false));
  14010. } else {
  14011. rng.setStartAfter(tmpNode);
  14012. }
  14013. pre = tmpNode.previousSibling;
  14014. var tmp;
  14015. while (pre) {
  14016. tmp = pre;
  14017. pre = pre.previousSibling;
  14018. if (!pre || pre.nodeName == "BR") {
  14019. pre = tmp;
  14020. break;
  14021. }
  14022. }
  14023. if (pre) {
  14024. var str = "";
  14025. while (
  14026. pre &&
  14027. pre.nodeName != "BR" &&
  14028. new RegExp("^[\\s" + domUtils.fillChar + "]*$").test(pre.nodeValue)
  14029. ) {
  14030. str += pre.nodeValue;
  14031. pre = pre.nextSibling;
  14032. }
  14033. if (pre.nodeName != "BR") {
  14034. var match = pre.nodeValue.match(
  14035. new RegExp("^([\\s" + domUtils.fillChar + "]+)")
  14036. );
  14037. if (match && match[1]) {
  14038. str += match[1];
  14039. }
  14040. }
  14041. if (str) {
  14042. str = me.document.createTextNode(str);
  14043. rng.insertNode(str).setStartAfter(str);
  14044. }
  14045. }
  14046. rng.collapse(true).select(true);
  14047. } else {
  14048. if (browser.version > 8) {
  14049. var txt = me.document.createTextNode("\n");
  14050. var start = rng.startContainer;
  14051. if (rng.startOffset == 0) {
  14052. var preNode = start.previousSibling;
  14053. if (preNode) {
  14054. rng.insertNode(txt);
  14055. var fillchar = me.document.createTextNode(" ");
  14056. rng
  14057. .setStartAfter(txt)
  14058. .insertNode(fillchar)
  14059. .setStart(fillchar, 0)
  14060. .collapse(true)
  14061. .select(true);
  14062. }
  14063. } else {
  14064. rng.insertNode(txt).setStartAfter(txt);
  14065. var fillchar = me.document.createTextNode(" ");
  14066. start = rng.startContainer.childNodes[rng.startOffset];
  14067. if (start && !/^\n/.test(start.nodeValue)) {
  14068. rng.setStartBefore(txt);
  14069. }
  14070. rng
  14071. .insertNode(fillchar)
  14072. .setStart(fillchar, 0)
  14073. .collapse(true)
  14074. .select(true);
  14075. }
  14076. } else {
  14077. var tmpNode = me.document.createElement("br");
  14078. rng.insertNode(tmpNode);
  14079. rng.insertNode(me.document.createTextNode(domUtils.fillChar));
  14080. rng.setStartAfter(tmpNode);
  14081. pre = tmpNode.previousSibling;
  14082. var tmp;
  14083. while (pre) {
  14084. tmp = pre;
  14085. pre = pre.previousSibling;
  14086. if (!pre || pre.nodeName == "BR") {
  14087. pre = tmp;
  14088. break;
  14089. }
  14090. }
  14091. if (pre) {
  14092. var str = "";
  14093. while (
  14094. pre &&
  14095. pre.nodeName != "BR" &&
  14096. new RegExp("^[ " + domUtils.fillChar + "]*$").test(pre.nodeValue)
  14097. ) {
  14098. str += pre.nodeValue;
  14099. pre = pre.nextSibling;
  14100. }
  14101. if (pre.nodeName != "BR") {
  14102. var match = pre.nodeValue.match(
  14103. new RegExp("^([ " + domUtils.fillChar + "]+)")
  14104. );
  14105. if (match && match[1]) {
  14106. str += match[1];
  14107. }
  14108. }
  14109. str = me.document.createTextNode(str);
  14110. rng.insertNode(str).setStartAfter(str);
  14111. }
  14112. rng.collapse(true).select();
  14113. }
  14114. }
  14115. me.fireEvent("saveScene");
  14116. return true;
  14117. }
  14118. });
  14119. me.addListener("tabkeydown", function(cmd, evt) {
  14120. var rng = me.selection.getRange();
  14121. var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  14122. if (pre) {
  14123. me.fireEvent("saveScene");
  14124. if (evt.shiftKey) {
  14125. } else {
  14126. if (!rng.collapsed) {
  14127. var bk = rng.createBookmark();
  14128. var start = bk.start.previousSibling;
  14129. while (start) {
  14130. if (pre.firstChild === start && !domUtils.isBr(start)) {
  14131. pre.insertBefore(me.document.createTextNode(" "), start);
  14132. break;
  14133. }
  14134. if (domUtils.isBr(start)) {
  14135. pre.insertBefore(
  14136. me.document.createTextNode(" "),
  14137. start.nextSibling
  14138. );
  14139. break;
  14140. }
  14141. start = start.previousSibling;
  14142. }
  14143. var end = bk.end;
  14144. start = bk.start.nextSibling;
  14145. if (pre.firstChild === bk.start) {
  14146. pre.insertBefore(
  14147. me.document.createTextNode(" "),
  14148. start.nextSibling
  14149. );
  14150. }
  14151. while (start && start !== end) {
  14152. if (domUtils.isBr(start) && start.nextSibling) {
  14153. if (start.nextSibling === end) {
  14154. break;
  14155. }
  14156. pre.insertBefore(
  14157. me.document.createTextNode(" "),
  14158. start.nextSibling
  14159. );
  14160. }
  14161. start = start.nextSibling;
  14162. }
  14163. rng.moveToBookmark(bk).select();
  14164. } else {
  14165. var tmpNode = me.document.createTextNode(" ");
  14166. rng
  14167. .insertNode(tmpNode)
  14168. .setStartAfter(tmpNode)
  14169. .collapse(true)
  14170. .select(true);
  14171. }
  14172. }
  14173. me.fireEvent("saveScene");
  14174. return true;
  14175. }
  14176. });
  14177. me.addListener("beforeinserthtml", function(evtName, html) {
  14178. var me = this,
  14179. rng = me.selection.getRange(),
  14180. pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
  14181. if (pre) {
  14182. if (!rng.collapsed) {
  14183. rng.deleteContents();
  14184. }
  14185. var htmlstr = "";
  14186. if (browser.ie && browser.version > 8) {
  14187. utils.each(
  14188. UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
  14189. .children,
  14190. function(node) {
  14191. if (node.type == "element") {
  14192. if (node.tagName == "br") {
  14193. htmlstr += "\n";
  14194. } else if (!dtd.$empty[node.tagName]) {
  14195. utils.each(node.children, function(cn) {
  14196. if (cn.type == "element") {
  14197. if (cn.tagName == "br") {
  14198. htmlstr += "\n";
  14199. } else if (!dtd.$empty[node.tagName]) {
  14200. htmlstr += cn.innerText();
  14201. }
  14202. } else {
  14203. htmlstr += cn.data;
  14204. }
  14205. });
  14206. if (!/\n$/.test(htmlstr)) {
  14207. htmlstr += "\n";
  14208. }
  14209. }
  14210. } else {
  14211. htmlstr += node.data + "\n";
  14212. }
  14213. if (!node.nextSibling() && /\n$/.test(htmlstr)) {
  14214. htmlstr = htmlstr.replace(/\n$/, "");
  14215. }
  14216. }
  14217. );
  14218. var tmpNode = me.document.createTextNode(
  14219. utils.html(htmlstr.replace(/&nbsp;/g, " "))
  14220. );
  14221. rng.insertNode(tmpNode).selectNode(tmpNode).select();
  14222. } else {
  14223. var frag = me.document.createDocumentFragment();
  14224. utils.each(
  14225. UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
  14226. .children,
  14227. function(node) {
  14228. if (node.type == "element") {
  14229. if (node.tagName == "br") {
  14230. frag.appendChild(me.document.createElement("br"));
  14231. } else if (!dtd.$empty[node.tagName]) {
  14232. utils.each(node.children, function(cn) {
  14233. if (cn.type == "element") {
  14234. if (cn.tagName == "br") {
  14235. frag.appendChild(me.document.createElement("br"));
  14236. } else if (!dtd.$empty[node.tagName]) {
  14237. frag.appendChild(
  14238. me.document.createTextNode(
  14239. utils.html(cn.innerText().replace(/&nbsp;/g, " "))
  14240. )
  14241. );
  14242. }
  14243. } else {
  14244. frag.appendChild(
  14245. me.document.createTextNode(
  14246. utils.html(cn.data.replace(/&nbsp;/g, " "))
  14247. )
  14248. );
  14249. }
  14250. });
  14251. if (frag.lastChild.nodeName != "BR") {
  14252. frag.appendChild(me.document.createElement("br"));
  14253. }
  14254. }
  14255. } else {
  14256. frag.appendChild(
  14257. me.document.createTextNode(
  14258. utils.html(node.data.replace(/&nbsp;/g, " "))
  14259. )
  14260. );
  14261. }
  14262. if (!node.nextSibling() && frag.lastChild.nodeName == "BR") {
  14263. frag.removeChild(frag.lastChild);
  14264. }
  14265. }
  14266. );
  14267. rng.insertNode(frag).select();
  14268. }
  14269. return true;
  14270. }
  14271. });
  14272. //方向键的处理
  14273. me.addListener("keydown", function(cmd, evt) {
  14274. var me = this,
  14275. keyCode = evt.keyCode || evt.which;
  14276. if (keyCode == 40) {
  14277. var rng = me.selection.getRange(),
  14278. pre,
  14279. start = rng.startContainer;
  14280. if (
  14281. rng.collapsed &&
  14282. (pre = domUtils.findParentByTagName(rng.startContainer, "pre", true)) &&
  14283. !pre.nextSibling
  14284. ) {
  14285. var last = pre.lastChild;
  14286. while (last && last.nodeName == "BR") {
  14287. last = last.previousSibling;
  14288. }
  14289. if (
  14290. last === start ||
  14291. (rng.startContainer === pre &&
  14292. rng.startOffset == pre.childNodes.length)
  14293. ) {
  14294. me.execCommand("insertparagraph");
  14295. domUtils.preventDefault(evt);
  14296. }
  14297. }
  14298. }
  14299. });
  14300. //trace:3395
  14301. me.addListener("delkeydown", function(type, evt) {
  14302. var rng = this.selection.getRange();
  14303. rng.txtToElmBoundary(true);
  14304. var start = rng.startContainer;
  14305. if (
  14306. domUtils.isTagNode(start, "pre") &&
  14307. rng.collapsed &&
  14308. domUtils.isStartInblock(rng)
  14309. ) {
  14310. var p = me.document.createElement("p");
  14311. domUtils.fillNode(me.document, p);
  14312. start.parentNode.insertBefore(p, start);
  14313. domUtils.remove(start);
  14314. rng.setStart(p, 0).setCursor(false, true);
  14315. domUtils.preventDefault(evt);
  14316. return true;
  14317. }
  14318. });
  14319. };
  14320. // plugins/cleardoc.js
  14321. /**
  14322. * 清空文档插件
  14323. * @file
  14324. * @since 1.2.6.1
  14325. */
  14326. /**
  14327. * 清空文档
  14328. * @command cleardoc
  14329. * @method execCommand
  14330. * @param { String } cmd 命令字符串
  14331. * @example
  14332. * ```javascript
  14333. * //editor 是编辑器实例
  14334. * editor.execCommand('cleardoc');
  14335. * ```
  14336. */
  14337. UE.commands["cleardoc"] = {
  14338. execCommand: function(cmdName) {
  14339. var me = this,
  14340. enterTag = me.options.enterTag,
  14341. range = me.selection.getRange();
  14342. if (enterTag == "br") {
  14343. me.body.innerHTML = "<br/>";
  14344. range.setStart(me.body, 0).setCursor();
  14345. } else {
  14346. me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
  14347. range.setStart(me.body.firstChild, 0).setCursor(false, true);
  14348. }
  14349. setTimeout(function() {
  14350. me.fireEvent("clearDoc");
  14351. }, 0);
  14352. }
  14353. };
  14354. // plugins/anchor.js
  14355. /**
  14356. * 锚点插件,为UEditor提供插入锚点支持
  14357. * @file
  14358. * @since 1.2.6.1
  14359. */
  14360. UE.plugin.register("anchor", function() {
  14361. return {
  14362. bindEvents: {
  14363. ready: function() {
  14364. utils.cssRule(
  14365. "anchor",
  14366. ".anchorclass{background: url('" +
  14367. this.options.themePath +
  14368. this.options.theme +
  14369. "/images/anchor.gif') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}",
  14370. this.document
  14371. );
  14372. }
  14373. },
  14374. outputRule: function(root) {
  14375. utils.each(root.getNodesByTagName("img"), function(a) {
  14376. var val;
  14377. if ((val = a.getAttr("anchorname"))) {
  14378. a.tagName = "a";
  14379. a.setAttr({
  14380. anchorname: "",
  14381. name: val,
  14382. class: ""
  14383. });
  14384. }
  14385. });
  14386. },
  14387. inputRule: function(root) {
  14388. utils.each(root.getNodesByTagName("a"), function(a) {
  14389. var val;
  14390. if ((val = a.getAttr("name")) && !a.getAttr("href")) {
  14391. //过滤掉word冗余标签
  14392. //_Toc\d+有可能勿命中
  14393. if (/^\_Toc\d+$/.test(val)) {
  14394. a.parentNode.removeChild(a);
  14395. return;
  14396. }
  14397. a.tagName = "img";
  14398. a.setAttr({
  14399. anchorname: a.getAttr("name"),
  14400. class: "anchorclass"
  14401. });
  14402. a.setAttr("name");
  14403. }
  14404. });
  14405. },
  14406. commands: {
  14407. /**
  14408. * 插入锚点
  14409. * @command anchor
  14410. * @method execCommand
  14411. * @param { String } cmd 命令字符串
  14412. * @param { String } name 锚点名称字符串
  14413. * @example
  14414. * ```javascript
  14415. * //editor 是编辑器实例
  14416. * editor.execCommand('anchor', 'anchor1');
  14417. * ```
  14418. */
  14419. anchor: {
  14420. execCommand: function(cmd, name) {
  14421. var range = this.selection.getRange(),
  14422. img = range.getClosedNode();
  14423. if (img && img.getAttribute("anchorname")) {
  14424. if (name) {
  14425. img.setAttribute("anchorname", name);
  14426. } else {
  14427. range.setStartBefore(img).setCursor();
  14428. domUtils.remove(img);
  14429. }
  14430. } else {
  14431. if (name) {
  14432. //只在选区的开始插入
  14433. var anchor = this.document.createElement("img");
  14434. range.collapse(true);
  14435. domUtils.setAttributes(anchor, {
  14436. anchorname: name,
  14437. class: "anchorclass"
  14438. });
  14439. range
  14440. .insertNode(anchor)
  14441. .setStartAfter(anchor)
  14442. .setCursor(false, true);
  14443. }
  14444. }
  14445. }
  14446. }
  14447. }
  14448. };
  14449. });
  14450. // plugins/wordcount.js
  14451. ///import core
  14452. ///commands 字数统计
  14453. ///commandsName WordCount,wordCount
  14454. ///commandsTitle 字数统计
  14455. /*
  14456. * Created by JetBrains WebStorm.
  14457. * User: taoqili
  14458. * Date: 11-9-7
  14459. * Time: 下午8:18
  14460. * To change this template use File | Settings | File Templates.
  14461. */
  14462. UE.plugins["wordcount"] = function() {
  14463. var me = this;
  14464. me.setOpt("wordCount", true);
  14465. me.addListener("contentchange", function() {
  14466. me.fireEvent("wordcount");
  14467. });
  14468. var timer;
  14469. me.addListener("ready", function() {
  14470. var me = this;
  14471. domUtils.on(me.body, "keyup", function(evt) {
  14472. var code = evt.keyCode || evt.which,
  14473. //忽略的按键,ctr,alt,shift,方向键
  14474. ignores = {
  14475. "16": 1,
  14476. "18": 1,
  14477. "20": 1,
  14478. "37": 1,
  14479. "38": 1,
  14480. "39": 1,
  14481. "40": 1
  14482. };
  14483. if (code in ignores) return;
  14484. clearTimeout(timer);
  14485. timer = setTimeout(function() {
  14486. me.fireEvent("wordcount");
  14487. }, 200);
  14488. });
  14489. });
  14490. };
  14491. // plugins/pagebreak.js
  14492. /**
  14493. * 分页功能插件
  14494. * @file
  14495. * @since 1.2.6.1
  14496. */
  14497. UE.plugins["pagebreak"] = function() {
  14498. var me = this,
  14499. notBreakTags = ["td"];
  14500. me.setOpt("pageBreakTag", "_ueditor_page_break_tag_");
  14501. function fillNode(node) {
  14502. if (domUtils.isEmptyBlock(node)) {
  14503. var firstChild = node.firstChild,
  14504. tmpNode;
  14505. while (
  14506. firstChild &&
  14507. firstChild.nodeType == 1 &&
  14508. domUtils.isEmptyBlock(firstChild)
  14509. ) {
  14510. tmpNode = firstChild;
  14511. firstChild = firstChild.firstChild;
  14512. }
  14513. !tmpNode && (tmpNode = node);
  14514. domUtils.fillNode(me.document, tmpNode);
  14515. }
  14516. }
  14517. //分页符样式添加
  14518. me.ready(function() {
  14519. utils.cssRule(
  14520. "pagebreak",
  14521. ".pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}",
  14522. me.document
  14523. );
  14524. });
  14525. function isHr(node) {
  14526. return (
  14527. node &&
  14528. node.nodeType == 1 &&
  14529. node.tagName == "HR" &&
  14530. node.className == "pagebreak"
  14531. );
  14532. }
  14533. me.addInputRule(function(root) {
  14534. root.traversal(function(node) {
  14535. if (node.type == "text" && node.data == me.options.pageBreakTag) {
  14536. var hr = UE.uNode.createElement(
  14537. '<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">'
  14538. );
  14539. node.parentNode.insertBefore(hr, node);
  14540. node.parentNode.removeChild(node);
  14541. }
  14542. });
  14543. });
  14544. me.addOutputRule(function(node) {
  14545. utils.each(node.getNodesByTagName("hr"), function(n) {
  14546. if (n.getAttr("class") == "pagebreak") {
  14547. var txt = UE.uNode.createText(me.options.pageBreakTag);
  14548. n.parentNode.insertBefore(txt, n);
  14549. n.parentNode.removeChild(n);
  14550. }
  14551. });
  14552. });
  14553. /**
  14554. * 插入分页符
  14555. * @command pagebreak
  14556. * @method execCommand
  14557. * @param { String } cmd 命令字符串
  14558. * @remind 在表格中插入分页符会把表格切分成两部分
  14559. * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串,
  14560. * 以便于提交数据到服务器端后处理分页。
  14561. * @example
  14562. * ```javascript
  14563. * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
  14564. * ```
  14565. */
  14566. me.commands["pagebreak"] = {
  14567. execCommand: function() {
  14568. var range = me.selection.getRange(),
  14569. hr = me.document.createElement("hr");
  14570. domUtils.setAttributes(hr, {
  14571. class: "pagebreak",
  14572. noshade: "noshade",
  14573. size: "5"
  14574. });
  14575. domUtils.unSelectable(hr);
  14576. //table单独处理
  14577. var node = domUtils.findParentByTagName(
  14578. range.startContainer,
  14579. notBreakTags,
  14580. true
  14581. ),
  14582. parents = [],
  14583. pN;
  14584. if (node) {
  14585. switch (node.tagName) {
  14586. case "TD":
  14587. pN = node.parentNode;
  14588. if (!pN.previousSibling) {
  14589. var table = domUtils.findParentByTagName(pN, "table");
  14590. // var tableWrapDiv = table.parentNode;
  14591. // if(tableWrapDiv && tableWrapDiv.nodeType == 1
  14592. // && tableWrapDiv.tagName == 'DIV'
  14593. // && tableWrapDiv.getAttribute('dropdrag')
  14594. // ){
  14595. // domUtils.remove(tableWrapDiv,true);
  14596. // }
  14597. table.parentNode.insertBefore(hr, table);
  14598. parents = domUtils.findParents(hr, true);
  14599. } else {
  14600. pN.parentNode.insertBefore(hr, pN);
  14601. parents = domUtils.findParents(hr);
  14602. }
  14603. pN = parents[1];
  14604. if (hr !== pN) {
  14605. domUtils.breakParent(hr, pN);
  14606. }
  14607. //table要重写绑定一下拖拽
  14608. me.fireEvent("afteradjusttable", me.document);
  14609. }
  14610. } else {
  14611. if (!range.collapsed) {
  14612. range.deleteContents();
  14613. var start = range.startContainer;
  14614. while (
  14615. !domUtils.isBody(start) &&
  14616. domUtils.isBlockElm(start) &&
  14617. domUtils.isEmptyNode(start)
  14618. ) {
  14619. range.setStartBefore(start).collapse(true);
  14620. domUtils.remove(start);
  14621. start = range.startContainer;
  14622. }
  14623. }
  14624. range.insertNode(hr);
  14625. var pN = hr.parentNode,
  14626. nextNode;
  14627. while (!domUtils.isBody(pN)) {
  14628. domUtils.breakParent(hr, pN);
  14629. nextNode = hr.nextSibling;
  14630. if (nextNode && domUtils.isEmptyBlock(nextNode)) {
  14631. domUtils.remove(nextNode);
  14632. }
  14633. pN = hr.parentNode;
  14634. }
  14635. nextNode = hr.nextSibling;
  14636. var pre = hr.previousSibling;
  14637. if (isHr(pre)) {
  14638. domUtils.remove(pre);
  14639. } else {
  14640. pre && fillNode(pre);
  14641. }
  14642. if (!nextNode) {
  14643. var p = me.document.createElement("p");
  14644. hr.parentNode.appendChild(p);
  14645. domUtils.fillNode(me.document, p);
  14646. range.setStart(p, 0).collapse(true);
  14647. } else {
  14648. if (isHr(nextNode)) {
  14649. domUtils.remove(nextNode);
  14650. } else {
  14651. fillNode(nextNode);
  14652. }
  14653. range.setEndAfter(hr).collapse(false);
  14654. }
  14655. range.select(true);
  14656. }
  14657. }
  14658. };
  14659. };
  14660. // plugins/wordimage.js
  14661. ///import core
  14662. ///commands 本地图片引导上传
  14663. ///commandsName WordImage
  14664. ///commandsTitle 本地图片引导上传
  14665. ///commandsDialog dialogs\wordimage
  14666. UE.plugin.register("wordimage", function() {
  14667. var me = this,
  14668. images = [];
  14669. return {
  14670. commands: {
  14671. wordimage: {
  14672. execCommand: function() {
  14673. var images = domUtils.getElementsByTagName(me.body, "img");
  14674. var urlList = [];
  14675. for (var i = 0, ci; (ci = images[i++]); ) {
  14676. var url = ci.getAttribute("word_img");
  14677. url && urlList.push(url);
  14678. }
  14679. return urlList;
  14680. },
  14681. queryCommandState: function() {
  14682. images = domUtils.getElementsByTagName(me.body, "img");
  14683. for (var i = 0, ci; (ci = images[i++]); ) {
  14684. if (ci.getAttribute("word_img")) {
  14685. return 1;
  14686. }
  14687. }
  14688. return -1;
  14689. },
  14690. notNeedUndo: true
  14691. }
  14692. },
  14693. inputRule: function(root) {
  14694. utils.each(root.getNodesByTagName("img"), function(img) {
  14695. var attrs = img.attrs,
  14696. flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
  14697. opt = me.options,
  14698. src = opt.UEDITOR_HOME_URL + "themes/notadd/images/spacer.gif";
  14699. if (attrs["src"] && /^(?:(file:\/+))/.test(attrs["src"])) {
  14700. img.setAttr({
  14701. width: attrs.width,
  14702. height: attrs.height,
  14703. alt: attrs.alt,
  14704. word_img: attrs.src,
  14705. src: src,
  14706. style:
  14707. "background:url(" +
  14708. (flag
  14709. ? opt.themePath + opt.theme + "/images/word.gif"
  14710. : opt.langPath + opt.lang + "/images/localimage.png") +
  14711. ") no-repeat center center;border:1px solid #ddd"
  14712. });
  14713. }
  14714. });
  14715. }
  14716. };
  14717. });
  14718. // plugins/dragdrop.js
  14719. UE.plugins["dragdrop"] = function() {
  14720. var me = this;
  14721. me.ready(function() {
  14722. domUtils.on(this.body, "dragend", function() {
  14723. var rng = me.selection.getRange();
  14724. var node = rng.getClosedNode() || me.selection.getStart();
  14725. if (node && node.tagName == "IMG") {
  14726. var pre = node.previousSibling,
  14727. next;
  14728. while ((next = node.nextSibling)) {
  14729. if (
  14730. next.nodeType == 1 &&
  14731. next.tagName == "SPAN" &&
  14732. !next.firstChild
  14733. ) {
  14734. domUtils.remove(next);
  14735. } else {
  14736. break;
  14737. }
  14738. }
  14739. if (
  14740. ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre)) || !pre) &&
  14741. (!next || (next && !domUtils.isEmptyBlock(next)))
  14742. ) {
  14743. if (pre && pre.tagName == "P" && !domUtils.isEmptyBlock(pre)) {
  14744. pre.appendChild(node);
  14745. domUtils.moveChild(next, pre);
  14746. domUtils.remove(next);
  14747. } else if (
  14748. next &&
  14749. next.tagName == "P" &&
  14750. !domUtils.isEmptyBlock(next)
  14751. ) {
  14752. next.insertBefore(node, next.firstChild);
  14753. }
  14754. if (pre && pre.tagName == "P" && domUtils.isEmptyBlock(pre)) {
  14755. domUtils.remove(pre);
  14756. }
  14757. if (next && next.tagName == "P" && domUtils.isEmptyBlock(next)) {
  14758. domUtils.remove(next);
  14759. }
  14760. rng.selectNode(node).select();
  14761. me.fireEvent("saveScene");
  14762. }
  14763. }
  14764. });
  14765. });
  14766. me.addListener("keyup", function(type, evt) {
  14767. var keyCode = evt.keyCode || evt.which;
  14768. if (keyCode == 13) {
  14769. var rng = me.selection.getRange(),
  14770. node;
  14771. if (
  14772. (node = domUtils.findParentByTagName(rng.startContainer, "p", true))
  14773. ) {
  14774. if (domUtils.getComputedStyle(node, "text-align") == "center") {
  14775. domUtils.removeStyle(node, "text-align");
  14776. }
  14777. }
  14778. }
  14779. });
  14780. };
  14781. // plugins/undo.js
  14782. /**
  14783. * undo redo
  14784. * @file
  14785. * @since 1.2.6.1
  14786. */
  14787. /**
  14788. * 撤销上一次执行的命令
  14789. * @command undo
  14790. * @method execCommand
  14791. * @param { String } cmd 命令字符串
  14792. * @example
  14793. * ```javascript
  14794. * editor.execCommand( 'undo' );
  14795. * ```
  14796. */
  14797. /**
  14798. * 重做上一次执行的命令
  14799. * @command redo
  14800. * @method execCommand
  14801. * @param { String } cmd 命令字符串
  14802. * @example
  14803. * ```javascript
  14804. * editor.execCommand( 'redo' );
  14805. * ```
  14806. */
  14807. UE.plugins["undo"] = function() {
  14808. var saveSceneTimer;
  14809. var me = this,
  14810. maxUndoCount = me.options.maxUndoCount || 20,
  14811. maxInputCount = me.options.maxInputCount || 20,
  14812. fillchar = new RegExp(domUtils.fillChar + "|</hr>", "gi"); // ie会产生多余的</hr>
  14813. var noNeedFillCharTags = {
  14814. ol: 1,
  14815. ul: 1,
  14816. table: 1,
  14817. tbody: 1,
  14818. tr: 1,
  14819. body: 1
  14820. };
  14821. var orgState = me.options.autoClearEmptyNode;
  14822. function compareAddr(indexA, indexB) {
  14823. if (indexA.length != indexB.length) return 0;
  14824. for (var i = 0, l = indexA.length; i < l; i++) {
  14825. if (indexA[i] != indexB[i]) return 0;
  14826. }
  14827. return 1;
  14828. }
  14829. function compareRangeAddress(rngAddrA, rngAddrB) {
  14830. if (rngAddrA.collapsed != rngAddrB.collapsed) {
  14831. return 0;
  14832. }
  14833. if (
  14834. !compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) ||
  14835. !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)
  14836. ) {
  14837. return 0;
  14838. }
  14839. return 1;
  14840. }
  14841. function UndoManager() {
  14842. this.list = [];
  14843. this.index = 0;
  14844. this.hasUndo = false;
  14845. this.hasRedo = false;
  14846. this.undo = function() {
  14847. if (this.hasUndo) {
  14848. if (!this.list[this.index - 1] && this.list.length == 1) {
  14849. this.reset();
  14850. return;
  14851. }
  14852. while (
  14853. this.list[this.index].content == this.list[this.index - 1].content
  14854. ) {
  14855. this.index--;
  14856. if (this.index == 0) {
  14857. return this.restore(0);
  14858. }
  14859. }
  14860. this.restore(--this.index);
  14861. }
  14862. };
  14863. this.redo = function() {
  14864. if (this.hasRedo) {
  14865. while (
  14866. this.list[this.index].content == this.list[this.index + 1].content
  14867. ) {
  14868. this.index++;
  14869. if (this.index == this.list.length - 1) {
  14870. return this.restore(this.index);
  14871. }
  14872. }
  14873. this.restore(++this.index);
  14874. }
  14875. };
  14876. this.restore = function() {
  14877. var me = this.editor;
  14878. var scene = this.list[this.index];
  14879. var root = UE.htmlparser(scene.content.replace(fillchar, ""));
  14880. me.options.autoClearEmptyNode = false;
  14881. me.filterInputRule(root);
  14882. me.options.autoClearEmptyNode = orgState;
  14883. //trace:873
  14884. //去掉展位符
  14885. me.document.body.innerHTML = root.toHtml();
  14886. me.fireEvent("afterscencerestore");
  14887. //处理undo后空格不展位的问题
  14888. if (browser.ie) {
  14889. utils.each(
  14890. domUtils.getElementsByTagName(me.document, "td th caption p"),
  14891. function(node) {
  14892. if (domUtils.isEmptyNode(node)) {
  14893. domUtils.fillNode(me.document, node);
  14894. }
  14895. }
  14896. );
  14897. }
  14898. try {
  14899. var rng = new dom.Range(me.document).moveToAddress(scene.address);
  14900. rng.select(
  14901. noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]
  14902. );
  14903. } catch (e) {}
  14904. this.update();
  14905. this.clearKey();
  14906. //不能把自己reset了
  14907. me.fireEvent("reset", true);
  14908. };
  14909. this.getScene = function() {
  14910. var me = this.editor;
  14911. var rng = me.selection.getRange(),
  14912. rngAddress = rng.createAddress(false, true);
  14913. me.fireEvent("beforegetscene");
  14914. var root = UE.htmlparser(me.body.innerHTML);
  14915. me.options.autoClearEmptyNode = false;
  14916. me.filterOutputRule(root);
  14917. me.options.autoClearEmptyNode = orgState;
  14918. var cont = root.toHtml();
  14919. //trace:3461
  14920. //这个会引起回退时导致空格丢失的情况
  14921. // browser.ie && (cont = cont.replace(/>&nbsp;</g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
  14922. me.fireEvent("aftergetscene");
  14923. return {
  14924. address: rngAddress,
  14925. content: cont
  14926. };
  14927. };
  14928. this.save = function(notCompareRange, notSetCursor) {
  14929. clearTimeout(saveSceneTimer);
  14930. var currentScene = this.getScene(notSetCursor),
  14931. lastScene = this.list[this.index];
  14932. if (lastScene && lastScene.content != currentScene.content) {
  14933. me.trigger("contentchange");
  14934. }
  14935. //内容相同位置相同不存
  14936. if (
  14937. lastScene &&
  14938. lastScene.content == currentScene.content &&
  14939. (notCompareRange
  14940. ? 1
  14941. : compareRangeAddress(lastScene.address, currentScene.address))
  14942. ) {
  14943. return;
  14944. }
  14945. this.list = this.list.slice(0, this.index + 1);
  14946. this.list.push(currentScene);
  14947. //如果大于最大数量了,就把最前的剔除
  14948. if (this.list.length > maxUndoCount) {
  14949. this.list.shift();
  14950. }
  14951. this.index = this.list.length - 1;
  14952. this.clearKey();
  14953. //跟新undo/redo状态
  14954. this.update();
  14955. };
  14956. this.update = function() {
  14957. this.hasRedo = !!this.list[this.index + 1];
  14958. this.hasUndo = !!this.list[this.index - 1];
  14959. };
  14960. this.reset = function() {
  14961. this.list = [];
  14962. this.index = 0;
  14963. this.hasUndo = false;
  14964. this.hasRedo = false;
  14965. this.clearKey();
  14966. };
  14967. this.clearKey = function() {
  14968. keycont = 0;
  14969. lastKeyCode = null;
  14970. };
  14971. }
  14972. me.undoManger = new UndoManager();
  14973. me.undoManger.editor = me;
  14974. function saveScene() {
  14975. this.undoManger.save();
  14976. }
  14977. me.addListener("saveScene", function() {
  14978. var args = Array.prototype.splice.call(arguments, 1);
  14979. this.undoManger.save.apply(this.undoManger, args);
  14980. });
  14981. // me.addListener('beforeexeccommand', saveScene);
  14982. // me.addListener('afterexeccommand', saveScene);
  14983. me.addListener("reset", function(type, exclude) {
  14984. if (!exclude) {
  14985. this.undoManger.reset();
  14986. }
  14987. });
  14988. me.commands["redo"] = me.commands["undo"] = {
  14989. execCommand: function(cmdName) {
  14990. this.undoManger[cmdName]();
  14991. },
  14992. queryCommandState: function(cmdName) {
  14993. return this.undoManger[
  14994. "has" + (cmdName.toLowerCase() == "undo" ? "Undo" : "Redo")
  14995. ]
  14996. ? 0
  14997. : -1;
  14998. },
  14999. notNeedUndo: 1
  15000. };
  15001. var keys = {
  15002. // /*Backspace*/ 8:1, /*Delete*/ 46:1,
  15003. /*Shift*/ 16: 1,
  15004. /*Ctrl*/ 17: 1,
  15005. /*Alt*/ 18: 1,
  15006. 37: 1,
  15007. 38: 1,
  15008. 39: 1,
  15009. 40: 1
  15010. },
  15011. keycont = 0,
  15012. lastKeyCode;
  15013. //输入法状态下不计算字符数
  15014. var inputType = false;
  15015. me.addListener("ready", function() {
  15016. domUtils.on(this.body, "compositionstart", function() {
  15017. inputType = true;
  15018. });
  15019. domUtils.on(this.body, "compositionend", function() {
  15020. inputType = false;
  15021. });
  15022. });
  15023. //快捷键
  15024. me.addshortcutkey({
  15025. Undo: "ctrl+90", //undo
  15026. Redo: "ctrl+89" //redo
  15027. });
  15028. var isCollapsed = true;
  15029. me.addListener("keydown", function(type, evt) {
  15030. var me = this;
  15031. var keyCode = evt.keyCode || evt.which;
  15032. if (
  15033. !keys[keyCode] &&
  15034. !evt.ctrlKey &&
  15035. !evt.metaKey &&
  15036. !evt.shiftKey &&
  15037. !evt.altKey
  15038. ) {
  15039. if (inputType) return;
  15040. if (!me.selection.getRange().collapsed) {
  15041. me.undoManger.save(false, true);
  15042. isCollapsed = false;
  15043. return;
  15044. }
  15045. if (me.undoManger.list.length == 0) {
  15046. me.undoManger.save(true);
  15047. }
  15048. clearTimeout(saveSceneTimer);
  15049. function save(cont) {
  15050. cont.undoManger.save(false, true);
  15051. cont.fireEvent("selectionchange");
  15052. }
  15053. saveSceneTimer = setTimeout(function() {
  15054. if (inputType) {
  15055. var interalTimer = setInterval(function() {
  15056. if (!inputType) {
  15057. save(me);
  15058. clearInterval(interalTimer);
  15059. }
  15060. }, 300);
  15061. return;
  15062. }
  15063. save(me);
  15064. }, 200);
  15065. lastKeyCode = keyCode;
  15066. keycont++;
  15067. if (keycont >= maxInputCount) {
  15068. save(me);
  15069. }
  15070. }
  15071. });
  15072. me.addListener("keyup", function(type, evt) {
  15073. var keyCode = evt.keyCode || evt.which;
  15074. if (
  15075. !keys[keyCode] &&
  15076. !evt.ctrlKey &&
  15077. !evt.metaKey &&
  15078. !evt.shiftKey &&
  15079. !evt.altKey
  15080. ) {
  15081. if (inputType) return;
  15082. if (!isCollapsed) {
  15083. this.undoManger.save(false, true);
  15084. isCollapsed = true;
  15085. }
  15086. }
  15087. });
  15088. //扩展实例,添加关闭和开启命令undo
  15089. me.stopCmdUndo = function() {
  15090. me.__hasEnterExecCommand = true;
  15091. };
  15092. me.startCmdUndo = function() {
  15093. me.__hasEnterExecCommand = false;
  15094. };
  15095. };
  15096. // plugins/copy.js
  15097. UE.plugin.register("copy", function() {
  15098. var me = this;
  15099. function initZeroClipboard() {
  15100. ZeroClipboard.config({
  15101. debug: false,
  15102. swfPath:
  15103. me.options.UEDITOR_HOME_URL +
  15104. "third-party/zeroclipboard/ZeroClipboard.swf"
  15105. });
  15106. var client = (me.zeroclipboard = new ZeroClipboard());
  15107. // 复制内容
  15108. client.on("copy", function(e) {
  15109. var client = e.client,
  15110. rng = me.selection.getRange(),
  15111. div = document.createElement("div");
  15112. div.appendChild(rng.cloneContents());
  15113. client.setText(div.innerText || div.textContent);
  15114. client.setHtml(div.innerHTML);
  15115. rng.select();
  15116. });
  15117. // hover事件传递到target
  15118. client.on("mouseover mouseout", function(e) {
  15119. var target = e.target;
  15120. if (target) {
  15121. if (e.type == "mouseover") {
  15122. domUtils.addClass(target, "edui-state-hover");
  15123. } else if (e.type == "mouseout") {
  15124. domUtils.removeClasses(target, "edui-state-hover");
  15125. }
  15126. }
  15127. });
  15128. // flash加载不成功
  15129. client.on("wrongflash noflash", function() {
  15130. ZeroClipboard.destroy();
  15131. });
  15132. // 触发事件
  15133. me.fireEvent("zeroclipboardready", client);
  15134. }
  15135. return {
  15136. bindEvents: {
  15137. ready: function() {
  15138. if (!browser.ie) {
  15139. if (window.ZeroClipboard) {
  15140. initZeroClipboard();
  15141. } else {
  15142. utils.loadFile(
  15143. document,
  15144. {
  15145. src:
  15146. me.options.UEDITOR_HOME_URL +
  15147. "third-party/zeroclipboard/ZeroClipboard.js",
  15148. tag: "script",
  15149. type: "text/javascript",
  15150. defer: "defer"
  15151. },
  15152. function() {
  15153. initZeroClipboard();
  15154. }
  15155. );
  15156. }
  15157. }
  15158. }
  15159. },
  15160. commands: {
  15161. copy: {
  15162. execCommand: function(cmd) {
  15163. if (!me.document.execCommand("copy")) {
  15164. alert(me.getLang("copymsg"));
  15165. }
  15166. }
  15167. }
  15168. }
  15169. };
  15170. });
  15171. // plugins/paste.js
  15172. ///import core
  15173. ///import plugins/inserthtml.js
  15174. ///import plugins/undo.js
  15175. ///import plugins/serialize.js
  15176. ///commands 粘贴
  15177. ///commandsName PastePlain
  15178. ///commandsTitle 纯文本粘贴模式
  15179. /**
  15180. * @description 粘贴
  15181. * @author zhanyi
  15182. */
  15183. UE.plugins["paste"] = function() {
  15184. function getClipboardData(callback) {
  15185. var doc = this.document;
  15186. if (doc.getElementById("baidu_pastebin")) {
  15187. return;
  15188. }
  15189. var range = this.selection.getRange(),
  15190. bk = range.createBookmark(),
  15191. //创建剪贴的容器div
  15192. pastebin = doc.createElement("div");
  15193. pastebin.id = "baidu_pastebin";
  15194. // Safari 要求div必须有内容,才能粘贴内容进来
  15195. browser.webkit &&
  15196. pastebin.appendChild(
  15197. doc.createTextNode(domUtils.fillChar + domUtils.fillChar)
  15198. );
  15199. doc.body.appendChild(pastebin);
  15200. //trace:717 隐藏的span不能得到top
  15201. //bk.start.innerHTML = '&nbsp;';
  15202. bk.start.style.display = "";
  15203. pastebin.style.cssText =
  15204. "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
  15205. //要在现在光标平行的位置加入,否则会出现跳动的问题
  15206. domUtils.getXY(bk.start).y +
  15207. "px";
  15208. range.selectNodeContents(pastebin).select(true);
  15209. setTimeout(function() {
  15210. if (browser.webkit) {
  15211. for (
  15212. var i = 0, pastebins = doc.querySelectorAll("#baidu_pastebin"), pi;
  15213. (pi = pastebins[i++]);
  15214. ) {
  15215. if (domUtils.isEmptyNode(pi)) {
  15216. domUtils.remove(pi);
  15217. } else {
  15218. pastebin = pi;
  15219. break;
  15220. }
  15221. }
  15222. }
  15223. try {
  15224. pastebin.parentNode.removeChild(pastebin);
  15225. } catch (e) {}
  15226. range.moveToBookmark(bk).select(true);
  15227. callback(pastebin);
  15228. }, 0);
  15229. }
  15230. var me = this;
  15231. me.setOpt({
  15232. retainOnlyLabelPasted: false
  15233. });
  15234. var txtContent, htmlContent, address;
  15235. function getPureHtml(html) {
  15236. return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function(
  15237. a,
  15238. b,
  15239. tagName,
  15240. attrs
  15241. ) {
  15242. tagName = tagName.toLowerCase();
  15243. if ({ img: 1 }[tagName]) {
  15244. return a;
  15245. }
  15246. attrs = attrs.replace(
  15247. /([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi,
  15248. function(str, atr, val) {
  15249. if (
  15250. {
  15251. src: 1,
  15252. href: 1,
  15253. name: 1
  15254. }[atr.toLowerCase()]
  15255. ) {
  15256. return atr + "=" + val + " ";
  15257. }
  15258. return "";
  15259. }
  15260. );
  15261. if (
  15262. {
  15263. span: 1,
  15264. div: 1
  15265. }[tagName]
  15266. ) {
  15267. return "";
  15268. } else {
  15269. return "<" + b + tagName + " " + utils.trim(attrs) + ">";
  15270. }
  15271. });
  15272. }
  15273. function filter(div) {
  15274. var html;
  15275. if (div.firstChild) {
  15276. //去掉cut中添加的边界值
  15277. var nodes = domUtils.getElementsByTagName(div, "span");
  15278. for (var i = 0, ni; (ni = nodes[i++]); ) {
  15279. if (ni.id == "_baidu_cut_start" || ni.id == "_baidu_cut_end") {
  15280. domUtils.remove(ni);
  15281. }
  15282. }
  15283. if (browser.webkit) {
  15284. var brs = div.querySelectorAll("div br");
  15285. for (var i = 0, bi; (bi = brs[i++]); ) {
  15286. var pN = bi.parentNode;
  15287. if (pN.tagName == "DIV" && pN.childNodes.length == 1) {
  15288. pN.innerHTML = "<p><br/></p>";
  15289. domUtils.remove(pN);
  15290. }
  15291. }
  15292. var divs = div.querySelectorAll("#baidu_pastebin");
  15293. for (var i = 0, di; (di = divs[i++]); ) {
  15294. var tmpP = me.document.createElement("p");
  15295. di.parentNode.insertBefore(tmpP, di);
  15296. while (di.firstChild) {
  15297. tmpP.appendChild(di.firstChild);
  15298. }
  15299. domUtils.remove(di);
  15300. }
  15301. var metas = div.querySelectorAll("meta");
  15302. for (var i = 0, ci; (ci = metas[i++]); ) {
  15303. domUtils.remove(ci);
  15304. }
  15305. var brs = div.querySelectorAll("br");
  15306. for (i = 0; (ci = brs[i++]); ) {
  15307. if (/^apple-/i.test(ci.className)) {
  15308. domUtils.remove(ci);
  15309. }
  15310. }
  15311. }
  15312. if (browser.gecko) {
  15313. var dirtyNodes = div.querySelectorAll("[_moz_dirty]");
  15314. for (i = 0; (ci = dirtyNodes[i++]); ) {
  15315. ci.removeAttribute("_moz_dirty");
  15316. }
  15317. }
  15318. if (!browser.ie) {
  15319. var spans = div.querySelectorAll("span.Apple-style-span");
  15320. for (var i = 0, ci; (ci = spans[i++]); ) {
  15321. domUtils.remove(ci, true);
  15322. }
  15323. }
  15324. //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
  15325. html = div.innerHTML; //.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
  15326. //过滤word粘贴过来的冗余属性
  15327. html = UE.filterWord(html);
  15328. //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
  15329. var root = UE.htmlparser(html);
  15330. //如果给了过滤规则就先进行过滤
  15331. if (me.options.filterRules) {
  15332. UE.filterNode(root, me.options.filterRules);
  15333. }
  15334. //执行默认的处理
  15335. me.filterInputRule(root);
  15336. //针对chrome的处理
  15337. if (browser.webkit) {
  15338. var br = root.lastChild();
  15339. if (br && br.type == "element" && br.tagName == "br") {
  15340. root.removeChild(br);
  15341. }
  15342. utils.each(me.body.querySelectorAll("div"), function(node) {
  15343. if (domUtils.isEmptyBlock(node)) {
  15344. domUtils.remove(node, true);
  15345. }
  15346. });
  15347. }
  15348. html = { html: root.toHtml() };
  15349. me.fireEvent("beforepaste", html, root);
  15350. //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
  15351. if (!html.html) {
  15352. return;
  15353. }
  15354. root = UE.htmlparser(html.html, true);
  15355. //如果开启了纯文本模式
  15356. if (me.queryCommandState("pasteplain") === 1) {
  15357. me.execCommand(
  15358. "insertHtml",
  15359. UE.filterNode(root, me.options.filterTxtRules).toHtml(),
  15360. true
  15361. );
  15362. } else {
  15363. //文本模式
  15364. UE.filterNode(root, me.options.filterTxtRules);
  15365. txtContent = root.toHtml();
  15366. //完全模式
  15367. htmlContent = html.html;
  15368. address = me.selection.getRange().createAddress(true);
  15369. me.execCommand(
  15370. "insertHtml",
  15371. me.getOpt("retainOnlyLabelPasted") === true
  15372. ? getPureHtml(htmlContent)
  15373. : htmlContent,
  15374. true
  15375. );
  15376. }
  15377. me.fireEvent("afterpaste", html);
  15378. }
  15379. }
  15380. me.addListener("pasteTransfer", function(cmd, plainType) {
  15381. if (address && txtContent && htmlContent && txtContent != htmlContent) {
  15382. var range = me.selection.getRange();
  15383. range.moveToAddress(address, true);
  15384. if (!range.collapsed) {
  15385. while (!domUtils.isBody(range.startContainer)) {
  15386. var start = range.startContainer;
  15387. if (start.nodeType == 1) {
  15388. start = start.childNodes[range.startOffset];
  15389. if (!start) {
  15390. range.setStartBefore(range.startContainer);
  15391. continue;
  15392. }
  15393. var pre = start.previousSibling;
  15394. if (
  15395. pre &&
  15396. pre.nodeType == 3 &&
  15397. new RegExp("^[\n\r\t " + domUtils.fillChar + "]*$").test(
  15398. pre.nodeValue
  15399. )
  15400. ) {
  15401. range.setStartBefore(pre);
  15402. }
  15403. }
  15404. if (range.startOffset == 0) {
  15405. range.setStartBefore(range.startContainer);
  15406. } else {
  15407. break;
  15408. }
  15409. }
  15410. while (!domUtils.isBody(range.endContainer)) {
  15411. var end = range.endContainer;
  15412. if (end.nodeType == 1) {
  15413. end = end.childNodes[range.endOffset];
  15414. if (!end) {
  15415. range.setEndAfter(range.endContainer);
  15416. continue;
  15417. }
  15418. var next = end.nextSibling;
  15419. if (
  15420. next &&
  15421. next.nodeType == 3 &&
  15422. new RegExp("^[\n\r\t" + domUtils.fillChar + "]*$").test(
  15423. next.nodeValue
  15424. )
  15425. ) {
  15426. range.setEndAfter(next);
  15427. }
  15428. }
  15429. if (
  15430. range.endOffset ==
  15431. range.endContainer[
  15432. range.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  15433. ].length
  15434. ) {
  15435. range.setEndAfter(range.endContainer);
  15436. } else {
  15437. break;
  15438. }
  15439. }
  15440. }
  15441. range.deleteContents();
  15442. range.select(true);
  15443. me.__hasEnterExecCommand = true;
  15444. var html = htmlContent;
  15445. if (plainType === 2) {
  15446. html = getPureHtml(html);
  15447. } else if (plainType) {
  15448. html = txtContent;
  15449. }
  15450. me.execCommand("inserthtml", html, true);
  15451. me.__hasEnterExecCommand = false;
  15452. var rng = me.selection.getRange();
  15453. while (
  15454. !domUtils.isBody(rng.startContainer) &&
  15455. !rng.startOffset &&
  15456. rng.startContainer[
  15457. rng.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
  15458. ].length
  15459. ) {
  15460. rng.setStartBefore(rng.startContainer);
  15461. }
  15462. var tmpAddress = rng.createAddress(true);
  15463. address.endAddress = tmpAddress.startAddress;
  15464. }
  15465. });
  15466. me.addListener("ready", function() {
  15467. domUtils.on(me.body, "cut", function() {
  15468. var range = me.selection.getRange();
  15469. if (!range.collapsed && me.undoManger) {
  15470. me.undoManger.save();
  15471. }
  15472. });
  15473. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  15474. domUtils.on(
  15475. me.body,
  15476. browser.ie || browser.opera ? "keydown" : "paste",
  15477. function(e) {
  15478. if (
  15479. (browser.ie || browser.opera) &&
  15480. ((!e.ctrlKey && !e.metaKey) || e.keyCode != "86")
  15481. ) {
  15482. return;
  15483. }
  15484. getClipboardData.call(me, function(div) {
  15485. filter(div);
  15486. });
  15487. }
  15488. );
  15489. });
  15490. me.commands["paste"] = {
  15491. execCommand: function(cmd) {
  15492. if (browser.ie) {
  15493. getClipboardData.call(me, function(div) {
  15494. filter(div);
  15495. });
  15496. me.document.execCommand("paste");
  15497. } else {
  15498. alert(me.getLang("pastemsg"));
  15499. }
  15500. }
  15501. };
  15502. };
  15503. // plugins/puretxtpaste.js
  15504. /**
  15505. * 纯文本粘贴插件
  15506. * @file
  15507. * @since 1.2.6.1
  15508. */
  15509. UE.plugins["pasteplain"] = function() {
  15510. var me = this;
  15511. me.setOpt({
  15512. pasteplain: false,
  15513. filterTxtRules: (function() {
  15514. function transP(node) {
  15515. node.tagName = "p";
  15516. node.setStyle();
  15517. }
  15518. function removeNode(node) {
  15519. node.parentNode.removeChild(node, true);
  15520. }
  15521. return {
  15522. //直接删除及其字节点内容
  15523. "-": "script style object iframe embed input select",
  15524. p: { $: {} },
  15525. br: { $: {} },
  15526. div: function(node) {
  15527. var tmpNode,
  15528. p = UE.uNode.createElement("p");
  15529. while ((tmpNode = node.firstChild())) {
  15530. if (tmpNode.type == "text" || !UE.dom.dtd.$block[tmpNode.tagName]) {
  15531. p.appendChild(tmpNode);
  15532. } else {
  15533. if (p.firstChild()) {
  15534. node.parentNode.insertBefore(p, node);
  15535. p = UE.uNode.createElement("p");
  15536. } else {
  15537. node.parentNode.insertBefore(tmpNode, node);
  15538. }
  15539. }
  15540. }
  15541. if (p.firstChild()) {
  15542. node.parentNode.insertBefore(p, node);
  15543. }
  15544. node.parentNode.removeChild(node);
  15545. },
  15546. ol: removeNode,
  15547. ul: removeNode,
  15548. dl: removeNode,
  15549. dt: removeNode,
  15550. dd: removeNode,
  15551. li: removeNode,
  15552. caption: transP,
  15553. th: transP,
  15554. tr: transP,
  15555. h1: transP,
  15556. h2: transP,
  15557. h3: transP,
  15558. h4: transP,
  15559. h5: transP,
  15560. h6: transP,
  15561. td: function(node) {
  15562. //没有内容的td直接删掉
  15563. var txt = !!node.innerText();
  15564. if (txt) {
  15565. node.parentNode.insertAfter(
  15566. UE.uNode.createText(" &nbsp; &nbsp;"),
  15567. node
  15568. );
  15569. }
  15570. node.parentNode.removeChild(node, node.innerText());
  15571. }
  15572. };
  15573. })()
  15574. });
  15575. //暂时这里支持一下老版本的属性
  15576. var pasteplain = me.options.pasteplain;
  15577. /**
  15578. * 启用或取消纯文本粘贴模式
  15579. * @command pasteplain
  15580. * @method execCommand
  15581. * @param { String } cmd 命令字符串
  15582. * @example
  15583. * ```javascript
  15584. * editor.queryCommandState( 'pasteplain' );
  15585. * ```
  15586. */
  15587. /**
  15588. * 查询当前是否处于纯文本粘贴模式
  15589. * @command pasteplain
  15590. * @method queryCommandState
  15591. * @param { String } cmd 命令字符串
  15592. * @return { int } 如果处于纯文本模式,返回1,否则,返回0
  15593. * @example
  15594. * ```javascript
  15595. * editor.queryCommandState( 'pasteplain' );
  15596. * ```
  15597. */
  15598. me.commands["pasteplain"] = {
  15599. queryCommandState: function() {
  15600. return pasteplain ? 1 : 0;
  15601. },
  15602. execCommand: function() {
  15603. pasteplain = !pasteplain | 0;
  15604. },
  15605. notNeedUndo: 1
  15606. };
  15607. };
  15608. // plugins/list.js
  15609. /**
  15610. * 有序列表,无序列表插件
  15611. * @file
  15612. * @since 1.2.6.1
  15613. */
  15614. UE.plugins["list"] = function() {
  15615. var me = this,
  15616. notExchange = {
  15617. TD: 1,
  15618. PRE: 1,
  15619. BLOCKQUOTE: 1
  15620. };
  15621. var customStyle = {
  15622. cn: "cn-1-",
  15623. cn1: "cn-2-",
  15624. cn2: "cn-3-",
  15625. num: "num-1-",
  15626. num1: "num-2-",
  15627. num2: "num-3-",
  15628. dash: "dash",
  15629. dot: "dot"
  15630. };
  15631. me.setOpt({
  15632. autoTransWordToList: false,
  15633. insertorderedlist: {
  15634. num: "",
  15635. num1: "",
  15636. num2: "",
  15637. cn: "",
  15638. cn1: "",
  15639. cn2: "",
  15640. decimal: "",
  15641. "lower-alpha": "",
  15642. "lower-roman": "",
  15643. "upper-alpha": "",
  15644. "upper-roman": ""
  15645. },
  15646. insertunorderedlist: {
  15647. circle: "",
  15648. disc: "",
  15649. square: "",
  15650. dash: "",
  15651. dot: ""
  15652. },
  15653. listDefaultPaddingLeft: "30",
  15654. listiconpath: "http://bs.baidu.com/listicon/",
  15655. maxListLevel: -1, //-1不限制
  15656. disablePInList: false
  15657. });
  15658. function listToArray(list) {
  15659. var arr = [];
  15660. for (var p in list) {
  15661. arr.push(p);
  15662. }
  15663. return arr;
  15664. }
  15665. var listStyle = {
  15666. OL: listToArray(me.options.insertorderedlist),
  15667. UL: listToArray(me.options.insertunorderedlist)
  15668. };
  15669. var liiconpath = me.options.listiconpath;
  15670. //根据用户配置,调整customStyle
  15671. for (var s in customStyle) {
  15672. if (
  15673. !me.options.insertorderedlist.hasOwnProperty(s) &&
  15674. !me.options.insertunorderedlist.hasOwnProperty(s)
  15675. ) {
  15676. delete customStyle[s];
  15677. }
  15678. }
  15679. me.ready(function() {
  15680. var customCss = [];
  15681. for (var p in customStyle) {
  15682. if (p == "dash" || p == "dot") {
  15683. customCss.push(
  15684. "li.list-" +
  15685. customStyle[p] +
  15686. "{background-image:url(" +
  15687. liiconpath +
  15688. customStyle[p] +
  15689. ".gif)}"
  15690. );
  15691. customCss.push(
  15692. "ul.custom_" +
  15693. p +
  15694. "{list-style:none;}ul.custom_" +
  15695. p +
  15696. " li{background-position:0 3px;background-repeat:no-repeat}"
  15697. );
  15698. } else {
  15699. for (var i = 0; i < 99; i++) {
  15700. customCss.push(
  15701. "li.list-" +
  15702. customStyle[p] +
  15703. i +
  15704. "{background-image:url(" +
  15705. liiconpath +
  15706. "list-" +
  15707. customStyle[p] +
  15708. i +
  15709. ".gif)}"
  15710. );
  15711. }
  15712. customCss.push(
  15713. "ol.custom_" +
  15714. p +
  15715. "{list-style:none;}ol.custom_" +
  15716. p +
  15717. " li{background-position:0 3px;background-repeat:no-repeat}"
  15718. );
  15719. }
  15720. switch (p) {
  15721. case "cn":
  15722. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:25px}");
  15723. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
  15724. customCss.push("li.list-" + p + "-paddingleft-3{padding-left:55px}");
  15725. break;
  15726. case "cn1":
  15727. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:30px}");
  15728. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
  15729. customCss.push("li.list-" + p + "-paddingleft-3{padding-left:55px}");
  15730. break;
  15731. case "cn2":
  15732. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:40px}");
  15733. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:55px}");
  15734. customCss.push("li.list-" + p + "-paddingleft-3{padding-left:68px}");
  15735. break;
  15736. case "num":
  15737. case "num1":
  15738. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:25px}");
  15739. break;
  15740. case "num2":
  15741. customCss.push("li.list-" + p + "-paddingleft-1{padding-left:35px}");
  15742. customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
  15743. break;
  15744. case "dash":
  15745. customCss.push("li.list-" + p + "-paddingleft{padding-left:35px}");
  15746. break;
  15747. case "dot":
  15748. customCss.push("li.list-" + p + "-paddingleft{padding-left:20px}");
  15749. }
  15750. }
  15751. customCss.push(".list-paddingleft-1{padding-left:0}");
  15752. customCss.push(
  15753. ".list-paddingleft-2{padding-left:" +
  15754. me.options.listDefaultPaddingLeft +
  15755. "px}"
  15756. );
  15757. customCss.push(
  15758. ".list-paddingleft-3{padding-left:" +
  15759. me.options.listDefaultPaddingLeft * 2 +
  15760. "px}"
  15761. );
  15762. //如果不给宽度会在自定应样式里出现滚动条
  15763. utils.cssRule(
  15764. "list",
  15765. "ol,ul{margin:0;pading:0;" +
  15766. (browser.ie ? "" : "width:95%") +
  15767. "}li{clear:both;}" +
  15768. customCss.join("\n"),
  15769. me.document
  15770. );
  15771. });
  15772. //单独处理剪切的问题
  15773. me.ready(function() {
  15774. domUtils.on(me.body, "cut", function() {
  15775. setTimeout(function() {
  15776. var rng = me.selection.getRange(),
  15777. li;
  15778. //trace:3416
  15779. if (!rng.collapsed) {
  15780. if (
  15781. (li = domUtils.findParentByTagName(rng.startContainer, "li", true))
  15782. ) {
  15783. if (!li.nextSibling && domUtils.isEmptyBlock(li)) {
  15784. var pn = li.parentNode,
  15785. node;
  15786. if ((node = pn.previousSibling)) {
  15787. domUtils.remove(pn);
  15788. rng.setStartAtLast(node).collapse(true);
  15789. rng.select(true);
  15790. } else if ((node = pn.nextSibling)) {
  15791. domUtils.remove(pn);
  15792. rng.setStartAtFirst(node).collapse(true);
  15793. rng.select(true);
  15794. } else {
  15795. var tmpNode = me.document.createElement("p");
  15796. domUtils.fillNode(me.document, tmpNode);
  15797. pn.parentNode.insertBefore(tmpNode, pn);
  15798. domUtils.remove(pn);
  15799. rng.setStart(tmpNode, 0).collapse(true);
  15800. rng.select(true);
  15801. }
  15802. }
  15803. }
  15804. }
  15805. });
  15806. });
  15807. });
  15808. function getStyle(node) {
  15809. var cls = node.className;
  15810. if (domUtils.hasClass(node, /custom_/)) {
  15811. return cls.match(/custom_(\w+)/)[1];
  15812. }
  15813. return domUtils.getStyle(node, "list-style-type");
  15814. }
  15815. me.addListener("beforepaste", function(type, html) {
  15816. var me = this,
  15817. rng = me.selection.getRange(),
  15818. li;
  15819. var root = UE.htmlparser(html.html, true);
  15820. if ((li = domUtils.findParentByTagName(rng.startContainer, "li", true))) {
  15821. var list = li.parentNode,
  15822. tagName = list.tagName == "OL" ? "ul" : "ol";
  15823. utils.each(root.getNodesByTagName(tagName), function(n) {
  15824. n.tagName = list.tagName;
  15825. n.setAttr();
  15826. if (n.parentNode === root) {
  15827. type = getStyle(list) || (list.tagName == "OL" ? "decimal" : "disc");
  15828. } else {
  15829. var className = n.parentNode.getAttr("class");
  15830. if (className && /custom_/.test(className)) {
  15831. type = className.match(/custom_(\w+)/)[1];
  15832. } else {
  15833. type = n.parentNode.getStyle("list-style-type");
  15834. }
  15835. if (!type) {
  15836. type = list.tagName == "OL" ? "decimal" : "disc";
  15837. }
  15838. }
  15839. var index = utils.indexOf(listStyle[list.tagName], type);
  15840. if (n.parentNode !== root)
  15841. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  15842. var currentStyle = listStyle[list.tagName][index];
  15843. if (customStyle[currentStyle]) {
  15844. n.setAttr("class", "custom_" + currentStyle);
  15845. } else {
  15846. n.setStyle("list-style-type", currentStyle);
  15847. }
  15848. });
  15849. }
  15850. html.html = root.toHtml();
  15851. });
  15852. //导出时,去掉p标签
  15853. me.getOpt("disablePInList") === true &&
  15854. me.addOutputRule(function(root) {
  15855. utils.each(root.getNodesByTagName("li"), function(li) {
  15856. var newChildrens = [],
  15857. index = 0;
  15858. utils.each(li.children, function(n) {
  15859. if (n.tagName == "p") {
  15860. var tmpNode;
  15861. while ((tmpNode = n.children.pop())) {
  15862. newChildrens.splice(index, 0, tmpNode);
  15863. tmpNode.parentNode = li;
  15864. lastNode = tmpNode;
  15865. }
  15866. tmpNode = newChildrens[newChildrens.length - 1];
  15867. if (
  15868. !tmpNode ||
  15869. tmpNode.type != "element" ||
  15870. tmpNode.tagName != "br"
  15871. ) {
  15872. var br = UE.uNode.createElement("br");
  15873. br.parentNode = li;
  15874. newChildrens.push(br);
  15875. }
  15876. index = newChildrens.length;
  15877. }
  15878. });
  15879. if (newChildrens.length) {
  15880. li.children = newChildrens;
  15881. }
  15882. });
  15883. });
  15884. //进入编辑器的li要套p标签
  15885. me.addInputRule(function(root) {
  15886. utils.each(root.getNodesByTagName("li"), function(li) {
  15887. var tmpP = UE.uNode.createElement("p");
  15888. for (var i = 0, ci; (ci = li.children[i]); ) {
  15889. if (ci.type == "text" || dtd.p[ci.tagName]) {
  15890. tmpP.appendChild(ci);
  15891. } else {
  15892. if (tmpP.firstChild()) {
  15893. li.insertBefore(tmpP, ci);
  15894. tmpP = UE.uNode.createElement("p");
  15895. i = i + 2;
  15896. } else {
  15897. i++;
  15898. }
  15899. }
  15900. }
  15901. if ((tmpP.firstChild() && !tmpP.parentNode) || !li.firstChild()) {
  15902. li.appendChild(tmpP);
  15903. }
  15904. //trace:3357
  15905. //p不能为空
  15906. if (!tmpP.firstChild()) {
  15907. tmpP.innerHTML(browser.ie ? "&nbsp;" : "<br/>");
  15908. }
  15909. //去掉末尾的空白
  15910. var p = li.firstChild();
  15911. var lastChild = p.lastChild();
  15912. if (
  15913. lastChild &&
  15914. lastChild.type == "text" &&
  15915. /^\s*$/.test(lastChild.data)
  15916. ) {
  15917. p.removeChild(lastChild);
  15918. }
  15919. });
  15920. if (me.options.autoTransWordToList) {
  15921. var orderlisttype = {
  15922. num1: /^\d+\)/,
  15923. decimal: /^\d+\./,
  15924. "lower-alpha": /^[a-z]+\)/,
  15925. "upper-alpha": /^[A-Z]+\./,
  15926. cn: /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
  15927. cn2: /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
  15928. },
  15929. unorderlisttype = {
  15930. square: "n"
  15931. };
  15932. function checkListType(content, container) {
  15933. var span = container.firstChild();
  15934. if (
  15935. span &&
  15936. span.type == "element" &&
  15937. span.tagName == "span" &&
  15938. /Wingdings|Symbol/.test(span.getStyle("font-family"))
  15939. ) {
  15940. for (var p in unorderlisttype) {
  15941. if (unorderlisttype[p] == span.data) {
  15942. return p;
  15943. }
  15944. }
  15945. return "disc";
  15946. }
  15947. for (var p in orderlisttype) {
  15948. if (orderlisttype[p].test(content)) {
  15949. return p;
  15950. }
  15951. }
  15952. }
  15953. utils.each(root.getNodesByTagName("p"), function(node) {
  15954. if (node.getAttr("class") != "MsoListParagraph") {
  15955. return;
  15956. }
  15957. //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
  15958. node.setStyle("margin", "");
  15959. node.setStyle("margin-left", "");
  15960. node.setAttr("class", "");
  15961. function appendLi(list, p, type) {
  15962. if (list.tagName == "ol") {
  15963. if (browser.ie) {
  15964. var first = p.firstChild();
  15965. if (
  15966. first.type == "element" &&
  15967. first.tagName == "span" &&
  15968. orderlisttype[type].test(first.innerText())
  15969. ) {
  15970. p.removeChild(first);
  15971. }
  15972. } else {
  15973. p.innerHTML(p.innerHTML().replace(orderlisttype[type], ""));
  15974. }
  15975. } else {
  15976. p.removeChild(p.firstChild());
  15977. }
  15978. var li = UE.uNode.createElement("li");
  15979. li.appendChild(p);
  15980. list.appendChild(li);
  15981. }
  15982. var tmp = node,
  15983. type,
  15984. cacheNode = node;
  15985. if (
  15986. node.parentNode.tagName != "li" &&
  15987. (type = checkListType(node.innerText(), node))
  15988. ) {
  15989. var list = UE.uNode.createElement(
  15990. me.options.insertorderedlist.hasOwnProperty(type) ? "ol" : "ul"
  15991. );
  15992. if (customStyle[type]) {
  15993. list.setAttr("class", "custom_" + type);
  15994. } else {
  15995. list.setStyle("list-style-type", type);
  15996. }
  15997. while (
  15998. node &&
  15999. node.parentNode.tagName != "li" &&
  16000. checkListType(node.innerText(), node)
  16001. ) {
  16002. tmp = node.nextSibling();
  16003. if (!tmp) {
  16004. node.parentNode.insertBefore(list, node);
  16005. }
  16006. appendLi(list, node, type);
  16007. node = tmp;
  16008. }
  16009. if (!list.parentNode && node && node.parentNode) {
  16010. node.parentNode.insertBefore(list, node);
  16011. }
  16012. }
  16013. var span = cacheNode.firstChild();
  16014. if (
  16015. span &&
  16016. span.type == "element" &&
  16017. span.tagName == "span" &&
  16018. /^\s*(&nbsp;)+\s*$/.test(span.innerText())
  16019. ) {
  16020. span.parentNode.removeChild(span);
  16021. }
  16022. });
  16023. }
  16024. });
  16025. //调整索引标签
  16026. me.addListener("contentchange", function() {
  16027. adjustListStyle(me.document);
  16028. });
  16029. function adjustListStyle(doc, ignore) {
  16030. utils.each(domUtils.getElementsByTagName(doc, "ol ul"), function(node) {
  16031. if (!domUtils.inDoc(node, doc)) return;
  16032. var parent = node.parentNode;
  16033. if (parent.tagName == node.tagName) {
  16034. var nodeStyleType =
  16035. getStyle(node) || (node.tagName == "OL" ? "decimal" : "disc"),
  16036. parentStyleType =
  16037. getStyle(parent) || (parent.tagName == "OL" ? "decimal" : "disc");
  16038. if (nodeStyleType == parentStyleType) {
  16039. var styleIndex = utils.indexOf(
  16040. listStyle[node.tagName],
  16041. nodeStyleType
  16042. );
  16043. styleIndex = styleIndex + 1 == listStyle[node.tagName].length
  16044. ? 0
  16045. : styleIndex + 1;
  16046. setListStyle(node, listStyle[node.tagName][styleIndex]);
  16047. }
  16048. }
  16049. var index = 0,
  16050. type = 2;
  16051. if (domUtils.hasClass(node, /custom_/)) {
  16052. if (
  16053. !(
  16054. /[ou]l/i.test(parent.tagName) &&
  16055. domUtils.hasClass(parent, /custom_/)
  16056. )
  16057. ) {
  16058. type = 1;
  16059. }
  16060. } else {
  16061. if (
  16062. /[ou]l/i.test(parent.tagName) &&
  16063. domUtils.hasClass(parent, /custom_/)
  16064. ) {
  16065. type = 3;
  16066. }
  16067. }
  16068. var style = domUtils.getStyle(node, "list-style-type");
  16069. style && (node.style.cssText = "list-style-type:" + style);
  16070. node.className =
  16071. utils.trim(node.className.replace(/list-paddingleft-\w+/, "")) +
  16072. " list-paddingleft-" +
  16073. type;
  16074. utils.each(domUtils.getElementsByTagName(node, "li"), function(li) {
  16075. li.style.cssText && (li.style.cssText = "");
  16076. if (!li.firstChild) {
  16077. domUtils.remove(li);
  16078. return;
  16079. }
  16080. if (li.parentNode !== node) {
  16081. return;
  16082. }
  16083. index++;
  16084. if (domUtils.hasClass(node, /custom_/)) {
  16085. var paddingLeft = 1,
  16086. currentStyle = getStyle(node);
  16087. if (node.tagName == "OL") {
  16088. if (currentStyle) {
  16089. switch (currentStyle) {
  16090. case "cn":
  16091. case "cn1":
  16092. case "cn2":
  16093. if (
  16094. index > 10 &&
  16095. (index % 10 == 0 || (index > 10 && index < 20))
  16096. ) {
  16097. paddingLeft = 2;
  16098. } else if (index > 20) {
  16099. paddingLeft = 3;
  16100. }
  16101. break;
  16102. case "num2":
  16103. if (index > 9) {
  16104. paddingLeft = 2;
  16105. }
  16106. }
  16107. }
  16108. li.className =
  16109. "list-" +
  16110. customStyle[currentStyle] +
  16111. index +
  16112. " " +
  16113. "list-" +
  16114. currentStyle +
  16115. "-paddingleft-" +
  16116. paddingLeft;
  16117. } else {
  16118. li.className =
  16119. "list-" +
  16120. customStyle[currentStyle] +
  16121. " " +
  16122. "list-" +
  16123. currentStyle +
  16124. "-paddingleft";
  16125. }
  16126. } else {
  16127. li.className = li.className.replace(/list-[\w\-]+/gi, "");
  16128. }
  16129. var className = li.getAttribute("class");
  16130. if (className !== null && !className.replace(/\s/g, "")) {
  16131. domUtils.removeAttributes(li, "class");
  16132. }
  16133. });
  16134. !ignore &&
  16135. adjustList(
  16136. node,
  16137. node.tagName.toLowerCase(),
  16138. getStyle(node) || domUtils.getStyle(node, "list-style-type"),
  16139. true
  16140. );
  16141. });
  16142. }
  16143. function adjustList(list, tag, style, ignoreEmpty) {
  16144. var nextList = list.nextSibling;
  16145. if (
  16146. nextList &&
  16147. nextList.nodeType == 1 &&
  16148. nextList.tagName.toLowerCase() == tag &&
  16149. (getStyle(nextList) ||
  16150. domUtils.getStyle(nextList, "list-style-type") ||
  16151. (tag == "ol" ? "decimal" : "disc")) == style
  16152. ) {
  16153. domUtils.moveChild(nextList, list);
  16154. if (nextList.childNodes.length == 0) {
  16155. domUtils.remove(nextList);
  16156. }
  16157. }
  16158. if (nextList && domUtils.isFillChar(nextList)) {
  16159. domUtils.remove(nextList);
  16160. }
  16161. var preList = list.previousSibling;
  16162. if (
  16163. preList &&
  16164. preList.nodeType == 1 &&
  16165. preList.tagName.toLowerCase() == tag &&
  16166. (getStyle(preList) ||
  16167. domUtils.getStyle(preList, "list-style-type") ||
  16168. (tag == "ol" ? "decimal" : "disc")) == style
  16169. ) {
  16170. domUtils.moveChild(list, preList);
  16171. }
  16172. if (preList && domUtils.isFillChar(preList)) {
  16173. domUtils.remove(preList);
  16174. }
  16175. !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
  16176. if (getStyle(list)) {
  16177. adjustListStyle(list.ownerDocument, true);
  16178. }
  16179. }
  16180. function setListStyle(list, style) {
  16181. if (customStyle[style]) {
  16182. list.className = "custom_" + style;
  16183. }
  16184. try {
  16185. domUtils.setStyle(list, "list-style-type", style);
  16186. } catch (e) {}
  16187. }
  16188. function clearEmptySibling(node) {
  16189. var tmpNode = node.previousSibling;
  16190. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  16191. domUtils.remove(tmpNode);
  16192. }
  16193. tmpNode = node.nextSibling;
  16194. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  16195. domUtils.remove(tmpNode);
  16196. }
  16197. }
  16198. me.addListener("keydown", function(type, evt) {
  16199. function preventAndSave() {
  16200. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  16201. me.fireEvent("contentchange");
  16202. me.undoManger && me.undoManger.save();
  16203. }
  16204. function findList(node, filterFn) {
  16205. while (node && !domUtils.isBody(node)) {
  16206. if (filterFn(node)) {
  16207. return null;
  16208. }
  16209. if (node.nodeType == 1 && /[ou]l/i.test(node.tagName)) {
  16210. return node;
  16211. }
  16212. node = node.parentNode;
  16213. }
  16214. return null;
  16215. }
  16216. var keyCode = evt.keyCode || evt.which;
  16217. if (keyCode == 13 && !evt.shiftKey) {
  16218. //回车
  16219. var rng = me.selection.getRange(),
  16220. parent = domUtils.findParent(
  16221. rng.startContainer,
  16222. function(node) {
  16223. return domUtils.isBlockElm(node);
  16224. },
  16225. true
  16226. ),
  16227. li = domUtils.findParentByTagName(rng.startContainer, "li", true);
  16228. if (parent && parent.tagName != "PRE" && !li) {
  16229. var html = parent.innerHTML.replace(
  16230. new RegExp(domUtils.fillChar, "g"),
  16231. ""
  16232. );
  16233. if (/^\s*1\s*\.[^\d]/.test(html)) {
  16234. parent.innerHTML = html.replace(/^\s*1\s*\./, "");
  16235. rng.setStartAtLast(parent).collapse(true).select();
  16236. me.__hasEnterExecCommand = true;
  16237. me.execCommand("insertorderedlist");
  16238. me.__hasEnterExecCommand = false;
  16239. }
  16240. }
  16241. var range = me.selection.getRange(),
  16242. start = findList(range.startContainer, function(node) {
  16243. return node.tagName == "TABLE";
  16244. }),
  16245. end = range.collapsed
  16246. ? start
  16247. : findList(range.endContainer, function(node) {
  16248. return node.tagName == "TABLE";
  16249. });
  16250. if (start && end && start === end) {
  16251. if (!range.collapsed) {
  16252. start = domUtils.findParentByTagName(
  16253. range.startContainer,
  16254. "li",
  16255. true
  16256. );
  16257. end = domUtils.findParentByTagName(range.endContainer, "li", true);
  16258. if (start && end && start === end) {
  16259. range.deleteContents();
  16260. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16261. if (li && domUtils.isEmptyBlock(li)) {
  16262. pre = li.previousSibling;
  16263. next = li.nextSibling;
  16264. p = me.document.createElement("p");
  16265. domUtils.fillNode(me.document, p);
  16266. parentList = li.parentNode;
  16267. if (pre && next) {
  16268. range.setStart(next, 0).collapse(true).select(true);
  16269. domUtils.remove(li);
  16270. } else {
  16271. if ((!pre && !next) || !pre) {
  16272. parentList.parentNode.insertBefore(p, parentList);
  16273. } else {
  16274. li.parentNode.parentNode.insertBefore(
  16275. p,
  16276. parentList.nextSibling
  16277. );
  16278. }
  16279. domUtils.remove(li);
  16280. if (!parentList.firstChild) {
  16281. domUtils.remove(parentList);
  16282. }
  16283. range.setStart(p, 0).setCursor();
  16284. }
  16285. preventAndSave();
  16286. return;
  16287. }
  16288. } else {
  16289. var tmpRange = range.cloneRange(),
  16290. bk = tmpRange.collapse(false).createBookmark();
  16291. range.deleteContents();
  16292. tmpRange.moveToBookmark(bk);
  16293. var li = domUtils.findParentByTagName(
  16294. tmpRange.startContainer,
  16295. "li",
  16296. true
  16297. );
  16298. clearEmptySibling(li);
  16299. tmpRange.select();
  16300. preventAndSave();
  16301. return;
  16302. }
  16303. }
  16304. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16305. if (li) {
  16306. if (domUtils.isEmptyBlock(li)) {
  16307. bk = range.createBookmark();
  16308. var parentList = li.parentNode;
  16309. if (li !== parentList.lastChild) {
  16310. domUtils.breakParent(li, parentList);
  16311. clearEmptySibling(li);
  16312. } else {
  16313. parentList.parentNode.insertBefore(li, parentList.nextSibling);
  16314. if (domUtils.isEmptyNode(parentList)) {
  16315. domUtils.remove(parentList);
  16316. }
  16317. }
  16318. //嵌套不处理
  16319. if (!dtd.$list[li.parentNode.tagName]) {
  16320. if (!domUtils.isBlockElm(li.firstChild)) {
  16321. p = me.document.createElement("p");
  16322. li.parentNode.insertBefore(p, li);
  16323. while (li.firstChild) {
  16324. p.appendChild(li.firstChild);
  16325. }
  16326. domUtils.remove(li);
  16327. } else {
  16328. domUtils.remove(li, true);
  16329. }
  16330. }
  16331. range.moveToBookmark(bk).select();
  16332. } else {
  16333. var first = li.firstChild;
  16334. if (!first || !domUtils.isBlockElm(first)) {
  16335. var p = me.document.createElement("p");
  16336. !li.firstChild && domUtils.fillNode(me.document, p);
  16337. while (li.firstChild) {
  16338. p.appendChild(li.firstChild);
  16339. }
  16340. li.appendChild(p);
  16341. first = p;
  16342. }
  16343. var span = me.document.createElement("span");
  16344. range.insertNode(span);
  16345. domUtils.breakParent(span, li);
  16346. var nextLi = span.nextSibling;
  16347. first = nextLi.firstChild;
  16348. if (!first) {
  16349. p = me.document.createElement("p");
  16350. domUtils.fillNode(me.document, p);
  16351. nextLi.appendChild(p);
  16352. first = p;
  16353. }
  16354. if (domUtils.isEmptyNode(first)) {
  16355. first.innerHTML = "";
  16356. domUtils.fillNode(me.document, first);
  16357. }
  16358. range.setStart(first, 0).collapse(true).shrinkBoundary().select();
  16359. domUtils.remove(span);
  16360. var pre = nextLi.previousSibling;
  16361. if (pre && domUtils.isEmptyBlock(pre)) {
  16362. pre.innerHTML = "<p></p>";
  16363. domUtils.fillNode(me.document, pre.firstChild);
  16364. }
  16365. }
  16366. // }
  16367. preventAndSave();
  16368. }
  16369. }
  16370. }
  16371. if (keyCode == 8) {
  16372. //修中ie中li下的问题
  16373. range = me.selection.getRange();
  16374. if (range.collapsed && domUtils.isStartInblock(range)) {
  16375. tmpRange = range.cloneRange().trimBoundary();
  16376. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16377. //要在li的最左边,才能处理
  16378. if (li && domUtils.isStartInblock(tmpRange)) {
  16379. start = domUtils.findParentByTagName(range.startContainer, "p", true);
  16380. if (start && start !== li.firstChild) {
  16381. var parentList = domUtils.findParentByTagName(start, ["ol", "ul"]);
  16382. domUtils.breakParent(start, parentList);
  16383. clearEmptySibling(start);
  16384. me.fireEvent("contentchange");
  16385. range.setStart(start, 0).setCursor(false, true);
  16386. me.fireEvent("saveScene");
  16387. domUtils.preventDefault(evt);
  16388. return;
  16389. }
  16390. if (li && (pre = li.previousSibling)) {
  16391. if (keyCode == 46 && li.childNodes.length) {
  16392. return;
  16393. }
  16394. //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
  16395. if (dtd.$list[pre.tagName]) {
  16396. pre = pre.lastChild;
  16397. }
  16398. me.undoManger && me.undoManger.save();
  16399. first = li.firstChild;
  16400. if (domUtils.isBlockElm(first)) {
  16401. if (domUtils.isEmptyNode(first)) {
  16402. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  16403. pre.appendChild(first);
  16404. range.setStart(first, 0).setCursor(false, true);
  16405. //first不是唯一的节点
  16406. while (li.firstChild) {
  16407. pre.appendChild(li.firstChild);
  16408. }
  16409. } else {
  16410. span = me.document.createElement("span");
  16411. range.insertNode(span);
  16412. //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
  16413. if (domUtils.isEmptyBlock(pre)) {
  16414. pre.innerHTML = "";
  16415. }
  16416. domUtils.moveChild(li, pre);
  16417. range.setStartBefore(span).collapse(true).select(true);
  16418. domUtils.remove(span);
  16419. }
  16420. } else {
  16421. if (domUtils.isEmptyNode(li)) {
  16422. var p = me.document.createElement("p");
  16423. pre.appendChild(p);
  16424. range.setStart(p, 0).setCursor();
  16425. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  16426. } else {
  16427. range
  16428. .setEnd(pre, pre.childNodes.length)
  16429. .collapse()
  16430. .select(true);
  16431. while (li.firstChild) {
  16432. pre.appendChild(li.firstChild);
  16433. }
  16434. }
  16435. }
  16436. domUtils.remove(li);
  16437. me.fireEvent("contentchange");
  16438. me.fireEvent("saveScene");
  16439. domUtils.preventDefault(evt);
  16440. return;
  16441. }
  16442. //trace:980
  16443. if (li && !li.previousSibling) {
  16444. var parentList = li.parentNode;
  16445. var bk = range.createBookmark();
  16446. if (domUtils.isTagNode(parentList.parentNode, "ol ul")) {
  16447. parentList.parentNode.insertBefore(li, parentList);
  16448. if (domUtils.isEmptyNode(parentList)) {
  16449. domUtils.remove(parentList);
  16450. }
  16451. } else {
  16452. while (li.firstChild) {
  16453. parentList.parentNode.insertBefore(li.firstChild, parentList);
  16454. }
  16455. domUtils.remove(li);
  16456. if (domUtils.isEmptyNode(parentList)) {
  16457. domUtils.remove(parentList);
  16458. }
  16459. }
  16460. range.moveToBookmark(bk).setCursor(false, true);
  16461. me.fireEvent("contentchange");
  16462. me.fireEvent("saveScene");
  16463. domUtils.preventDefault(evt);
  16464. return;
  16465. }
  16466. }
  16467. }
  16468. }
  16469. });
  16470. me.addListener("keyup", function(type, evt) {
  16471. var keyCode = evt.keyCode || evt.which;
  16472. if (keyCode == 8) {
  16473. var rng = me.selection.getRange(),
  16474. list;
  16475. if (
  16476. (list = domUtils.findParentByTagName(
  16477. rng.startContainer,
  16478. ["ol", "ul"],
  16479. true
  16480. ))
  16481. ) {
  16482. adjustList(
  16483. list,
  16484. list.tagName.toLowerCase(),
  16485. getStyle(list) || domUtils.getComputedStyle(list, "list-style-type"),
  16486. true
  16487. );
  16488. }
  16489. }
  16490. });
  16491. //处理tab键
  16492. me.addListener("tabkeydown", function() {
  16493. var range = me.selection.getRange();
  16494. //控制级数
  16495. function checkLevel(li) {
  16496. if (me.options.maxListLevel != -1) {
  16497. var level = li.parentNode,
  16498. levelNum = 0;
  16499. while (/[ou]l/i.test(level.tagName)) {
  16500. levelNum++;
  16501. level = level.parentNode;
  16502. }
  16503. if (levelNum >= me.options.maxListLevel) {
  16504. return true;
  16505. }
  16506. }
  16507. }
  16508. //只以开始为准
  16509. //todo 后续改进
  16510. var li = domUtils.findParentByTagName(range.startContainer, "li", true);
  16511. if (li) {
  16512. var bk;
  16513. if (range.collapsed) {
  16514. if (checkLevel(li)) return true;
  16515. var parentLi = li.parentNode,
  16516. list = me.document.createElement(parentLi.tagName),
  16517. index = utils.indexOf(
  16518. listStyle[list.tagName],
  16519. getStyle(parentLi) ||
  16520. domUtils.getComputedStyle(parentLi, "list-style-type")
  16521. );
  16522. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  16523. var currentStyle = listStyle[list.tagName][index];
  16524. setListStyle(list, currentStyle);
  16525. if (domUtils.isStartInblock(range)) {
  16526. me.fireEvent("saveScene");
  16527. bk = range.createBookmark();
  16528. parentLi.insertBefore(list, li);
  16529. list.appendChild(li);
  16530. adjustList(list, list.tagName.toLowerCase(), currentStyle);
  16531. me.fireEvent("contentchange");
  16532. range.moveToBookmark(bk).select(true);
  16533. return true;
  16534. }
  16535. } else {
  16536. me.fireEvent("saveScene");
  16537. bk = range.createBookmark();
  16538. for (
  16539. var i = 0, closeList, parents = domUtils.findParents(li), ci;
  16540. (ci = parents[i++]);
  16541. ) {
  16542. if (domUtils.isTagNode(ci, "ol ul")) {
  16543. closeList = ci;
  16544. break;
  16545. }
  16546. }
  16547. var current = li;
  16548. if (bk.end) {
  16549. while (
  16550. current &&
  16551. !(
  16552. domUtils.getPosition(current, bk.end) &
  16553. domUtils.POSITION_FOLLOWING
  16554. )
  16555. ) {
  16556. if (checkLevel(current)) {
  16557. current = domUtils.getNextDomNode(current, false, null, function(
  16558. node
  16559. ) {
  16560. return node !== closeList;
  16561. });
  16562. continue;
  16563. }
  16564. var parentLi = current.parentNode,
  16565. list = me.document.createElement(parentLi.tagName),
  16566. index = utils.indexOf(
  16567. listStyle[list.tagName],
  16568. getStyle(parentLi) ||
  16569. domUtils.getComputedStyle(parentLi, "list-style-type")
  16570. );
  16571. var currentIndex = index + 1 == listStyle[list.tagName].length
  16572. ? 0
  16573. : index + 1;
  16574. var currentStyle = listStyle[list.tagName][currentIndex];
  16575. setListStyle(list, currentStyle);
  16576. parentLi.insertBefore(list, current);
  16577. while (
  16578. current &&
  16579. !(
  16580. domUtils.getPosition(current, bk.end) &
  16581. domUtils.POSITION_FOLLOWING
  16582. )
  16583. ) {
  16584. li = current.nextSibling;
  16585. list.appendChild(current);
  16586. if (!li || domUtils.isTagNode(li, "ol ul")) {
  16587. if (li) {
  16588. while ((li = li.firstChild)) {
  16589. if (li.tagName == "LI") {
  16590. break;
  16591. }
  16592. }
  16593. } else {
  16594. li = domUtils.getNextDomNode(current, false, null, function(
  16595. node
  16596. ) {
  16597. return node !== closeList;
  16598. });
  16599. }
  16600. break;
  16601. }
  16602. current = li;
  16603. }
  16604. adjustList(list, list.tagName.toLowerCase(), currentStyle);
  16605. current = li;
  16606. }
  16607. }
  16608. me.fireEvent("contentchange");
  16609. range.moveToBookmark(bk).select();
  16610. return true;
  16611. }
  16612. }
  16613. });
  16614. function getLi(start) {
  16615. while (start && !domUtils.isBody(start)) {
  16616. if (start.nodeName == "TABLE") {
  16617. return null;
  16618. }
  16619. if (start.nodeName == "LI") {
  16620. return start;
  16621. }
  16622. start = start.parentNode;
  16623. }
  16624. }
  16625. /**
  16626. * 有序列表,与“insertunorderedlist”命令互斥
  16627. * @command insertorderedlist
  16628. * @method execCommand
  16629. * @param { String } command 命令字符串
  16630. * @param { String } style 插入的有序列表类型,值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  16631. * @example
  16632. * ```javascript
  16633. * editor.execCommand( 'insertorderedlist','decimal');
  16634. * ```
  16635. */
  16636. /**
  16637. * 查询当前选区内容是否有序列表
  16638. * @command insertorderedlist
  16639. * @method queryCommandState
  16640. * @param { String } cmd 命令字符串
  16641. * @return { int } 如果当前选区是有序列表返回1,否则返回0
  16642. * @example
  16643. * ```javascript
  16644. * editor.queryCommandState( 'insertorderedlist' );
  16645. * ```
  16646. */
  16647. /**
  16648. * 查询当前选区内容是否有序列表
  16649. * @command insertorderedlist
  16650. * @method queryCommandValue
  16651. * @param { String } cmd 命令字符串
  16652. * @return { String } 返回当前有序列表的类型,值为null或decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  16653. * @example
  16654. * ```javascript
  16655. * editor.queryCommandValue( 'insertorderedlist' );
  16656. * ```
  16657. */
  16658. /**
  16659. * 无序列表,与“insertorderedlist”命令互斥
  16660. * @command insertunorderedlist
  16661. * @method execCommand
  16662. * @param { String } command 命令字符串
  16663. * @param { String } style 插入的无序列表类型,值为:circle,disc,square,dash,dot
  16664. * @example
  16665. * ```javascript
  16666. * editor.execCommand( 'insertunorderedlist','circle');
  16667. * ```
  16668. */
  16669. /**
  16670. * 查询当前是否有word文档粘贴进来的图片
  16671. * @command insertunorderedlist
  16672. * @method insertunorderedlist
  16673. * @param { String } command 命令字符串
  16674. * @return { int } 如果当前选区是无序列表返回1,否则返回0
  16675. * @example
  16676. * ```javascript
  16677. * editor.queryCommandState( 'insertunorderedlist' );
  16678. * ```
  16679. */
  16680. /**
  16681. * 查询当前选区内容是否有序列表
  16682. * @command insertunorderedlist
  16683. * @method queryCommandValue
  16684. * @param { String } command 命令字符串
  16685. * @return { String } 返回当前无序列表的类型,值为null或circle,disc,square,dash,dot
  16686. * @example
  16687. * ```javascript
  16688. * editor.queryCommandValue( 'insertunorderedlist' );
  16689. * ```
  16690. */
  16691. me.commands["insertorderedlist"] = me.commands["insertunorderedlist"] = {
  16692. execCommand: function(command, style) {
  16693. if (!style) {
  16694. style = command.toLowerCase() == "insertorderedlist"
  16695. ? "decimal"
  16696. : "disc";
  16697. }
  16698. var me = this,
  16699. range = this.selection.getRange(),
  16700. filterFn = function(node) {
  16701. return node.nodeType == 1
  16702. ? node.tagName.toLowerCase() != "br"
  16703. : !domUtils.isWhitespace(node);
  16704. },
  16705. tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul",
  16706. frag = me.document.createDocumentFragment();
  16707. //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
  16708. //range.shrinkBoundary();//.adjustmentBoundary();
  16709. range.adjustmentBoundary().shrinkBoundary();
  16710. var bko = range.createBookmark(true),
  16711. start = getLi(me.document.getElementById(bko.start)),
  16712. modifyStart = 0,
  16713. end = getLi(me.document.getElementById(bko.end)),
  16714. modifyEnd = 0,
  16715. startParent,
  16716. endParent,
  16717. list,
  16718. tmp;
  16719. if (start || end) {
  16720. start && (startParent = start.parentNode);
  16721. if (!bko.end) {
  16722. end = start;
  16723. }
  16724. end && (endParent = end.parentNode);
  16725. if (startParent === endParent) {
  16726. while (start !== end) {
  16727. tmp = start;
  16728. start = start.nextSibling;
  16729. if (!domUtils.isBlockElm(tmp.firstChild)) {
  16730. var p = me.document.createElement("p");
  16731. while (tmp.firstChild) {
  16732. p.appendChild(tmp.firstChild);
  16733. }
  16734. tmp.appendChild(p);
  16735. }
  16736. frag.appendChild(tmp);
  16737. }
  16738. tmp = me.document.createElement("span");
  16739. startParent.insertBefore(tmp, end);
  16740. if (!domUtils.isBlockElm(end.firstChild)) {
  16741. p = me.document.createElement("p");
  16742. while (end.firstChild) {
  16743. p.appendChild(end.firstChild);
  16744. }
  16745. end.appendChild(p);
  16746. }
  16747. frag.appendChild(end);
  16748. domUtils.breakParent(tmp, startParent);
  16749. if (domUtils.isEmptyNode(tmp.previousSibling)) {
  16750. domUtils.remove(tmp.previousSibling);
  16751. }
  16752. if (domUtils.isEmptyNode(tmp.nextSibling)) {
  16753. domUtils.remove(tmp.nextSibling);
  16754. }
  16755. var nodeStyle =
  16756. getStyle(startParent) ||
  16757. domUtils.getComputedStyle(startParent, "list-style-type") ||
  16758. (command.toLowerCase() == "insertorderedlist" ? "decimal" : "disc");
  16759. if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
  16760. for (
  16761. var i = 0, ci, tmpFrag = me.document.createDocumentFragment();
  16762. (ci = frag.firstChild);
  16763. ) {
  16764. if (domUtils.isTagNode(ci, "ol ul")) {
  16765. // 删除时,子列表不处理
  16766. // utils.each(domUtils.getElementsByTagName(ci,'li'),function(li){
  16767. // while(li.firstChild){
  16768. // tmpFrag.appendChild(li.firstChild);
  16769. // }
  16770. //
  16771. // });
  16772. tmpFrag.appendChild(ci);
  16773. } else {
  16774. while (ci.firstChild) {
  16775. tmpFrag.appendChild(ci.firstChild);
  16776. domUtils.remove(ci);
  16777. }
  16778. }
  16779. }
  16780. tmp.parentNode.insertBefore(tmpFrag, tmp);
  16781. } else {
  16782. list = me.document.createElement(tag);
  16783. setListStyle(list, style);
  16784. list.appendChild(frag);
  16785. tmp.parentNode.insertBefore(list, tmp);
  16786. }
  16787. domUtils.remove(tmp);
  16788. list && adjustList(list, tag, style);
  16789. range.moveToBookmark(bko).select();
  16790. return;
  16791. }
  16792. //开始
  16793. if (start) {
  16794. while (start) {
  16795. tmp = start.nextSibling;
  16796. if (domUtils.isTagNode(start, "ol ul")) {
  16797. frag.appendChild(start);
  16798. } else {
  16799. var tmpfrag = me.document.createDocumentFragment(),
  16800. hasBlock = 0;
  16801. while (start.firstChild) {
  16802. if (domUtils.isBlockElm(start.firstChild)) {
  16803. hasBlock = 1;
  16804. }
  16805. tmpfrag.appendChild(start.firstChild);
  16806. }
  16807. if (!hasBlock) {
  16808. var tmpP = me.document.createElement("p");
  16809. tmpP.appendChild(tmpfrag);
  16810. frag.appendChild(tmpP);
  16811. } else {
  16812. frag.appendChild(tmpfrag);
  16813. }
  16814. domUtils.remove(start);
  16815. }
  16816. start = tmp;
  16817. }
  16818. startParent.parentNode.insertBefore(frag, startParent.nextSibling);
  16819. if (domUtils.isEmptyNode(startParent)) {
  16820. range.setStartBefore(startParent);
  16821. domUtils.remove(startParent);
  16822. } else {
  16823. range.setStartAfter(startParent);
  16824. }
  16825. modifyStart = 1;
  16826. }
  16827. if (end && domUtils.inDoc(endParent, me.document)) {
  16828. //结束
  16829. start = endParent.firstChild;
  16830. while (start && start !== end) {
  16831. tmp = start.nextSibling;
  16832. if (domUtils.isTagNode(start, "ol ul")) {
  16833. frag.appendChild(start);
  16834. } else {
  16835. tmpfrag = me.document.createDocumentFragment();
  16836. hasBlock = 0;
  16837. while (start.firstChild) {
  16838. if (domUtils.isBlockElm(start.firstChild)) {
  16839. hasBlock = 1;
  16840. }
  16841. tmpfrag.appendChild(start.firstChild);
  16842. }
  16843. if (!hasBlock) {
  16844. tmpP = me.document.createElement("p");
  16845. tmpP.appendChild(tmpfrag);
  16846. frag.appendChild(tmpP);
  16847. } else {
  16848. frag.appendChild(tmpfrag);
  16849. }
  16850. domUtils.remove(start);
  16851. }
  16852. start = tmp;
  16853. }
  16854. var tmpDiv = domUtils.createElement(me.document, "div", {
  16855. tmpDiv: 1
  16856. });
  16857. domUtils.moveChild(end, tmpDiv);
  16858. frag.appendChild(tmpDiv);
  16859. domUtils.remove(end);
  16860. endParent.parentNode.insertBefore(frag, endParent);
  16861. range.setEndBefore(endParent);
  16862. if (domUtils.isEmptyNode(endParent)) {
  16863. domUtils.remove(endParent);
  16864. }
  16865. modifyEnd = 1;
  16866. }
  16867. }
  16868. if (!modifyStart) {
  16869. range.setStartBefore(me.document.getElementById(bko.start));
  16870. }
  16871. if (bko.end && !modifyEnd) {
  16872. range.setEndAfter(me.document.getElementById(bko.end));
  16873. }
  16874. range.enlarge(true, function(node) {
  16875. return notExchange[node.tagName];
  16876. });
  16877. frag = me.document.createDocumentFragment();
  16878. var bk = range.createBookmark(),
  16879. current = domUtils.getNextDomNode(bk.start, false, filterFn),
  16880. tmpRange = range.cloneRange(),
  16881. tmpNode,
  16882. block = domUtils.isBlockElm;
  16883. while (
  16884. current &&
  16885. current !== bk.end &&
  16886. domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING
  16887. ) {
  16888. if (current.nodeType == 3 || dtd.li[current.tagName]) {
  16889. if (current.nodeType == 1 && dtd.$list[current.tagName]) {
  16890. while (current.firstChild) {
  16891. frag.appendChild(current.firstChild);
  16892. }
  16893. tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  16894. domUtils.remove(current);
  16895. current = tmpNode;
  16896. continue;
  16897. }
  16898. tmpNode = current;
  16899. tmpRange.setStartBefore(current);
  16900. while (
  16901. current &&
  16902. current !== bk.end &&
  16903. (!block(current) || domUtils.isBookmarkNode(current))
  16904. ) {
  16905. tmpNode = current;
  16906. current = domUtils.getNextDomNode(current, false, null, function(
  16907. node
  16908. ) {
  16909. return !notExchange[node.tagName];
  16910. });
  16911. }
  16912. if (current && block(current)) {
  16913. tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
  16914. if (tmp && domUtils.isBookmarkNode(tmp)) {
  16915. current = domUtils.getNextDomNode(tmp, false, filterFn);
  16916. tmpNode = tmp;
  16917. }
  16918. }
  16919. tmpRange.setEndAfter(tmpNode);
  16920. current = domUtils.getNextDomNode(tmpNode, false, filterFn);
  16921. var li = range.document.createElement("li");
  16922. li.appendChild(tmpRange.extractContents());
  16923. if (domUtils.isEmptyNode(li)) {
  16924. var tmpNode = range.document.createElement("p");
  16925. while (li.firstChild) {
  16926. tmpNode.appendChild(li.firstChild);
  16927. }
  16928. li.appendChild(tmpNode);
  16929. }
  16930. frag.appendChild(li);
  16931. } else {
  16932. current = domUtils.getNextDomNode(current, true, filterFn);
  16933. }
  16934. }
  16935. range.moveToBookmark(bk).collapse(true);
  16936. list = me.document.createElement(tag);
  16937. setListStyle(list, style);
  16938. list.appendChild(frag);
  16939. range.insertNode(list);
  16940. //当前list上下看能否合并
  16941. adjustList(list, tag, style);
  16942. //去掉冗余的tmpDiv
  16943. for (
  16944. var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, "div");
  16945. (ci = tmpDivs[i++]);
  16946. ) {
  16947. if (ci.getAttribute("tmpDiv")) {
  16948. domUtils.remove(ci, true);
  16949. }
  16950. }
  16951. range.moveToBookmark(bko).select();
  16952. },
  16953. queryCommandState: function(command) {
  16954. var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
  16955. var path = this.selection.getStartElementPath();
  16956. for (var i = 0, ci; (ci = path[i++]); ) {
  16957. if (ci.nodeName == "TABLE") {
  16958. return 0;
  16959. }
  16960. if (tag == ci.nodeName.toLowerCase()) {
  16961. return 1;
  16962. }
  16963. }
  16964. return 0;
  16965. },
  16966. queryCommandValue: function(command) {
  16967. var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
  16968. var path = this.selection.getStartElementPath(),
  16969. node;
  16970. for (var i = 0, ci; (ci = path[i++]); ) {
  16971. if (ci.nodeName == "TABLE") {
  16972. node = null;
  16973. break;
  16974. }
  16975. if (tag == ci.nodeName.toLowerCase()) {
  16976. node = ci;
  16977. break;
  16978. }
  16979. }
  16980. return node
  16981. ? getStyle(node) || domUtils.getComputedStyle(node, "list-style-type")
  16982. : null;
  16983. }
  16984. };
  16985. };
  16986. // plugins/source.js
  16987. /**
  16988. * 源码编辑插件
  16989. * @file
  16990. * @since 1.2.6.1
  16991. */
  16992. ;(function() {
  16993. var sourceEditors = {
  16994. textarea: function(editor, holder) {
  16995. var textarea = holder.ownerDocument.createElement("textarea");
  16996. textarea.style.cssText =
  16997. "position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;";
  16998. // todo: IE下只有onresize属性可用... 很纠结
  16999. if (browser.ie && browser.version < 8) {
  17000. textarea.style.width = holder.offsetWidth + "px";
  17001. textarea.style.height = holder.offsetHeight + "px";
  17002. holder.onresize = function() {
  17003. textarea.style.width = holder.offsetWidth + "px";
  17004. textarea.style.height = holder.offsetHeight + "px";
  17005. };
  17006. }
  17007. holder.appendChild(textarea);
  17008. return {
  17009. setContent: function(content) {
  17010. textarea.value = content;
  17011. },
  17012. getContent: function() {
  17013. return textarea.value;
  17014. },
  17015. select: function() {
  17016. var range;
  17017. if (browser.ie) {
  17018. range = textarea.createTextRange();
  17019. range.collapse(true);
  17020. range.select();
  17021. } else {
  17022. //todo: chrome下无法设置焦点
  17023. textarea.setSelectionRange(0, 0);
  17024. textarea.focus();
  17025. }
  17026. },
  17027. dispose: function() {
  17028. holder.removeChild(textarea);
  17029. // todo
  17030. holder.onresize = null;
  17031. textarea = null;
  17032. holder = null;
  17033. },
  17034. focus: function (){
  17035. textarea.focus();
  17036. },
  17037. blur: function (){
  17038. textarea.blur();
  17039. }
  17040. };
  17041. },
  17042. codemirror: function(editor, holder) {
  17043. var codeEditor = window.CodeMirror(holder, {
  17044. mode: "text/html",
  17045. tabMode: "indent",
  17046. lineNumbers: true,
  17047. lineWrapping: true
  17048. });
  17049. var dom = codeEditor.getWrapperElement();
  17050. dom.style.cssText =
  17051. 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
  17052. codeEditor.getScrollerElement().style.cssText =
  17053. "position:absolute;left:0;top:0;width:100%;height:100%;";
  17054. codeEditor.refresh();
  17055. return {
  17056. getCodeMirror: function() {
  17057. return codeEditor;
  17058. },
  17059. setContent: function(content) {
  17060. codeEditor.setValue(content);
  17061. },
  17062. getContent: function() {
  17063. return codeEditor.getValue();
  17064. },
  17065. select: function() {
  17066. codeEditor.focus();
  17067. },
  17068. dispose: function() {
  17069. holder.removeChild(dom);
  17070. dom = null;
  17071. codeEditor = null;
  17072. },
  17073. focus: function (){
  17074. codeEditor.focus();
  17075. },
  17076. blur: function (){
  17077. // codeEditor.blur();
  17078. // since codemirror not support blur()
  17079. codeEditor.setOption('readOnly', true);
  17080. codeEditor.setOption('readOnly', false);
  17081. }
  17082. };
  17083. }
  17084. };
  17085. UE.plugins["source"] = function() {
  17086. var me = this;
  17087. var opt = this.options;
  17088. var sourceMode = false;
  17089. var sourceEditor;
  17090. var orgSetContent;
  17091. var orgFocus;
  17092. var orgBlur;
  17093. opt.sourceEditor = browser.ie
  17094. ? "textarea"
  17095. : opt.sourceEditor || "codemirror";
  17096. me.setOpt({
  17097. sourceEditorFirst: false
  17098. });
  17099. function createSourceEditor(holder) {
  17100. return sourceEditors[
  17101. opt.sourceEditor == "codemirror" && window.CodeMirror
  17102. ? "codemirror"
  17103. : "textarea"
  17104. ](me, holder);
  17105. }
  17106. var bakCssText;
  17107. //解决在源码模式下getContent不能得到最新的内容问题
  17108. var oldGetContent, bakAddress;
  17109. /**
  17110. * 切换源码模式和编辑模式
  17111. * @command source
  17112. * @method execCommand
  17113. * @param { String } cmd 命令字符串
  17114. * @example
  17115. * ```javascript
  17116. * editor.execCommand( 'source');
  17117. * ```
  17118. */
  17119. /**
  17120. * 查询当前编辑区域的状态是源码模式还是可视化模式
  17121. * @command source
  17122. * @method queryCommandState
  17123. * @param { String } cmd 命令字符串
  17124. * @return { int } 如果当前是源码编辑模式,返回1,否则返回0
  17125. * @example
  17126. * ```javascript
  17127. * editor.queryCommandState( 'source' );
  17128. * ```
  17129. */
  17130. me.commands["source"] = {
  17131. execCommand: function() {
  17132. sourceMode = !sourceMode;
  17133. if (sourceMode) {
  17134. bakAddress = me.selection.getRange().createAddress(false, true);
  17135. me.undoManger && me.undoManger.save(true);
  17136. if (browser.gecko) {
  17137. me.body.contentEditable = false;
  17138. }
  17139. bakCssText = me.iframe.style.cssText;
  17140. me.iframe.style.cssText +=
  17141. "position:absolute;left:-32768px;top:-32768px;";
  17142. me.fireEvent("beforegetcontent");
  17143. var root = UE.htmlparser(me.body.innerHTML);
  17144. me.filterOutputRule(root);
  17145. root.traversal(function(node) {
  17146. if (node.type == "element") {
  17147. switch (node.tagName) {
  17148. case "td":
  17149. case "th":
  17150. case "caption":
  17151. if (node.children && node.children.length == 1) {
  17152. if (node.firstChild().tagName == "br") {
  17153. node.removeChild(node.firstChild());
  17154. }
  17155. }
  17156. break;
  17157. case "pre":
  17158. node.innerText(node.innerText().replace(/&nbsp;/g, " "));
  17159. }
  17160. }
  17161. });
  17162. me.fireEvent("aftergetcontent");
  17163. var content = root.toHtml(true);
  17164. sourceEditor = createSourceEditor(me.iframe.parentNode);
  17165. sourceEditor.setContent(content);
  17166. orgSetContent = me.setContent;
  17167. me.setContent = function(html) {
  17168. //这里暂时不触发事件,防止报错
  17169. var root = UE.htmlparser(html);
  17170. me.filterInputRule(root);
  17171. html = root.toHtml();
  17172. sourceEditor.setContent(html);
  17173. };
  17174. setTimeout(function() {
  17175. sourceEditor.select();
  17176. me.addListener("fullscreenchanged", function() {
  17177. try {
  17178. sourceEditor.getCodeMirror().refresh();
  17179. } catch (e) {}
  17180. });
  17181. });
  17182. //重置getContent,源码模式下取值也能是最新的数据
  17183. oldGetContent = me.getContent;
  17184. me.getContent = function() {
  17185. return (
  17186. sourceEditor.getContent() ||
  17187. "<p>" + (browser.ie ? "" : "<br/>") + "</p>"
  17188. );
  17189. };
  17190. orgFocus = me.focus;
  17191. orgBlur = me.blur;
  17192. me.focus = function(){
  17193. sourceEditor.focus();
  17194. };
  17195. me.blur = function(){
  17196. orgBlur.call(me);
  17197. sourceEditor.blur();
  17198. };
  17199. } else {
  17200. me.iframe.style.cssText = bakCssText;
  17201. var cont =
  17202. sourceEditor.getContent() ||
  17203. "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  17204. //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
  17205. cont = cont.replace(
  17206. new RegExp("[\\r\\t\\n ]*</?(\\w+)\\s*(?:[^>]*)>", "g"),
  17207. function(a, b) {
  17208. if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
  17209. return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, "");
  17210. }
  17211. return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, "");
  17212. }
  17213. );
  17214. me.setContent = orgSetContent;
  17215. me.setContent(cont);
  17216. sourceEditor.dispose();
  17217. sourceEditor = null;
  17218. //还原getContent方法
  17219. me.getContent = oldGetContent;
  17220. me.focus = orgFocus;
  17221. me.blur = orgBlur;
  17222. var first = me.body.firstChild;
  17223. //trace:1106 都删除空了,下边会报错,所以补充一个p占位
  17224. if (!first) {
  17225. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  17226. first = me.body.firstChild;
  17227. }
  17228. //要在ifm为显示时ff才能取到selection,否则报错
  17229. //这里不能比较位置了
  17230. me.undoManger && me.undoManger.save(true);
  17231. if (browser.gecko) {
  17232. var input = document.createElement("input");
  17233. input.style.cssText = "position:absolute;left:0;top:-32768px";
  17234. document.body.appendChild(input);
  17235. me.body.contentEditable = false;
  17236. setTimeout(function() {
  17237. domUtils.setViewportOffset(input, { left: -32768, top: 0 });
  17238. input.focus();
  17239. setTimeout(function() {
  17240. me.body.contentEditable = true;
  17241. me.selection.getRange().moveToAddress(bakAddress).select(true);
  17242. domUtils.remove(input);
  17243. });
  17244. });
  17245. } else {
  17246. //ie下有可能报错,比如在代码顶头的情况
  17247. try {
  17248. me.selection.getRange().moveToAddress(bakAddress).select(true);
  17249. } catch (e) {}
  17250. }
  17251. }
  17252. this.fireEvent("sourcemodechanged", sourceMode);
  17253. },
  17254. queryCommandState: function() {
  17255. return sourceMode | 0;
  17256. },
  17257. notNeedUndo: 1
  17258. };
  17259. var oldQueryCommandState = me.queryCommandState;
  17260. me.queryCommandState = function(cmdName) {
  17261. cmdName = cmdName.toLowerCase();
  17262. if (sourceMode) {
  17263. //源码模式下可以开启的命令
  17264. return cmdName in
  17265. {
  17266. source: 1,
  17267. fullscreen: 1
  17268. }
  17269. ? 1
  17270. : -1;
  17271. }
  17272. return oldQueryCommandState.apply(this, arguments);
  17273. };
  17274. if (opt.sourceEditor == "codemirror") {
  17275. me.addListener("ready", function() {
  17276. utils.loadFile(
  17277. document,
  17278. {
  17279. src:
  17280. opt.codeMirrorJsUrl ||
  17281. opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js",
  17282. tag: "script",
  17283. type: "text/javascript",
  17284. defer: "defer"
  17285. },
  17286. function() {
  17287. if (opt.sourceEditorFirst) {
  17288. setTimeout(function() {
  17289. me.execCommand("source");
  17290. }, 0);
  17291. }
  17292. }
  17293. );
  17294. utils.loadFile(document, {
  17295. tag: "link",
  17296. rel: "stylesheet",
  17297. type: "text/css",
  17298. href:
  17299. opt.codeMirrorCssUrl ||
  17300. opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css"
  17301. });
  17302. });
  17303. }
  17304. };
  17305. })();
  17306. // plugins/enterkey.js
  17307. ///import core
  17308. ///import plugins/undo.js
  17309. ///commands 设置回车标签p或br
  17310. ///commandsName EnterKey
  17311. ///commandsTitle 设置回车标签p或br
  17312. /**
  17313. * @description 处理回车
  17314. * @author zhanyi
  17315. */
  17316. UE.plugins["enterkey"] = function() {
  17317. var hTag,
  17318. me = this,
  17319. tag = me.options.enterTag;
  17320. me.addListener("keyup", function(type, evt) {
  17321. var keyCode = evt.keyCode || evt.which;
  17322. if (keyCode == 13) {
  17323. var range = me.selection.getRange(),
  17324. start = range.startContainer,
  17325. doSave;
  17326. //修正在h1-h6里边回车后不能嵌套p的问题
  17327. if (!browser.ie) {
  17328. if (/h\d/i.test(hTag)) {
  17329. if (browser.gecko) {
  17330. var h = domUtils.findParentByTagName(
  17331. start,
  17332. [
  17333. "h1",
  17334. "h2",
  17335. "h3",
  17336. "h4",
  17337. "h5",
  17338. "h6",
  17339. "blockquote",
  17340. "caption",
  17341. "table"
  17342. ],
  17343. true
  17344. );
  17345. if (!h) {
  17346. me.document.execCommand("formatBlock", false, "<p>");
  17347. doSave = 1;
  17348. }
  17349. } else {
  17350. //chrome remove div
  17351. if (start.nodeType == 1) {
  17352. var tmp = me.document.createTextNode(""),
  17353. div;
  17354. range.insertNode(tmp);
  17355. div = domUtils.findParentByTagName(tmp, "div", true);
  17356. if (div) {
  17357. var p = me.document.createElement("p");
  17358. while (div.firstChild) {
  17359. p.appendChild(div.firstChild);
  17360. }
  17361. div.parentNode.insertBefore(p, div);
  17362. domUtils.remove(div);
  17363. range.setStartBefore(tmp).setCursor();
  17364. doSave = 1;
  17365. }
  17366. domUtils.remove(tmp);
  17367. }
  17368. }
  17369. if (me.undoManger && doSave) {
  17370. me.undoManger.save();
  17371. }
  17372. }
  17373. //没有站位符,会出现多行的问题
  17374. browser.opera && range.select();
  17375. } else {
  17376. me.fireEvent("saveScene", true, true);
  17377. }
  17378. }
  17379. });
  17380. me.addListener("keydown", function(type, evt) {
  17381. var keyCode = evt.keyCode || evt.which;
  17382. if (keyCode == 13) {
  17383. //回车
  17384. if (me.fireEvent("beforeenterkeydown")) {
  17385. domUtils.preventDefault(evt);
  17386. return;
  17387. }
  17388. me.fireEvent("saveScene", true, true);
  17389. hTag = "";
  17390. var range = me.selection.getRange();
  17391. if (!range.collapsed) {
  17392. //跨td不能删
  17393. var start = range.startContainer,
  17394. end = range.endContainer,
  17395. startTd = domUtils.findParentByTagName(start, "td", true),
  17396. endTd = domUtils.findParentByTagName(end, "td", true);
  17397. if (
  17398. (startTd && endTd && startTd !== endTd) ||
  17399. (!startTd && endTd) ||
  17400. (startTd && !endTd)
  17401. ) {
  17402. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  17403. return;
  17404. }
  17405. }
  17406. if (tag == "p") {
  17407. if (!browser.ie) {
  17408. start = domUtils.findParentByTagName(
  17409. range.startContainer,
  17410. [
  17411. "ol",
  17412. "ul",
  17413. "p",
  17414. "h1",
  17415. "h2",
  17416. "h3",
  17417. "h4",
  17418. "h5",
  17419. "h6",
  17420. "blockquote",
  17421. "caption"
  17422. ],
  17423. true
  17424. );
  17425. //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
  17426. //trace:2431
  17427. if (!start && !browser.opera) {
  17428. me.document.execCommand("formatBlock", false, "<p>");
  17429. if (browser.gecko) {
  17430. range = me.selection.getRange();
  17431. start = domUtils.findParentByTagName(
  17432. range.startContainer,
  17433. "p",
  17434. true
  17435. );
  17436. start && domUtils.removeDirtyAttr(start);
  17437. }
  17438. } else {
  17439. hTag = start.tagName;
  17440. start.tagName.toLowerCase() == "p" &&
  17441. browser.gecko &&
  17442. domUtils.removeDirtyAttr(start);
  17443. }
  17444. }
  17445. } else {
  17446. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  17447. if (!range.collapsed) {
  17448. range.deleteContents();
  17449. start = range.startContainer;
  17450. if (
  17451. start.nodeType == 1 &&
  17452. (start = start.childNodes[range.startOffset])
  17453. ) {
  17454. while (start.nodeType == 1) {
  17455. if (dtd.$empty[start.tagName]) {
  17456. range.setStartBefore(start).setCursor();
  17457. if (me.undoManger) {
  17458. me.undoManger.save();
  17459. }
  17460. return false;
  17461. }
  17462. if (!start.firstChild) {
  17463. var br = range.document.createElement("br");
  17464. start.appendChild(br);
  17465. range.setStart(start, 0).setCursor();
  17466. if (me.undoManger) {
  17467. me.undoManger.save();
  17468. }
  17469. return false;
  17470. }
  17471. start = start.firstChild;
  17472. }
  17473. if (start === range.startContainer.childNodes[range.startOffset]) {
  17474. br = range.document.createElement("br");
  17475. range.insertNode(br).setCursor();
  17476. } else {
  17477. range.setStart(start, 0).setCursor();
  17478. }
  17479. } else {
  17480. br = range.document.createElement("br");
  17481. range.insertNode(br).setStartAfter(br).setCursor();
  17482. }
  17483. } else {
  17484. br = range.document.createElement("br");
  17485. range.insertNode(br);
  17486. var parent = br.parentNode;
  17487. if (parent.lastChild === br) {
  17488. br.parentNode.insertBefore(br.cloneNode(true), br);
  17489. range.setStartBefore(br);
  17490. } else {
  17491. range.setStartAfter(br);
  17492. }
  17493. range.setCursor();
  17494. }
  17495. }
  17496. }
  17497. });
  17498. };
  17499. // plugins/keystrokes.js
  17500. /* 处理特殊键的兼容性问题 */
  17501. UE.plugins["keystrokes"] = function() {
  17502. var me = this;
  17503. var collapsed = true;
  17504. me.addListener("keydown", function(type, evt) {
  17505. var keyCode = evt.keyCode || evt.which,
  17506. rng = me.selection.getRange();
  17507. //处理全选的情况
  17508. if (
  17509. !rng.collapsed &&
  17510. !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) &&
  17511. ((keyCode >= 65 && keyCode <= 90) ||
  17512. (keyCode >= 48 && keyCode <= 57) ||
  17513. (keyCode >= 96 && keyCode <= 111) ||
  17514. {
  17515. 13: 1,
  17516. 8: 1,
  17517. 46: 1
  17518. }[keyCode])
  17519. ) {
  17520. var tmpNode = rng.startContainer;
  17521. if (domUtils.isFillChar(tmpNode)) {
  17522. rng.setStartBefore(tmpNode);
  17523. }
  17524. tmpNode = rng.endContainer;
  17525. if (domUtils.isFillChar(tmpNode)) {
  17526. rng.setEndAfter(tmpNode);
  17527. }
  17528. rng.txtToElmBoundary();
  17529. //结束边界可能放到了br的前边,要把br包含进来
  17530. // x[xxx]<br/>
  17531. if (rng.endContainer && rng.endContainer.nodeType == 1) {
  17532. tmpNode = rng.endContainer.childNodes[rng.endOffset];
  17533. if (tmpNode && domUtils.isBr(tmpNode)) {
  17534. rng.setEndAfter(tmpNode);
  17535. }
  17536. }
  17537. if (rng.startOffset == 0) {
  17538. tmpNode = rng.startContainer;
  17539. if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
  17540. tmpNode = rng.endContainer;
  17541. if (
  17542. rng.endOffset ==
  17543. (tmpNode.nodeType == 3
  17544. ? tmpNode.nodeValue.length
  17545. : tmpNode.childNodes.length) &&
  17546. domUtils.isBoundaryNode(tmpNode, "lastChild")
  17547. ) {
  17548. me.fireEvent("saveScene");
  17549. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  17550. rng.setStart(me.body.firstChild, 0).setCursor(false, true);
  17551. me._selectionChange();
  17552. return;
  17553. }
  17554. }
  17555. }
  17556. }
  17557. //处理backspace
  17558. if (keyCode == keymap.Backspace) {
  17559. rng = me.selection.getRange();
  17560. collapsed = rng.collapsed;
  17561. if (me.fireEvent("delkeydown", evt)) {
  17562. return;
  17563. }
  17564. var start, end;
  17565. //避免按两次删除才能生效的问题
  17566. if (rng.collapsed && rng.inFillChar()) {
  17567. start = rng.startContainer;
  17568. if (domUtils.isFillChar(start)) {
  17569. rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
  17570. domUtils.remove(start);
  17571. } else {
  17572. start.nodeValue = start.nodeValue.replace(
  17573. new RegExp("^" + domUtils.fillChar),
  17574. ""
  17575. );
  17576. rng.startOffset--;
  17577. rng.collapse(true).select(true);
  17578. }
  17579. }
  17580. //解决选中control元素不能删除的问题
  17581. if ((start = rng.getClosedNode())) {
  17582. me.fireEvent("saveScene");
  17583. rng.setStartBefore(start);
  17584. domUtils.remove(start);
  17585. rng.setCursor();
  17586. me.fireEvent("saveScene");
  17587. domUtils.preventDefault(evt);
  17588. return;
  17589. }
  17590. //阻止在table上的删除
  17591. if (!browser.ie) {
  17592. start = domUtils.findParentByTagName(rng.startContainer, "table", true);
  17593. end = domUtils.findParentByTagName(rng.endContainer, "table", true);
  17594. if ((start && !end) || (!start && end) || start !== end) {
  17595. evt.preventDefault();
  17596. return;
  17597. }
  17598. }
  17599. }
  17600. //处理tab键的逻辑
  17601. if (keyCode == keymap.Tab) {
  17602. //不处理以下标签
  17603. var excludeTagNameForTabKey = {
  17604. ol: 1,
  17605. ul: 1,
  17606. table: 1
  17607. };
  17608. //处理组件里的tab按下事件
  17609. if (me.fireEvent("tabkeydown", evt)) {
  17610. domUtils.preventDefault(evt);
  17611. return;
  17612. }
  17613. var range = me.selection.getRange();
  17614. me.fireEvent("saveScene");
  17615. for (
  17616. var i = 0,
  17617. txt = "",
  17618. tabSize = me.options.tabSize || 4,
  17619. tabNode = me.options.tabNode || "&nbsp;";
  17620. i < tabSize;
  17621. i++
  17622. ) {
  17623. txt += tabNode;
  17624. }
  17625. var span = me.document.createElement("span");
  17626. span.innerHTML = txt + domUtils.fillChar;
  17627. if (range.collapsed) {
  17628. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  17629. } else {
  17630. var filterFn = function(node) {
  17631. return (
  17632. domUtils.isBlockElm(node) &&
  17633. !excludeTagNameForTabKey[node.tagName.toLowerCase()]
  17634. );
  17635. };
  17636. //普通的情况
  17637. start = domUtils.findParent(range.startContainer, filterFn, true);
  17638. end = domUtils.findParent(range.endContainer, filterFn, true);
  17639. if (start && end && start === end) {
  17640. range.deleteContents();
  17641. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  17642. } else {
  17643. var bookmark = range.createBookmark();
  17644. range.enlarge(true);
  17645. var bookmark2 = range.createBookmark(),
  17646. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
  17647. while (
  17648. current &&
  17649. !(
  17650. domUtils.getPosition(current, bookmark2.end) &
  17651. domUtils.POSITION_FOLLOWING
  17652. )
  17653. ) {
  17654. current.insertBefore(
  17655. span.cloneNode(true).firstChild,
  17656. current.firstChild
  17657. );
  17658. current = domUtils.getNextDomNode(current, false, filterFn);
  17659. }
  17660. range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
  17661. }
  17662. }
  17663. domUtils.preventDefault(evt);
  17664. }
  17665. //trace:1634
  17666. //ff的del键在容器空的时候,也会删除
  17667. if (browser.gecko && keyCode == 46) {
  17668. range = me.selection.getRange();
  17669. if (range.collapsed) {
  17670. start = range.startContainer;
  17671. if (domUtils.isEmptyBlock(start)) {
  17672. var parent = start.parentNode;
  17673. while (
  17674. domUtils.getChildCount(parent) == 1 &&
  17675. !domUtils.isBody(parent)
  17676. ) {
  17677. start = parent;
  17678. parent = parent.parentNode;
  17679. }
  17680. if (start === parent.lastChild) evt.preventDefault();
  17681. return;
  17682. }
  17683. }
  17684. }
  17685. /* 修复在编辑区域快捷键 (Mac:meta+alt+I; Win:ctrl+shift+I) 打不开 chrome 控制台的问题 */
  17686. browser.chrome &&
  17687. me.on("keydown", function(type, e) {
  17688. var keyCode = e.keyCode || e.which;
  17689. if (
  17690. ((e.metaKey && e.altKey) || (e.ctrlKey && e.shiftKey)) &&
  17691. keyCode == 73
  17692. ) {
  17693. return true;
  17694. }
  17695. });
  17696. });
  17697. me.addListener("keyup", function(type, evt) {
  17698. var keyCode = evt.keyCode || evt.which,
  17699. rng,
  17700. me = this;
  17701. if (keyCode == keymap.Backspace) {
  17702. if (me.fireEvent("delkeyup")) {
  17703. return;
  17704. }
  17705. rng = me.selection.getRange();
  17706. if (rng.collapsed) {
  17707. var tmpNode,
  17708. autoClearTagName = ["h1", "h2", "h3", "h4", "h5", "h6"];
  17709. if (
  17710. (tmpNode = domUtils.findParentByTagName(
  17711. rng.startContainer,
  17712. autoClearTagName,
  17713. true
  17714. ))
  17715. ) {
  17716. if (domUtils.isEmptyBlock(tmpNode)) {
  17717. var pre = tmpNode.previousSibling;
  17718. if (pre && pre.nodeName != "TABLE") {
  17719. domUtils.remove(tmpNode);
  17720. rng.setStartAtLast(pre).setCursor(false, true);
  17721. return;
  17722. } else {
  17723. var next = tmpNode.nextSibling;
  17724. if (next && next.nodeName != "TABLE") {
  17725. domUtils.remove(tmpNode);
  17726. rng.setStartAtFirst(next).setCursor(false, true);
  17727. return;
  17728. }
  17729. }
  17730. }
  17731. }
  17732. //处理当删除到body时,要重新给p标签展位
  17733. if (domUtils.isBody(rng.startContainer)) {
  17734. var tmpNode = domUtils.createElement(me.document, "p", {
  17735. innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
  17736. });
  17737. rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true);
  17738. }
  17739. }
  17740. //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
  17741. if (
  17742. !collapsed &&
  17743. (rng.startContainer.nodeType == 3 ||
  17744. (rng.startContainer.nodeType == 1 &&
  17745. domUtils.isEmptyBlock(rng.startContainer)))
  17746. ) {
  17747. if (browser.ie) {
  17748. var span = rng.document.createElement("span");
  17749. rng.insertNode(span).setStartBefore(span).collapse(true);
  17750. rng.select();
  17751. domUtils.remove(span);
  17752. } else {
  17753. rng.select();
  17754. }
  17755. }
  17756. }
  17757. });
  17758. };
  17759. // plugins/fiximgclick.js
  17760. ///import core
  17761. ///commands 修复chrome下图片不能点击的问题,出现八个角可改变大小
  17762. ///commandsName FixImgClick
  17763. ///commandsTitle 修复chrome下图片不能点击的问题,出现八个角可改变大小
  17764. //修复chrome下图片不能点击的问题,出现八个角可改变大小
  17765. UE.plugins["fiximgclick"] = (function() {
  17766. var elementUpdated = false;
  17767. function Scale() {
  17768. this.editor = null;
  17769. this.resizer = null;
  17770. this.cover = null;
  17771. this.doc = document;
  17772. this.prePos = { x: 0, y: 0 };
  17773. this.startPos = { x: 0, y: 0 };
  17774. }
  17775. (function() {
  17776. var rect = [
  17777. //[left, top, width, height]
  17778. [0, 0, -1, -1],
  17779. [0, 0, 0, -1],
  17780. [0, 0, 1, -1],
  17781. [0, 0, -1, 0],
  17782. [0, 0, 1, 0],
  17783. [0, 0, -1, 1],
  17784. [0, 0, 0, 1],
  17785. [0, 0, 1, 1]
  17786. ];
  17787. Scale.prototype = {
  17788. init: function(editor) {
  17789. var me = this;
  17790. me.editor = editor;
  17791. me.startPos = this.prePos = { x: 0, y: 0 };
  17792. me.dragId = -1;
  17793. var hands = [],
  17794. cover = (me.cover = document.createElement("div")),
  17795. resizer = (me.resizer = document.createElement("div"));
  17796. cover.id = me.editor.ui.id + "_imagescale_cover";
  17797. cover.style.cssText =
  17798. "position:absolute;display:none;z-index:" +
  17799. me.editor.options.zIndex +
  17800. ";filter:alpha(opacity=0); opacity:0;background:#CCC;";
  17801. domUtils.on(cover, "mousedown click", function() {
  17802. me.hide();
  17803. });
  17804. for (i = 0; i < 8; i++) {
  17805. hands.push(
  17806. '<span class="edui-editor-imagescale-hand' + i + '"></span>'
  17807. );
  17808. }
  17809. resizer.id = me.editor.ui.id + "_imagescale";
  17810. resizer.className = "edui-editor-imagescale";
  17811. resizer.innerHTML = hands.join("");
  17812. resizer.style.cssText +=
  17813. ";display:none;border:1px solid #3b77ff;z-index:" +
  17814. me.editor.options.zIndex +
  17815. ";";
  17816. me.editor.ui.getDom().appendChild(cover);
  17817. me.editor.ui.getDom().appendChild(resizer);
  17818. me.initStyle();
  17819. me.initEvents();
  17820. },
  17821. initStyle: function() {
  17822. utils.cssRule(
  17823. "imagescale",
  17824. ".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;}" +
  17825. ".edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}" +
  17826. ".edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}" +
  17827. ".edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}" +
  17828. ".edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}" +
  17829. ".edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}" +
  17830. ".edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}" +
  17831. ".edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}" +
  17832. ".edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}" +
  17833. ".edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}"
  17834. );
  17835. },
  17836. initEvents: function() {
  17837. var me = this;
  17838. me.startPos.x = me.startPos.y = 0;
  17839. me.isDraging = false;
  17840. },
  17841. _eventHandler: function(e) {
  17842. var me = this;
  17843. switch (e.type) {
  17844. case "mousedown":
  17845. var hand = e.target || e.srcElement,
  17846. hand;
  17847. if (
  17848. hand.className.indexOf("edui-editor-imagescale-hand") != -1 &&
  17849. me.dragId == -1
  17850. ) {
  17851. me.dragId = hand.className.slice(-1);
  17852. me.startPos.x = me.prePos.x = e.clientX;
  17853. me.startPos.y = me.prePos.y = e.clientY;
  17854. domUtils.on(me.doc, "mousemove", me.proxy(me._eventHandler, me));
  17855. }
  17856. break;
  17857. case "mousemove":
  17858. if (me.dragId != -1) {
  17859. me.updateContainerStyle(me.dragId, {
  17860. x: e.clientX - me.prePos.x,
  17861. y: e.clientY - me.prePos.y
  17862. });
  17863. me.prePos.x = e.clientX;
  17864. me.prePos.y = e.clientY;
  17865. elementUpdated = true;
  17866. me.updateTargetElement();
  17867. }
  17868. break;
  17869. case "mouseup":
  17870. if (me.dragId != -1) {
  17871. me.updateContainerStyle(me.dragId, {
  17872. x: e.clientX - me.prePos.x,
  17873. y: e.clientY - me.prePos.y
  17874. });
  17875. me.updateTargetElement();
  17876. if (me.target.parentNode) me.attachTo(me.target);
  17877. me.dragId = -1;
  17878. }
  17879. domUtils.un(me.doc, "mousemove", me.proxy(me._eventHandler, me));
  17880. //修复只是点击挪动点,但没有改变大小,不应该触发contentchange
  17881. if (elementUpdated) {
  17882. elementUpdated = false;
  17883. me.editor.fireEvent("contentchange");
  17884. }
  17885. break;
  17886. default:
  17887. break;
  17888. }
  17889. },
  17890. updateTargetElement: function() {
  17891. var me = this;
  17892. domUtils.setStyles(me.target, {
  17893. width: me.resizer.style.width,
  17894. height: me.resizer.style.height
  17895. });
  17896. me.target.width = parseInt(me.resizer.style.width);
  17897. me.target.height = parseInt(me.resizer.style.height);
  17898. me.attachTo(me.target);
  17899. },
  17900. updateContainerStyle: function(dir, offset) {
  17901. var me = this,
  17902. dom = me.resizer,
  17903. tmp;
  17904. if (rect[dir][0] != 0) {
  17905. tmp = parseInt(dom.style.left) + offset.x;
  17906. dom.style.left = me._validScaledProp("left", tmp) + "px";
  17907. }
  17908. if (rect[dir][1] != 0) {
  17909. tmp = parseInt(dom.style.top) + offset.y;
  17910. dom.style.top = me._validScaledProp("top", tmp) + "px";
  17911. }
  17912. if (rect[dir][2] != 0) {
  17913. tmp = dom.clientWidth + rect[dir][2] * offset.x;
  17914. dom.style.width = me._validScaledProp("width", tmp) + "px";
  17915. }
  17916. if (rect[dir][3] != 0) {
  17917. tmp = dom.clientHeight + rect[dir][3] * offset.y;
  17918. dom.style.height = me._validScaledProp("height", tmp) + "px";
  17919. }
  17920. },
  17921. _validScaledProp: function(prop, value) {
  17922. var ele = this.resizer,
  17923. wrap = document;
  17924. value = isNaN(value) ? 0 : value;
  17925. switch (prop) {
  17926. case "left":
  17927. return value < 0
  17928. ? 0
  17929. : value + ele.clientWidth > wrap.clientWidth
  17930. ? wrap.clientWidth - ele.clientWidth
  17931. : value;
  17932. case "top":
  17933. return value < 0
  17934. ? 0
  17935. : value + ele.clientHeight > wrap.clientHeight
  17936. ? wrap.clientHeight - ele.clientHeight
  17937. : value;
  17938. case "width":
  17939. return value <= 0
  17940. ? 1
  17941. : value + ele.offsetLeft > wrap.clientWidth
  17942. ? wrap.clientWidth - ele.offsetLeft
  17943. : value;
  17944. case "height":
  17945. return value <= 0
  17946. ? 1
  17947. : value + ele.offsetTop > wrap.clientHeight
  17948. ? wrap.clientHeight - ele.offsetTop
  17949. : value;
  17950. }
  17951. },
  17952. hideCover: function() {
  17953. this.cover.style.display = "none";
  17954. },
  17955. showCover: function() {
  17956. var me = this,
  17957. editorPos = domUtils.getXY(me.editor.ui.getDom()),
  17958. iframePos = domUtils.getXY(me.editor.iframe);
  17959. domUtils.setStyles(me.cover, {
  17960. width: me.editor.iframe.offsetWidth + "px",
  17961. height: me.editor.iframe.offsetHeight + "px",
  17962. top: iframePos.y - editorPos.y + "px",
  17963. left: iframePos.x - editorPos.x + "px",
  17964. position: "absolute",
  17965. display: ""
  17966. });
  17967. },
  17968. show: function(targetObj) {
  17969. var me = this;
  17970. me.resizer.style.display = "block";
  17971. if (targetObj) me.attachTo(targetObj);
  17972. domUtils.on(this.resizer, "mousedown", me.proxy(me._eventHandler, me));
  17973. domUtils.on(me.doc, "mouseup", me.proxy(me._eventHandler, me));
  17974. me.showCover();
  17975. me.editor.fireEvent("afterscaleshow", me);
  17976. me.editor.fireEvent("saveScene");
  17977. },
  17978. hide: function() {
  17979. var me = this;
  17980. me.hideCover();
  17981. me.resizer.style.display = "none";
  17982. domUtils.un(me.resizer, "mousedown", me.proxy(me._eventHandler, me));
  17983. domUtils.un(me.doc, "mouseup", me.proxy(me._eventHandler, me));
  17984. me.editor.fireEvent("afterscalehide", me);
  17985. },
  17986. proxy: function(fn, context) {
  17987. return function(e) {
  17988. return fn.apply(context || this, arguments);
  17989. };
  17990. },
  17991. attachTo: function(targetObj) {
  17992. var me = this,
  17993. target = (me.target = targetObj),
  17994. resizer = this.resizer,
  17995. imgPos = domUtils.getXY(target),
  17996. iframePos = domUtils.getXY(me.editor.iframe),
  17997. editorPos = domUtils.getXY(resizer.parentNode);
  17998. var doc = me.editor.document;
  17999. domUtils.setStyles(resizer, {
  18000. width: target.width + "px",
  18001. height: target.height + "px",
  18002. left:
  18003. iframePos.x +
  18004. imgPos.x -
  18005. (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0) -
  18006. editorPos.x -
  18007. parseInt(resizer.style.borderLeftWidth) +
  18008. "px",
  18009. top:
  18010. iframePos.y +
  18011. imgPos.y -
  18012. (doc.documentElement.scrollTop || doc.body.scrollTop || 0) -
  18013. editorPos.y -
  18014. parseInt(resizer.style.borderTopWidth) +
  18015. "px"
  18016. });
  18017. }
  18018. };
  18019. })();
  18020. return function() {
  18021. var me = this,
  18022. imageScale;
  18023. me.setOpt("imageScaleEnabled", true);
  18024. if (!browser.ie && me.options.imageScaleEnabled) {
  18025. me.addListener("click", function(type, e) {
  18026. var range = me.selection.getRange(),
  18027. img = range.getClosedNode();
  18028. if (img && img.tagName == "IMG" && me.body.contentEditable != "false") {
  18029. if (
  18030. img.className.indexOf("edui-faked-music") != -1 ||
  18031. img.getAttribute("anchorname") ||
  18032. domUtils.hasClass(img, "loadingclass") ||
  18033. domUtils.hasClass(img, "loaderrorclass")
  18034. ) {
  18035. return;
  18036. }
  18037. if (!imageScale) {
  18038. imageScale = new Scale();
  18039. imageScale.init(me);
  18040. me.ui.getDom().appendChild(imageScale.resizer);
  18041. var _keyDownHandler = function(e) {
  18042. imageScale.hide();
  18043. if (imageScale.target)
  18044. me.selection.getRange().selectNode(imageScale.target).select();
  18045. },
  18046. _mouseDownHandler = function(e) {
  18047. var ele = e.target || e.srcElement;
  18048. if (
  18049. ele &&
  18050. (ele.className === undefined ||
  18051. ele.className.indexOf("edui-editor-imagescale") == -1)
  18052. ) {
  18053. _keyDownHandler(e);
  18054. }
  18055. },
  18056. timer;
  18057. me.addListener("afterscaleshow", function(e) {
  18058. me.addListener("beforekeydown", _keyDownHandler);
  18059. me.addListener("beforemousedown", _mouseDownHandler);
  18060. domUtils.on(document, "keydown", _keyDownHandler);
  18061. domUtils.on(document, "mousedown", _mouseDownHandler);
  18062. me.selection.getNative().removeAllRanges();
  18063. });
  18064. me.addListener("afterscalehide", function(e) {
  18065. me.removeListener("beforekeydown", _keyDownHandler);
  18066. me.removeListener("beforemousedown", _mouseDownHandler);
  18067. domUtils.un(document, "keydown", _keyDownHandler);
  18068. domUtils.un(document, "mousedown", _mouseDownHandler);
  18069. var target = imageScale.target;
  18070. if (target.parentNode) {
  18071. me.selection.getRange().selectNode(target).select();
  18072. }
  18073. });
  18074. //TODO 有iframe的情况,mousedown不能往下传。。
  18075. domUtils.on(imageScale.resizer, "mousedown", function(e) {
  18076. me.selection.getNative().removeAllRanges();
  18077. var ele = e.target || e.srcElement;
  18078. if (
  18079. ele &&
  18080. ele.className.indexOf("edui-editor-imagescale-hand") == -1
  18081. ) {
  18082. timer = setTimeout(function() {
  18083. imageScale.hide();
  18084. if (imageScale.target)
  18085. me.selection.getRange().selectNode(ele).select();
  18086. }, 200);
  18087. }
  18088. });
  18089. domUtils.on(imageScale.resizer, "mouseup", function(e) {
  18090. var ele = e.target || e.srcElement;
  18091. if (
  18092. ele &&
  18093. ele.className.indexOf("edui-editor-imagescale-hand") == -1
  18094. ) {
  18095. clearTimeout(timer);
  18096. }
  18097. });
  18098. }
  18099. imageScale.show(img);
  18100. } else {
  18101. if (imageScale && imageScale.resizer.style.display != "none")
  18102. imageScale.hide();
  18103. }
  18104. });
  18105. }
  18106. if (browser.webkit) {
  18107. me.addListener("click", function(type, e) {
  18108. if (e.target.tagName == "IMG" && me.body.contentEditable != "false") {
  18109. var range = new dom.Range(me.document);
  18110. range.selectNode(e.target).select();
  18111. }
  18112. });
  18113. }
  18114. };
  18115. })();
  18116. // plugins/autolink.js
  18117. ///import core
  18118. ///commands 为非ie浏览器自动添加a标签
  18119. ///commandsName AutoLink
  18120. ///commandsTitle 自动增加链接
  18121. /**
  18122. * @description 为非ie浏览器自动添加a标签
  18123. * @author zhanyi
  18124. */
  18125. UE.plugin.register(
  18126. "autolink",
  18127. function() {
  18128. var cont = 0;
  18129. return !browser.ie
  18130. ? {
  18131. bindEvents: {
  18132. reset: function() {
  18133. cont = 0;
  18134. },
  18135. keydown: function(type, evt) {
  18136. var me = this;
  18137. var keyCode = evt.keyCode || evt.which;
  18138. if (keyCode == 32 || keyCode == 13) {
  18139. var sel = me.selection.getNative(),
  18140. range = sel.getRangeAt(0).cloneRange(),
  18141. offset,
  18142. charCode;
  18143. var start = range.startContainer;
  18144. while (start.nodeType == 1 && range.startOffset > 0) {
  18145. start =
  18146. range.startContainer.childNodes[range.startOffset - 1];
  18147. if (!start) {
  18148. break;
  18149. }
  18150. range.setStart(
  18151. start,
  18152. start.nodeType == 1
  18153. ? start.childNodes.length
  18154. : start.nodeValue.length
  18155. );
  18156. range.collapse(true);
  18157. start = range.startContainer;
  18158. }
  18159. do {
  18160. if (range.startOffset == 0) {
  18161. start = range.startContainer.previousSibling;
  18162. while (start && start.nodeType == 1) {
  18163. start = start.lastChild;
  18164. }
  18165. if (!start || domUtils.isFillChar(start)) {
  18166. break;
  18167. }
  18168. offset = start.nodeValue.length;
  18169. } else {
  18170. start = range.startContainer;
  18171. offset = range.startOffset;
  18172. }
  18173. range.setStart(start, offset - 1);
  18174. charCode = range.toString().charCodeAt(0);
  18175. } while (charCode != 160 && charCode != 32);
  18176. if (
  18177. range
  18178. .toString()
  18179. .replace(new RegExp(domUtils.fillChar, "g"), "")
  18180. .match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)
  18181. ) {
  18182. while (range.toString().length) {
  18183. if (
  18184. /^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(
  18185. range.toString()
  18186. )
  18187. ) {
  18188. break;
  18189. }
  18190. try {
  18191. range.setStart(
  18192. range.startContainer,
  18193. range.startOffset + 1
  18194. );
  18195. } catch (e) {
  18196. //trace:2121
  18197. var start = range.startContainer;
  18198. while (!(next = start.nextSibling)) {
  18199. if (domUtils.isBody(start)) {
  18200. return;
  18201. }
  18202. start = start.parentNode;
  18203. }
  18204. range.setStart(next, 0);
  18205. }
  18206. }
  18207. //range的开始边界已经在a标签里的不再处理
  18208. if (
  18209. domUtils.findParentByTagName(
  18210. range.startContainer,
  18211. "a",
  18212. true
  18213. )
  18214. ) {
  18215. return;
  18216. }
  18217. var a = me.document.createElement("a"),
  18218. text = me.document.createTextNode(" "),
  18219. href;
  18220. me.undoManger && me.undoManger.save();
  18221. a.appendChild(range.extractContents());
  18222. a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, "");
  18223. href = a
  18224. .getAttribute("href")
  18225. .replace(new RegExp(domUtils.fillChar, "g"), "");
  18226. href = /^(?:https?:\/\/)/gi.test(href)
  18227. ? href
  18228. : "http://" + href;
  18229. a.setAttribute("_src", utils.html(href));
  18230. a.href = utils.html(href);
  18231. range.insertNode(a);
  18232. a.parentNode.insertBefore(text, a.nextSibling);
  18233. range.setStart(text, 0);
  18234. range.collapse(true);
  18235. sel.removeAllRanges();
  18236. sel.addRange(range);
  18237. me.undoManger && me.undoManger.save();
  18238. }
  18239. }
  18240. }
  18241. }
  18242. }
  18243. : {};
  18244. },
  18245. function() {
  18246. var keyCodes = {
  18247. 37: 1,
  18248. 38: 1,
  18249. 39: 1,
  18250. 40: 1,
  18251. 13: 1,
  18252. 32: 1
  18253. };
  18254. function checkIsCludeLink(node) {
  18255. if (node.nodeType == 3) {
  18256. return null;
  18257. }
  18258. if (node.nodeName == "A") {
  18259. return node;
  18260. }
  18261. var lastChild = node.lastChild;
  18262. while (lastChild) {
  18263. if (lastChild.nodeName == "A") {
  18264. return lastChild;
  18265. }
  18266. if (lastChild.nodeType == 3) {
  18267. if (domUtils.isWhitespace(lastChild)) {
  18268. lastChild = lastChild.previousSibling;
  18269. continue;
  18270. }
  18271. return null;
  18272. }
  18273. lastChild = lastChild.lastChild;
  18274. }
  18275. }
  18276. browser.ie &&
  18277. this.addListener("keyup", function(cmd, evt) {
  18278. var me = this,
  18279. keyCode = evt.keyCode;
  18280. if (keyCodes[keyCode]) {
  18281. var rng = me.selection.getRange();
  18282. var start = rng.startContainer;
  18283. if (keyCode == 13) {
  18284. while (
  18285. start &&
  18286. !domUtils.isBody(start) &&
  18287. !domUtils.isBlockElm(start)
  18288. ) {
  18289. start = start.parentNode;
  18290. }
  18291. if (start && !domUtils.isBody(start) && start.nodeName == "P") {
  18292. var pre = start.previousSibling;
  18293. if (pre && pre.nodeType == 1) {
  18294. var pre = checkIsCludeLink(pre);
  18295. if (pre && !pre.getAttribute("_href")) {
  18296. domUtils.remove(pre, true);
  18297. }
  18298. }
  18299. }
  18300. } else if (keyCode == 32) {
  18301. if (start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
  18302. start = start.previousSibling;
  18303. if (
  18304. start &&
  18305. start.nodeName == "A" &&
  18306. !start.getAttribute("_href")
  18307. ) {
  18308. domUtils.remove(start, true);
  18309. }
  18310. }
  18311. } else {
  18312. start = domUtils.findParentByTagName(start, "a", true);
  18313. if (start && !start.getAttribute("_href")) {
  18314. var bk = rng.createBookmark();
  18315. domUtils.remove(start, true);
  18316. rng.moveToBookmark(bk).select(true);
  18317. }
  18318. }
  18319. }
  18320. });
  18321. }
  18322. );
  18323. // plugins/autoheight.js
  18324. ///import core
  18325. ///commands 当输入内容超过编辑器高度时,编辑器自动增高
  18326. ///commandsName AutoHeight,autoHeightEnabled
  18327. ///commandsTitle 自动增高
  18328. /**
  18329. * @description 自动伸展
  18330. * @author zhanyi
  18331. */
  18332. UE.plugins["autoheight"] = function() {
  18333. var me = this;
  18334. //提供开关,就算加载也可以关闭
  18335. me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
  18336. if (!me.autoHeightEnabled) {
  18337. return;
  18338. }
  18339. var bakOverflow,
  18340. lastHeight = 0,
  18341. options = me.options,
  18342. currentHeight,
  18343. timer;
  18344. function adjustHeight() {
  18345. var me = this;
  18346. clearTimeout(timer);
  18347. if (isFullscreen) return;
  18348. if (
  18349. !me.queryCommandState ||
  18350. (me.queryCommandState && me.queryCommandState("source") != 1)
  18351. ) {
  18352. timer = setTimeout(function() {
  18353. var node = me.body.lastChild;
  18354. while (node && node.nodeType != 1) {
  18355. node = node.previousSibling;
  18356. }
  18357. if (node && node.nodeType == 1) {
  18358. node.style.clear = "both";
  18359. currentHeight = Math.max(
  18360. domUtils.getXY(node).y + node.offsetHeight + 25,
  18361. Math.max(options.minFrameHeight, options.initialFrameHeight)
  18362. );
  18363. if (currentHeight != lastHeight) {
  18364. if (currentHeight !== parseInt(me.iframe.parentNode.style.height)) {
  18365. me.iframe.parentNode.style.height = currentHeight + "px";
  18366. }
  18367. me.body.style.height = currentHeight + "px";
  18368. lastHeight = currentHeight;
  18369. }
  18370. domUtils.removeStyle(node, "clear");
  18371. }
  18372. }, 50);
  18373. }
  18374. }
  18375. var isFullscreen;
  18376. me.addListener("fullscreenchanged", function(cmd, f) {
  18377. isFullscreen = f;
  18378. });
  18379. me.addListener("destroy", function() {
  18380. domUtils.un(me.window, "scroll", fixedScrollTop);
  18381. me.removeListener(
  18382. "contentchange afterinserthtml keyup mouseup",
  18383. adjustHeight
  18384. );
  18385. });
  18386. me.enableAutoHeight = function() {
  18387. var me = this;
  18388. if (!me.autoHeightEnabled) {
  18389. return;
  18390. }
  18391. var doc = me.document;
  18392. me.autoHeightEnabled = true;
  18393. bakOverflow = doc.body.style.overflowY;
  18394. doc.body.style.overflowY = "hidden";
  18395. me.addListener("contentchange afterinserthtml keyup mouseup", adjustHeight);
  18396. //ff不给事件算得不对
  18397. setTimeout(function() {
  18398. adjustHeight.call(me);
  18399. }, browser.gecko ? 100 : 0);
  18400. me.fireEvent("autoheightchanged", me.autoHeightEnabled);
  18401. };
  18402. me.disableAutoHeight = function() {
  18403. me.body.style.overflowY = bakOverflow || "";
  18404. me.removeListener("contentchange", adjustHeight);
  18405. me.removeListener("keyup", adjustHeight);
  18406. me.removeListener("mouseup", adjustHeight);
  18407. me.autoHeightEnabled = false;
  18408. me.fireEvent("autoheightchanged", me.autoHeightEnabled);
  18409. };
  18410. me.on("setHeight", function() {
  18411. me.disableAutoHeight();
  18412. });
  18413. me.addListener("ready", function() {
  18414. me.enableAutoHeight();
  18415. //trace:1764
  18416. var timer;
  18417. domUtils.on(
  18418. browser.ie ? me.body : me.document,
  18419. browser.webkit ? "dragover" : "drop",
  18420. function() {
  18421. clearTimeout(timer);
  18422. timer = setTimeout(function() {
  18423. //trace:3681
  18424. adjustHeight.call(me);
  18425. }, 100);
  18426. }
  18427. );
  18428. //修复内容过多时,回到顶部,顶部内容被工具栏遮挡问题
  18429. domUtils.on(me.window, "scroll", fixedScrollTop);
  18430. });
  18431. var lastScrollY;
  18432. function fixedScrollTop() {
  18433. if (!me.window) return;
  18434. if (lastScrollY === null) {
  18435. lastScrollY = me.window.scrollY;
  18436. } else if (me.window.scrollY == 0 && lastScrollY != 0) {
  18437. me.window.scrollTo(0, 0);
  18438. lastScrollY = null;
  18439. }
  18440. }
  18441. };
  18442. // plugins/autofloat.js
  18443. ///import core
  18444. ///commands 悬浮工具栏
  18445. ///commandsName AutoFloat,autoFloatEnabled
  18446. ///commandsTitle 悬浮工具栏
  18447. /**
  18448. * modified by chengchao01
  18449. * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
  18450. */
  18451. UE.plugins["autofloat"] = function() {
  18452. var me = this,
  18453. lang = me.getLang();
  18454. me.setOpt({
  18455. topOffset: 0
  18456. });
  18457. var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
  18458. topOffset = me.options.topOffset;
  18459. //如果不固定toolbar的位置,则直接退出
  18460. if (!optsAutoFloatEnabled) {
  18461. return;
  18462. }
  18463. var uiUtils = UE.ui.uiUtils,
  18464. LteIE6 = browser.ie && browser.version <= 6,
  18465. quirks = browser.quirks;
  18466. function checkHasUI() {
  18467. if (!UE.ui) {
  18468. alert(lang.autofloatMsg);
  18469. return 0;
  18470. }
  18471. return 1;
  18472. }
  18473. function fixIE6FixedPos() {
  18474. var docStyle = document.body.style;
  18475. docStyle.backgroundImage = 'url("about:blank")';
  18476. docStyle.backgroundAttachment = "fixed";
  18477. }
  18478. var bakCssText,
  18479. placeHolder = document.createElement("div"),
  18480. toolbarBox,
  18481. orgTop,
  18482. getPosition,
  18483. flag = true; //ie7模式下需要偏移
  18484. function setFloating() {
  18485. var toobarBoxPos = domUtils.getXY(toolbarBox),
  18486. origalFloat = domUtils.getComputedStyle(toolbarBox, "position"),
  18487. origalLeft = domUtils.getComputedStyle(toolbarBox, "left");
  18488. toolbarBox.style.width = toolbarBox.offsetWidth + "px";
  18489. toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
  18490. toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
  18491. if (LteIE6 || (quirks && browser.ie)) {
  18492. if (toolbarBox.style.position != "absolute") {
  18493. toolbarBox.style.position = "absolute";
  18494. }
  18495. toolbarBox.style.top =
  18496. (document.body.scrollTop || document.documentElement.scrollTop) -
  18497. orgTop +
  18498. topOffset +
  18499. "px";
  18500. } else {
  18501. if (browser.ie7Compat && flag) {
  18502. flag = false;
  18503. toolbarBox.style.left =
  18504. domUtils.getXY(toolbarBox).x -
  18505. document.documentElement.getBoundingClientRect().left +
  18506. 2 +
  18507. "px";
  18508. }
  18509. if (toolbarBox.style.position != "fixed") {
  18510. toolbarBox.style.position = "fixed";
  18511. toolbarBox.style.top = topOffset + "px";
  18512. (origalFloat == "absolute" || origalFloat == "relative") &&
  18513. parseFloat(origalLeft) &&
  18514. (toolbarBox.style.left = toobarBoxPos.x + "px");
  18515. }
  18516. }
  18517. }
  18518. function unsetFloating() {
  18519. flag = true;
  18520. if (placeHolder.parentNode) {
  18521. placeHolder.parentNode.removeChild(placeHolder);
  18522. }
  18523. toolbarBox.style.cssText = bakCssText;
  18524. }
  18525. function updateFloating() {
  18526. var rect3 = getPosition(me.container);
  18527. var offset = me.options.toolbarTopOffset || 0;
  18528. if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
  18529. setFloating();
  18530. } else {
  18531. unsetFloating();
  18532. }
  18533. }
  18534. var defer_updateFloating = utils.defer(
  18535. function() {
  18536. updateFloating();
  18537. },
  18538. browser.ie ? 200 : 100,
  18539. true
  18540. );
  18541. me.addListener("destroy", function() {
  18542. domUtils.un(window, ["scroll", "resize"], updateFloating);
  18543. me.removeListener("keydown", defer_updateFloating);
  18544. //适用于在DIV scrollbox中滚动,但页面不滚动的浮动toolbar
  18545. var scrollBox = document.getElementById("scrollBox");
  18546. if (scrollBox) {
  18547. domUtils.un(scrollBox, ['scroll','resize'], updateFloating);
  18548. }
  18549. });
  18550. me.addListener("ready", function() {
  18551. if (checkHasUI(me)) {
  18552. //加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断
  18553. if (!me.ui) {
  18554. return;
  18555. }
  18556. getPosition = uiUtils.getClientRect;
  18557. toolbarBox = me.ui.getDom("toolbarbox");
  18558. orgTop = getPosition(toolbarBox).top;
  18559. bakCssText = toolbarBox.style.cssText;
  18560. placeHolder.style.height = toolbarBox.offsetHeight + "px";
  18561. if (LteIE6) {
  18562. fixIE6FixedPos();
  18563. }
  18564. domUtils.on(window, ["scroll", "resize"], updateFloating);
  18565. me.addListener("keydown", defer_updateFloating);
  18566. //适用于在DIV scrollbox中滚动,但页面不滚动的浮动toolbar
  18567. var scrollBox = document.getElementById("scrollBox");
  18568. if (scrollBox) {
  18569. domUtils.on(scrollBox, ['scroll','resize'], updateFloating);
  18570. }
  18571. me.addListener("beforefullscreenchange", function(t, enabled) {
  18572. if (enabled) {
  18573. unsetFloating();
  18574. }
  18575. });
  18576. me.addListener("fullscreenchanged", function(t, enabled) {
  18577. if (!enabled) {
  18578. updateFloating();
  18579. }
  18580. });
  18581. me.addListener("sourcemodechanged", function(t, enabled) {
  18582. setTimeout(function() {
  18583. updateFloating();
  18584. }, 0);
  18585. });
  18586. me.addListener("clearDoc", function() {
  18587. setTimeout(function() {
  18588. updateFloating();
  18589. }, 0);
  18590. });
  18591. }
  18592. });
  18593. };
  18594. // plugins/video.js
  18595. /**
  18596. * video插件, 为UEditor提供视频插入支持
  18597. * @file
  18598. * @since 1.2.6.1
  18599. */
  18600. UE.plugins["video"] = function() {
  18601. var me = this;
  18602. /**
  18603. * 创建插入视频字符窜
  18604. * @param url 视频地址
  18605. * @param width 视频宽度
  18606. * @param height 视频高度
  18607. * @param align 视频对齐
  18608. * @param toEmbed 是否以flash代替显示
  18609. * @param addParagraph 是否需要添加P 标签
  18610. */
  18611. function creatInsertStr(url, width, height, id, align, classname, type) {
  18612. var str;
  18613. switch (type) {
  18614. case "image":
  18615. str =
  18616. "<img " +
  18617. (id ? 'id="' + id + '"' : "") +
  18618. ' width="' +
  18619. width +
  18620. '" height="' +
  18621. height +
  18622. '" _url="' +
  18623. url +
  18624. '" class="' +
  18625. classname.replace(/\bvideo-js\b/, "") +
  18626. '"' +
  18627. ' src="' +
  18628. me.options.UEDITOR_HOME_URL +
  18629. 'themes/notadd/images/spacer.gif" style="background:url(' +
  18630. me.options.UEDITOR_HOME_URL +
  18631. "themes/notadd/images/videologo.gif) no-repeat center center; border:1px solid gray;" +
  18632. (align ? "float:" + align + ";" : "") +
  18633. '" />';
  18634. break;
  18635. case "embed":
  18636. str =
  18637. '<embed type="application/x-shockwave-flash" class="' +
  18638. classname +
  18639. '" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  18640. ' src="' +
  18641. utils.html(url) +
  18642. '" width="' +
  18643. width +
  18644. '" height="' +
  18645. height +
  18646. '"' +
  18647. (align ? ' style="float:' + align + '"' : "") +
  18648. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  18649. break;
  18650. case "video":
  18651. var ext = url.substr(url.lastIndexOf(".") + 1);
  18652. if (ext == "ogv") ext = "ogg";
  18653. str =
  18654. "<video" +
  18655. (id ? ' id="' + id + '"' : "") +
  18656. ' class="' +
  18657. classname +
  18658. ' video-js" ' +
  18659. (align ? ' style="float:' + align + '"' : "") +
  18660. ' controls preload="none" width="' +
  18661. width +
  18662. '" height="' +
  18663. height +
  18664. '" src="' +
  18665. url +
  18666. '" data-setup="{}">' +
  18667. '<source src="' +
  18668. url +
  18669. '" type="video/' +
  18670. ext +
  18671. '" /></video>';
  18672. break;
  18673. }
  18674. return str;
  18675. }
  18676. function switchImgAndVideo(root, img2video) {
  18677. utils.each(
  18678. root.getNodesByTagName(img2video ? "img" : "embed video"),
  18679. function(node) {
  18680. var className = node.getAttr("class");
  18681. if (className && className.indexOf("edui-faked-video") != -1) {
  18682. var html = creatInsertStr(
  18683. img2video ? node.getAttr("_url") : node.getAttr("src"),
  18684. node.getAttr("width"),
  18685. node.getAttr("height"),
  18686. null,
  18687. node.getStyle("float") || "",
  18688. className,
  18689. img2video ? "embed" : "image"
  18690. );
  18691. node.parentNode.replaceChild(UE.uNode.createElement(html), node);
  18692. }
  18693. if (className && className.indexOf("edui-upload-video") != -1) {
  18694. var html = creatInsertStr(
  18695. img2video ? node.getAttr("_url") : node.getAttr("src"),
  18696. node.getAttr("width"),
  18697. node.getAttr("height"),
  18698. null,
  18699. node.getStyle("float") || "",
  18700. className,
  18701. img2video ? "video" : "image"
  18702. );
  18703. node.parentNode.replaceChild(UE.uNode.createElement(html), node);
  18704. }
  18705. }
  18706. );
  18707. }
  18708. me.addOutputRule(function(root) {
  18709. switchImgAndVideo(root, true);
  18710. });
  18711. me.addInputRule(function(root) {
  18712. switchImgAndVideo(root);
  18713. });
  18714. /**
  18715. * 插入视频
  18716. * @command insertvideo
  18717. * @method execCommand
  18718. * @param { String } cmd 命令字符串
  18719. * @param { Object } videoAttr 键值对对象, 描述一个视频的所有属性
  18720. * @example
  18721. * ```javascript
  18722. *
  18723. * var videoAttr = {
  18724. * //视频地址
  18725. * url: 'http://www.youku.com/xxx',
  18726. * //视频宽高值, 单位px
  18727. * width: 200,
  18728. * height: 100
  18729. * };
  18730. *
  18731. * //editor 是编辑器实例
  18732. * //向编辑器插入单个视频
  18733. * editor.execCommand( 'insertvideo', videoAttr );
  18734. * ```
  18735. */
  18736. /**
  18737. * 插入视频
  18738. * @command insertvideo
  18739. * @method execCommand
  18740. * @param { String } cmd 命令字符串
  18741. * @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
  18742. * @example
  18743. * ```javascript
  18744. *
  18745. * var videoAttr1 = {
  18746. * //视频地址
  18747. * url: 'http://www.youku.com/xxx',
  18748. * //视频宽高值, 单位px
  18749. * width: 200,
  18750. * height: 100
  18751. * },
  18752. * videoAttr2 = {
  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', [ videoAttr1, videoAttr2 ] );
  18763. * ```
  18764. */
  18765. /**
  18766. * 查询当前光标所在处是否是一个视频
  18767. * @command insertvideo
  18768. * @method queryCommandState
  18769. * @param { String } cmd 需要查询的命令字符串
  18770. * @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
  18771. * @example
  18772. * ```javascript
  18773. *
  18774. * //editor 是编辑器实例
  18775. * editor.queryCommandState( 'insertvideo' );
  18776. * ```
  18777. */
  18778. me.commands["insertvideo"] = {
  18779. execCommand: function(cmd, videoObjs, type) {
  18780. videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs];
  18781. if (me.fireEvent("beforeinsertvideo", videoObjs) === true) {
  18782. return;
  18783. }
  18784. var html = [],
  18785. id = "tmpVedio",
  18786. cl;
  18787. for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
  18788. vi = videoObjs[i];
  18789. cl = type == "upload"
  18790. ? "edui-upload-video video-js vjs-default-skin"
  18791. : "edui-faked-video";
  18792. html.push(
  18793. creatInsertStr(
  18794. vi.url,
  18795. vi.width || 420,
  18796. vi.height || 280,
  18797. id + i,
  18798. null,
  18799. cl,
  18800. "image"
  18801. )
  18802. );
  18803. }
  18804. me.execCommand("inserthtml", html.join(""), true);
  18805. var rng = this.selection.getRange();
  18806. for (var i = 0, len = videoObjs.length; i < len; i++) {
  18807. var img = this.document.getElementById("tmpVedio" + i);
  18808. domUtils.removeAttributes(img, "id");
  18809. rng.selectNode(img).select();
  18810. me.execCommand("imagefloat", videoObjs[i].align);
  18811. }
  18812. me.fireEvent("afterinsertvideo", videoObjs);
  18813. },
  18814. queryCommandState: function() {
  18815. var img = me.selection.getRange().getClosedNode(),
  18816. flag =
  18817. img &&
  18818. (img.className == "edui-faked-video" ||
  18819. img.className.indexOf("edui-upload-video") != -1);
  18820. return flag ? 1 : 0;
  18821. }
  18822. };
  18823. };
  18824. // plugins/table.core.js
  18825. /**
  18826. * Created with JetBrains WebStorm.
  18827. * User: taoqili
  18828. * Date: 13-1-18
  18829. * Time: 上午11:09
  18830. * To change this template use File | Settings | File Templates.
  18831. */
  18832. /**
  18833. * UE表格操作类
  18834. * @param table
  18835. * @constructor
  18836. */
  18837. ;(function() {
  18838. var UETable = (UE.UETable = function(table) {
  18839. this.table = table;
  18840. this.indexTable = [];
  18841. this.selectedTds = [];
  18842. this.cellsRange = {};
  18843. this.update(table);
  18844. });
  18845. //===以下为静态工具方法===
  18846. UETable.removeSelectedClass = function(cells) {
  18847. utils.each(cells, function(cell) {
  18848. domUtils.removeClasses(cell, "selectTdClass");
  18849. });
  18850. };
  18851. UETable.addSelectedClass = function(cells) {
  18852. utils.each(cells, function(cell) {
  18853. domUtils.addClass(cell, "selectTdClass");
  18854. });
  18855. };
  18856. UETable.isEmptyBlock = function(node) {
  18857. var reg = new RegExp(domUtils.fillChar, "g");
  18858. if (
  18859. node[browser.ie ? "innerText" : "textContent"]
  18860. .replace(/^\s*$/, "")
  18861. .replace(reg, "").length > 0
  18862. ) {
  18863. return 0;
  18864. }
  18865. for (var i in dtd.$isNotEmpty)
  18866. if (dtd.$isNotEmpty.hasOwnProperty(i)) {
  18867. if (node.getElementsByTagName(i).length) {
  18868. return 0;
  18869. }
  18870. }
  18871. return 1;
  18872. };
  18873. UETable.getWidth = function(cell) {
  18874. if (!cell) return 0;
  18875. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  18876. };
  18877. /**
  18878. * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
  18879. * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
  18880. * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
  18881. * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
  18882. */
  18883. UETable.getTableCellAlignState = function(cells) {
  18884. !utils.isArray(cells) && (cells = [cells]);
  18885. var result = {},
  18886. status = ["align", "valign"],
  18887. tempStatus = null,
  18888. isSame = true; //状态是否相同
  18889. utils.each(cells, function(cellNode) {
  18890. utils.each(status, function(currentState) {
  18891. tempStatus = cellNode.getAttribute(currentState);
  18892. if (!result[currentState] && tempStatus) {
  18893. result[currentState] = tempStatus;
  18894. } else if (
  18895. !result[currentState] ||
  18896. tempStatus !== result[currentState]
  18897. ) {
  18898. isSame = false;
  18899. return false;
  18900. }
  18901. });
  18902. return isSame;
  18903. });
  18904. return isSame ? result : null;
  18905. };
  18906. /**
  18907. * 根据当前选区获取相关的table信息
  18908. * @return {Object}
  18909. */
  18910. UETable.getTableItemsByRange = function(editor) {
  18911. var start = editor.selection.getStart();
  18912. //ff下会选中bookmark
  18913. if (
  18914. start &&
  18915. start.id &&
  18916. start.id.indexOf("_baidu_bookmark_start_") === 0 &&
  18917. start.nextSibling
  18918. ) {
  18919. start = start.nextSibling;
  18920. }
  18921. //在table或者td边缘有可能存在选中tr的情况
  18922. var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
  18923. tr = cell && cell.parentNode,
  18924. table = tr && domUtils.findParentByTagName(tr, ["table"]),
  18925. caption = table && table.getElementsByTagName("caption")[0];
  18926. return {
  18927. cell: cell,
  18928. tr: tr,
  18929. table: table,
  18930. caption: caption
  18931. };
  18932. };
  18933. UETable.getUETableBySelected = function(editor) {
  18934. var table = UETable.getTableItemsByRange(editor).table;
  18935. if (table && table.ueTable && table.ueTable.selectedTds.length) {
  18936. return table.ueTable;
  18937. }
  18938. return null;
  18939. };
  18940. UETable.getDefaultValue = function(editor, table) {
  18941. var borderMap = {
  18942. thin: "0px",
  18943. medium: "1px",
  18944. thick: "2px"
  18945. },
  18946. tableBorder,
  18947. tdPadding,
  18948. tdBorder,
  18949. tmpValue;
  18950. if (!table) {
  18951. table = editor.document.createElement("table");
  18952. table.insertRow(0).insertCell(0).innerHTML = "xxx";
  18953. editor.body.appendChild(table);
  18954. var td = table.getElementsByTagName("td")[0];
  18955. tmpValue = domUtils.getComputedStyle(table, "border-left-width");
  18956. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18957. tmpValue = domUtils.getComputedStyle(td, "padding-left");
  18958. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18959. tmpValue = domUtils.getComputedStyle(td, "border-left-width");
  18960. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18961. domUtils.remove(table);
  18962. return {
  18963. tableBorder: tableBorder,
  18964. tdPadding: tdPadding,
  18965. tdBorder: tdBorder
  18966. };
  18967. } else {
  18968. td = table.getElementsByTagName("td")[0];
  18969. tmpValue = domUtils.getComputedStyle(table, "border-left-width");
  18970. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18971. tmpValue = domUtils.getComputedStyle(td, "padding-left");
  18972. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18973. tmpValue = domUtils.getComputedStyle(td, "border-left-width");
  18974. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  18975. return {
  18976. tableBorder: tableBorder,
  18977. tdPadding: tdPadding,
  18978. tdBorder: tdBorder
  18979. };
  18980. }
  18981. };
  18982. /**
  18983. * 根据当前点击的td或者table获取索引对象
  18984. * @param tdOrTable
  18985. */
  18986. UETable.getUETable = function(tdOrTable) {
  18987. var tag = tdOrTable.tagName.toLowerCase();
  18988. tdOrTable = tag == "td" || tag == "th" || tag == "caption"
  18989. ? domUtils.findParentByTagName(tdOrTable, "table", true)
  18990. : tdOrTable;
  18991. if (!tdOrTable.ueTable) {
  18992. tdOrTable.ueTable = new UETable(tdOrTable);
  18993. }
  18994. return tdOrTable.ueTable;
  18995. };
  18996. UETable.cloneCell = function(cell, ignoreMerge, keepPro) {
  18997. if (!cell || utils.isString(cell)) {
  18998. return this.table.ownerDocument.createElement(cell || "td");
  18999. }
  19000. var flag = domUtils.hasClass(cell, "selectTdClass");
  19001. flag && domUtils.removeClasses(cell, "selectTdClass");
  19002. var tmpCell = cell.cloneNode(true);
  19003. if (ignoreMerge) {
  19004. tmpCell.rowSpan = tmpCell.colSpan = 1;
  19005. }
  19006. //去掉宽高
  19007. !keepPro && domUtils.removeAttributes(tmpCell, "width height");
  19008. !keepPro && domUtils.removeAttributes(tmpCell, "style");
  19009. tmpCell.style.borderLeftStyle = "";
  19010. tmpCell.style.borderTopStyle = "";
  19011. tmpCell.style.borderLeftColor = cell.style.borderRightColor;
  19012. tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
  19013. tmpCell.style.borderTopColor = cell.style.borderBottomColor;
  19014. tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
  19015. flag && domUtils.addClass(cell, "selectTdClass");
  19016. return tmpCell;
  19017. };
  19018. UETable.prototype = {
  19019. getMaxRows: function() {
  19020. var rows = this.table.rows,
  19021. maxLen = 1;
  19022. for (var i = 0, row; (row = rows[i]); i++) {
  19023. var currentMax = 1;
  19024. for (var j = 0, cj; (cj = row.cells[j++]); ) {
  19025. currentMax = Math.max(cj.rowSpan || 1, currentMax);
  19026. }
  19027. maxLen = Math.max(currentMax + i, maxLen);
  19028. }
  19029. return maxLen;
  19030. },
  19031. /**
  19032. * 获取当前表格的最大列数
  19033. */
  19034. getMaxCols: function() {
  19035. var rows = this.table.rows,
  19036. maxLen = 0,
  19037. cellRows = {};
  19038. for (var i = 0, row; (row = rows[i]); i++) {
  19039. var cellsNum = 0;
  19040. for (var j = 0, cj; (cj = row.cells[j++]); ) {
  19041. cellsNum += cj.colSpan || 1;
  19042. if (cj.rowSpan && cj.rowSpan > 1) {
  19043. for (var k = 1; k < cj.rowSpan; k++) {
  19044. if (!cellRows["row_" + (i + k)]) {
  19045. cellRows["row_" + (i + k)] = cj.colSpan || 1;
  19046. } else {
  19047. cellRows["row_" + (i + k)]++;
  19048. }
  19049. }
  19050. }
  19051. }
  19052. cellsNum += cellRows["row_" + i] || 0;
  19053. maxLen = Math.max(cellsNum, maxLen);
  19054. }
  19055. return maxLen;
  19056. },
  19057. getCellColIndex: function(cell) {},
  19058. /**
  19059. * 获取当前cell旁边的单元格,
  19060. * @param cell
  19061. * @param right
  19062. */
  19063. getHSideCell: function(cell, right) {
  19064. try {
  19065. var cellInfo = this.getCellInfo(cell),
  19066. previewRowIndex,
  19067. previewColIndex;
  19068. var len = this.selectedTds.length,
  19069. range = this.cellsRange;
  19070. //首行或者首列没有前置单元格
  19071. if (
  19072. (!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
  19073. (right &&
  19074. (!len
  19075. ? cellInfo.colIndex == this.colsNum - 1
  19076. : range.endColIndex == this.colsNum - 1))
  19077. )
  19078. return null;
  19079. previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
  19080. previewColIndex = !right
  19081. ? !len
  19082. ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
  19083. : range.beginColIndex - 1
  19084. : !len ? cellInfo.colIndex + 1 : range.endColIndex + 1;
  19085. return this.getCell(
  19086. this.indexTable[previewRowIndex][previewColIndex].rowIndex,
  19087. this.indexTable[previewRowIndex][previewColIndex].cellIndex
  19088. );
  19089. } catch (e) {
  19090. showError(e);
  19091. }
  19092. },
  19093. getTabNextCell: function(cell, preRowIndex) {
  19094. var cellInfo = this.getCellInfo(cell),
  19095. rowIndex = preRowIndex || cellInfo.rowIndex,
  19096. colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
  19097. nextCell;
  19098. try {
  19099. nextCell = this.getCell(
  19100. this.indexTable[rowIndex][colIndex].rowIndex,
  19101. this.indexTable[rowIndex][colIndex].cellIndex
  19102. );
  19103. } catch (e) {
  19104. try {
  19105. rowIndex = rowIndex * 1 + 1;
  19106. colIndex = 0;
  19107. nextCell = this.getCell(
  19108. this.indexTable[rowIndex][colIndex].rowIndex,
  19109. this.indexTable[rowIndex][colIndex].cellIndex
  19110. );
  19111. } catch (e) {}
  19112. }
  19113. return nextCell;
  19114. },
  19115. /**
  19116. * 获取视觉上的后置单元格
  19117. * @param cell
  19118. * @param bottom
  19119. */
  19120. getVSideCell: function(cell, bottom, ignoreRange) {
  19121. try {
  19122. var cellInfo = this.getCellInfo(cell),
  19123. nextRowIndex,
  19124. nextColIndex;
  19125. var len = this.selectedTds.length && !ignoreRange,
  19126. range = this.cellsRange;
  19127. //末行或者末列没有后置单元格
  19128. if (
  19129. (!bottom && cellInfo.rowIndex == 0) ||
  19130. (bottom &&
  19131. (!len
  19132. ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
  19133. : range.endRowIndex == this.rowsNum - 1))
  19134. )
  19135. return null;
  19136. nextRowIndex = !bottom
  19137. ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
  19138. : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
  19139. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  19140. return this.getCell(
  19141. this.indexTable[nextRowIndex][nextColIndex].rowIndex,
  19142. this.indexTable[nextRowIndex][nextColIndex].cellIndex
  19143. );
  19144. } catch (e) {
  19145. showError(e);
  19146. }
  19147. },
  19148. /**
  19149. * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
  19150. */
  19151. getSameEndPosCells: function(cell, xOrY) {
  19152. try {
  19153. var flag = xOrY.toLowerCase() === "x",
  19154. end =
  19155. domUtils.getXY(cell)[flag ? "x" : "y"] +
  19156. cell["offset" + (flag ? "Width" : "Height")],
  19157. rows = this.table.rows,
  19158. cells = null,
  19159. returns = [];
  19160. for (var i = 0; i < this.rowsNum; i++) {
  19161. cells = rows[i].cells;
  19162. for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
  19163. var tmpEnd =
  19164. domUtils.getXY(tmpCell)[flag ? "x" : "y"] +
  19165. tmpCell["offset" + (flag ? "Width" : "Height")];
  19166. //对应行的td已经被上面行rowSpan了
  19167. if (tmpEnd > end && flag) break;
  19168. if (cell == tmpCell || end == tmpEnd) {
  19169. //只获取单一的单元格
  19170. //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
  19171. if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
  19172. returns.push(tmpCell);
  19173. }
  19174. if (flag) break;
  19175. }
  19176. }
  19177. }
  19178. return returns;
  19179. } catch (e) {
  19180. showError(e);
  19181. }
  19182. },
  19183. setCellContent: function(cell, content) {
  19184. cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />");
  19185. },
  19186. cloneCell: UETable.cloneCell,
  19187. /**
  19188. * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
  19189. */
  19190. getSameStartPosXCells: function(cell) {
  19191. try {
  19192. var start = domUtils.getXY(cell).x + cell.offsetWidth,
  19193. rows = this.table.rows,
  19194. cells,
  19195. returns = [];
  19196. for (var i = 0; i < this.rowsNum; i++) {
  19197. cells = rows[i].cells;
  19198. for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
  19199. var tmpStart = domUtils.getXY(tmpCell).x;
  19200. if (tmpStart > start) break;
  19201. if (tmpStart == start && tmpCell.colSpan == 1) {
  19202. returns.push(tmpCell);
  19203. break;
  19204. }
  19205. }
  19206. }
  19207. return returns;
  19208. } catch (e) {
  19209. showError(e);
  19210. }
  19211. },
  19212. /**
  19213. * 更新table对应的索引表
  19214. */
  19215. update: function(table) {
  19216. this.table = table || this.table;
  19217. this.selectedTds = [];
  19218. this.cellsRange = {};
  19219. this.indexTable = [];
  19220. var rows = this.table.rows,
  19221. rowsNum = this.getMaxRows(),
  19222. dNum = rowsNum - rows.length,
  19223. colsNum = this.getMaxCols();
  19224. while (dNum--) {
  19225. this.table.insertRow(rows.length);
  19226. }
  19227. this.rowsNum = rowsNum;
  19228. this.colsNum = colsNum;
  19229. for (var i = 0, len = rows.length; i < len; i++) {
  19230. this.indexTable[i] = new Array(colsNum);
  19231. }
  19232. //填充索引表
  19233. for (var rowIndex = 0, row; (row = rows[rowIndex]); rowIndex++) {
  19234. for (
  19235. var cellIndex = 0, cell, cells = row.cells;
  19236. (cell = cells[cellIndex]);
  19237. cellIndex++
  19238. ) {
  19239. //修正整行被rowSpan时导致的行数计算错误
  19240. if (cell.rowSpan > rowsNum) {
  19241. cell.rowSpan = rowsNum;
  19242. }
  19243. var colIndex = cellIndex,
  19244. rowSpan = cell.rowSpan || 1,
  19245. colSpan = cell.colSpan || 1;
  19246. //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
  19247. while (this.indexTable[rowIndex][colIndex]) colIndex++;
  19248. for (var j = 0; j < rowSpan; j++) {
  19249. for (var k = 0; k < colSpan; k++) {
  19250. this.indexTable[rowIndex + j][colIndex + k] = {
  19251. rowIndex: rowIndex,
  19252. cellIndex: cellIndex,
  19253. colIndex: colIndex,
  19254. rowSpan: rowSpan,
  19255. colSpan: colSpan
  19256. };
  19257. }
  19258. }
  19259. }
  19260. }
  19261. //修复残缺td
  19262. for (j = 0; j < rowsNum; j++) {
  19263. for (k = 0; k < colsNum; k++) {
  19264. if (this.indexTable[j][k] === undefined) {
  19265. row = rows[j];
  19266. cell = row.cells[row.cells.length - 1];
  19267. cell = cell
  19268. ? cell.cloneNode(true)
  19269. : this.table.ownerDocument.createElement("td");
  19270. this.setCellContent(cell);
  19271. if (cell.colSpan !== 1) cell.colSpan = 1;
  19272. if (cell.rowSpan !== 1) cell.rowSpan = 1;
  19273. row.appendChild(cell);
  19274. this.indexTable[j][k] = {
  19275. rowIndex: j,
  19276. cellIndex: cell.cellIndex,
  19277. colIndex: k,
  19278. rowSpan: 1,
  19279. colSpan: 1
  19280. };
  19281. }
  19282. }
  19283. }
  19284. //当框选后删除行或者列后撤销,需要重建选区。
  19285. var tds = domUtils.getElementsByTagName(this.table, "td"),
  19286. selectTds = [];
  19287. utils.each(tds, function(td) {
  19288. if (domUtils.hasClass(td, "selectTdClass")) {
  19289. selectTds.push(td);
  19290. }
  19291. });
  19292. if (selectTds.length) {
  19293. var start = selectTds[0],
  19294. end = selectTds[selectTds.length - 1],
  19295. startInfo = this.getCellInfo(start),
  19296. endInfo = this.getCellInfo(end);
  19297. this.selectedTds = selectTds;
  19298. this.cellsRange = {
  19299. beginRowIndex: startInfo.rowIndex,
  19300. beginColIndex: startInfo.colIndex,
  19301. endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
  19302. endColIndex: endInfo.colIndex + endInfo.colSpan - 1
  19303. };
  19304. }
  19305. //给第一行设置firstRow的样式名称,在排序图标的样式上使用到
  19306. if (!domUtils.hasClass(this.table.rows[0], "firstRow")) {
  19307. domUtils.addClass(this.table.rows[0], "firstRow");
  19308. for (var i = 1; i < this.table.rows.length; i++) {
  19309. domUtils.removeClasses(this.table.rows[i], "firstRow");
  19310. }
  19311. }
  19312. },
  19313. /**
  19314. * 获取单元格的索引信息
  19315. */
  19316. getCellInfo: function(cell) {
  19317. if (!cell) return;
  19318. var cellIndex = cell.cellIndex,
  19319. rowIndex = cell.parentNode.rowIndex,
  19320. rowInfo = this.indexTable[rowIndex],
  19321. numCols = this.colsNum;
  19322. for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
  19323. var cellInfo = rowInfo[colIndex];
  19324. if (
  19325. cellInfo.rowIndex === rowIndex &&
  19326. cellInfo.cellIndex === cellIndex
  19327. ) {
  19328. return cellInfo;
  19329. }
  19330. }
  19331. },
  19332. /**
  19333. * 根据行列号获取单元格
  19334. */
  19335. getCell: function(rowIndex, cellIndex) {
  19336. return (
  19337. (rowIndex < this.rowsNum &&
  19338. this.table.rows[rowIndex].cells[cellIndex]) ||
  19339. null
  19340. );
  19341. },
  19342. /**
  19343. * 删除单元格
  19344. */
  19345. deleteCell: function(cell, rowIndex) {
  19346. rowIndex = typeof rowIndex == "number"
  19347. ? rowIndex
  19348. : cell.parentNode.rowIndex;
  19349. var row = this.table.rows[rowIndex];
  19350. row.deleteCell(cell.cellIndex);
  19351. },
  19352. /**
  19353. * 根据始末两个单元格获取被框选的所有单元格范围
  19354. */
  19355. getCellsRange: function(cellA, cellB) {
  19356. function checkRange(
  19357. beginRowIndex,
  19358. beginColIndex,
  19359. endRowIndex,
  19360. endColIndex
  19361. ) {
  19362. var tmpBeginRowIndex = beginRowIndex,
  19363. tmpBeginColIndex = beginColIndex,
  19364. tmpEndRowIndex = endRowIndex,
  19365. tmpEndColIndex = endColIndex,
  19366. cellInfo,
  19367. colIndex,
  19368. rowIndex;
  19369. // 通过indexTable检查是否存在超出TableRange上边界的情况
  19370. if (beginRowIndex > 0) {
  19371. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  19372. cellInfo = me.indexTable[beginRowIndex][colIndex];
  19373. rowIndex = cellInfo.rowIndex;
  19374. if (rowIndex < beginRowIndex) {
  19375. tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex);
  19376. }
  19377. }
  19378. }
  19379. // 通过indexTable检查是否存在超出TableRange右边界的情况
  19380. if (endColIndex < me.colsNum) {
  19381. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  19382. cellInfo = me.indexTable[rowIndex][endColIndex];
  19383. colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
  19384. if (colIndex > endColIndex) {
  19385. tmpEndColIndex = Math.max(colIndex, tmpEndColIndex);
  19386. }
  19387. }
  19388. }
  19389. // 检查是否有超出TableRange下边界的情况
  19390. if (endRowIndex < me.rowsNum) {
  19391. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  19392. cellInfo = me.indexTable[endRowIndex][colIndex];
  19393. rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
  19394. if (rowIndex > endRowIndex) {
  19395. tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex);
  19396. }
  19397. }
  19398. }
  19399. // 检查是否有超出TableRange左边界的情况
  19400. if (beginColIndex > 0) {
  19401. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  19402. cellInfo = me.indexTable[rowIndex][beginColIndex];
  19403. colIndex = cellInfo.colIndex;
  19404. if (colIndex < beginColIndex) {
  19405. tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex);
  19406. }
  19407. }
  19408. }
  19409. //递归调用直至所有完成所有框选单元格的扩展
  19410. if (
  19411. tmpBeginRowIndex != beginRowIndex ||
  19412. tmpBeginColIndex != beginColIndex ||
  19413. tmpEndRowIndex != endRowIndex ||
  19414. tmpEndColIndex != endColIndex
  19415. ) {
  19416. return checkRange(
  19417. tmpBeginRowIndex,
  19418. tmpBeginColIndex,
  19419. tmpEndRowIndex,
  19420. tmpEndColIndex
  19421. );
  19422. } else {
  19423. // 不需要扩展TableRange的情况
  19424. return {
  19425. beginRowIndex: beginRowIndex,
  19426. beginColIndex: beginColIndex,
  19427. endRowIndex: endRowIndex,
  19428. endColIndex: endColIndex
  19429. };
  19430. }
  19431. }
  19432. try {
  19433. var me = this,
  19434. cellAInfo = me.getCellInfo(cellA);
  19435. if (cellA === cellB) {
  19436. return {
  19437. beginRowIndex: cellAInfo.rowIndex,
  19438. beginColIndex: cellAInfo.colIndex,
  19439. endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  19440. endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
  19441. };
  19442. }
  19443. var cellBInfo = me.getCellInfo(cellB);
  19444. // 计算TableRange的四个边
  19445. var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
  19446. beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
  19447. endRowIndex = Math.max(
  19448. cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  19449. cellBInfo.rowIndex + cellBInfo.rowSpan - 1
  19450. ),
  19451. endColIndex = Math.max(
  19452. cellAInfo.colIndex + cellAInfo.colSpan - 1,
  19453. cellBInfo.colIndex + cellBInfo.colSpan - 1
  19454. );
  19455. return checkRange(
  19456. beginRowIndex,
  19457. beginColIndex,
  19458. endRowIndex,
  19459. endColIndex
  19460. );
  19461. } catch (e) {
  19462. //throw e;
  19463. }
  19464. },
  19465. /**
  19466. * 依据cellsRange获取对应的单元格集合
  19467. */
  19468. getCells: function(range) {
  19469. //每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
  19470. this.clearSelected();
  19471. var beginRowIndex = range.beginRowIndex,
  19472. beginColIndex = range.beginColIndex,
  19473. endRowIndex = range.endRowIndex,
  19474. endColIndex = range.endColIndex,
  19475. cellInfo,
  19476. rowIndex,
  19477. colIndex,
  19478. tdHash = {},
  19479. returnTds = [];
  19480. for (var i = beginRowIndex; i <= endRowIndex; i++) {
  19481. for (var j = beginColIndex; j <= endColIndex; j++) {
  19482. cellInfo = this.indexTable[i][j];
  19483. rowIndex = cellInfo.rowIndex;
  19484. colIndex = cellInfo.colIndex;
  19485. // 如果Cells里已经包含了此Cell则跳过
  19486. var key = rowIndex + "|" + colIndex;
  19487. if (tdHash[key]) continue;
  19488. tdHash[key] = 1;
  19489. if (
  19490. rowIndex < i ||
  19491. colIndex < j ||
  19492. rowIndex + cellInfo.rowSpan - 1 > endRowIndex ||
  19493. colIndex + cellInfo.colSpan - 1 > endColIndex
  19494. ) {
  19495. return null;
  19496. }
  19497. returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex));
  19498. }
  19499. }
  19500. return returnTds;
  19501. },
  19502. /**
  19503. * 清理已经选中的单元格
  19504. */
  19505. clearSelected: function() {
  19506. UETable.removeSelectedClass(this.selectedTds);
  19507. this.selectedTds = [];
  19508. this.cellsRange = {};
  19509. },
  19510. /**
  19511. * 根据range设置已经选中的单元格
  19512. */
  19513. setSelected: function(range) {
  19514. var cells = this.getCells(range);
  19515. UETable.addSelectedClass(cells);
  19516. this.selectedTds = cells;
  19517. this.cellsRange = range;
  19518. },
  19519. isFullRow: function() {
  19520. var range = this.cellsRange;
  19521. return range.endColIndex - range.beginColIndex + 1 == this.colsNum;
  19522. },
  19523. isFullCol: function() {
  19524. var range = this.cellsRange,
  19525. table = this.table,
  19526. ths = table.getElementsByTagName("th"),
  19527. rows = range.endRowIndex - range.beginRowIndex + 1;
  19528. return !ths.length
  19529. ? rows == this.rowsNum
  19530. : rows == this.rowsNum || rows == this.rowsNum - 1;
  19531. },
  19532. /**
  19533. * 获取视觉上的前置单元格,默认是左边,top传入时
  19534. * @param cell
  19535. * @param top
  19536. */
  19537. getNextCell: function(cell, bottom, ignoreRange) {
  19538. try {
  19539. var cellInfo = this.getCellInfo(cell),
  19540. nextRowIndex,
  19541. nextColIndex;
  19542. var len = this.selectedTds.length && !ignoreRange,
  19543. range = this.cellsRange;
  19544. //末行或者末列没有后置单元格
  19545. if (
  19546. (!bottom && cellInfo.rowIndex == 0) ||
  19547. (bottom &&
  19548. (!len
  19549. ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
  19550. : range.endRowIndex == this.rowsNum - 1))
  19551. )
  19552. return null;
  19553. nextRowIndex = !bottom
  19554. ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
  19555. : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
  19556. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  19557. return this.getCell(
  19558. this.indexTable[nextRowIndex][nextColIndex].rowIndex,
  19559. this.indexTable[nextRowIndex][nextColIndex].cellIndex
  19560. );
  19561. } catch (e) {
  19562. showError(e);
  19563. }
  19564. },
  19565. getPreviewCell: function(cell, top) {
  19566. try {
  19567. var cellInfo = this.getCellInfo(cell),
  19568. previewRowIndex,
  19569. previewColIndex;
  19570. var len = this.selectedTds.length,
  19571. range = this.cellsRange;
  19572. //首行或者首列没有前置单元格
  19573. if (
  19574. (!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
  19575. (top &&
  19576. (!len
  19577. ? cellInfo.rowIndex > this.colsNum - 1
  19578. : range.endColIndex == this.colsNum - 1))
  19579. )
  19580. return null;
  19581. previewRowIndex = !top
  19582. ? !len ? cellInfo.rowIndex : range.beginRowIndex
  19583. : !len
  19584. ? cellInfo.rowIndex < 1 ? 0 : cellInfo.rowIndex - 1
  19585. : range.beginRowIndex;
  19586. previewColIndex = !top
  19587. ? !len
  19588. ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
  19589. : range.beginColIndex - 1
  19590. : !len ? cellInfo.colIndex : range.endColIndex + 1;
  19591. return this.getCell(
  19592. this.indexTable[previewRowIndex][previewColIndex].rowIndex,
  19593. this.indexTable[previewRowIndex][previewColIndex].cellIndex
  19594. );
  19595. } catch (e) {
  19596. showError(e);
  19597. }
  19598. },
  19599. /**
  19600. * 移动单元格中的内容
  19601. */
  19602. moveContent: function(cellTo, cellFrom) {
  19603. if (UETable.isEmptyBlock(cellFrom)) return;
  19604. if (UETable.isEmptyBlock(cellTo)) {
  19605. cellTo.innerHTML = cellFrom.innerHTML;
  19606. return;
  19607. }
  19608. var child = cellTo.lastChild;
  19609. if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
  19610. cellTo.appendChild(cellTo.ownerDocument.createElement("br"));
  19611. }
  19612. while ((child = cellFrom.firstChild)) {
  19613. cellTo.appendChild(child);
  19614. }
  19615. },
  19616. /**
  19617. * 向右合并单元格
  19618. */
  19619. mergeRight: function(cell) {
  19620. var cellInfo = this.getCellInfo(cell),
  19621. rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
  19622. rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
  19623. rightCell = this.getCell(
  19624. rightCellInfo.rowIndex,
  19625. rightCellInfo.cellIndex
  19626. );
  19627. //合并
  19628. cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
  19629. //被合并的单元格不应存在宽度属性
  19630. cell.removeAttribute("width");
  19631. //移动内容
  19632. this.moveContent(cell, rightCell);
  19633. //删掉被合并的Cell
  19634. this.deleteCell(rightCell, rightCellInfo.rowIndex);
  19635. this.update();
  19636. },
  19637. /**
  19638. * 向下合并单元格
  19639. */
  19640. mergeDown: function(cell) {
  19641. var cellInfo = this.getCellInfo(cell),
  19642. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
  19643. downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
  19644. downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
  19645. cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
  19646. cell.removeAttribute("height");
  19647. this.moveContent(cell, downCell);
  19648. this.deleteCell(downCell, downCellInfo.rowIndex);
  19649. this.update();
  19650. },
  19651. /**
  19652. * 合并整个range中的内容
  19653. */
  19654. mergeRange: function() {
  19655. //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
  19656. var range = this.cellsRange,
  19657. leftTopCell = this.getCell(
  19658. range.beginRowIndex,
  19659. this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
  19660. );
  19661. // 这段关于行表头或者列表头的特殊处理会导致表头合并范围错误
  19662. // 为什么有这段代码的原因未明,暂且注释掉,希望原作者看到后出面说明下
  19663. // if (
  19664. // leftTopCell.tagName == "TH" &&
  19665. // range.endRowIndex !== range.beginRowIndex
  19666. // ) {
  19667. // var index = this.indexTable,
  19668. // info = this.getCellInfo(leftTopCell);
  19669. // leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
  19670. // range = this.getCellsRange(
  19671. // leftTopCell,
  19672. // this.getCell(
  19673. // index[this.rowsNum - 1][info.colIndex].rowIndex,
  19674. // index[this.rowsNum - 1][info.colIndex].cellIndex
  19675. // )
  19676. // );
  19677. // }
  19678. // 删除剩余的Cells
  19679. var cells = this.getCells(range);
  19680. for (var i = 0, ci; (ci = cells[i++]); ) {
  19681. if (ci !== leftTopCell) {
  19682. this.moveContent(leftTopCell, ci);
  19683. this.deleteCell(ci);
  19684. }
  19685. }
  19686. // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
  19687. leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
  19688. leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
  19689. leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
  19690. leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
  19691. if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
  19692. leftTopCell.colSpan = 1;
  19693. }
  19694. if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
  19695. var rowIndex = leftTopCell.parentNode.rowIndex;
  19696. //解决IE下的表格操作问题
  19697. if (this.table.deleteRow) {
  19698. for (
  19699. var i = rowIndex + 1,
  19700. curIndex = rowIndex + 1,
  19701. len = leftTopCell.rowSpan;
  19702. i < len;
  19703. i++
  19704. ) {
  19705. this.table.deleteRow(curIndex);
  19706. }
  19707. } else {
  19708. for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
  19709. var row = this.table.rows[rowIndex + 1];
  19710. row.parentNode.removeChild(row);
  19711. }
  19712. }
  19713. leftTopCell.rowSpan = 1;
  19714. }
  19715. this.update();
  19716. },
  19717. /**
  19718. * 插入一行单元格
  19719. */
  19720. insertRow: function(rowIndex, sourceCell) {
  19721. var numCols = this.colsNum,
  19722. table = this.table,
  19723. row = table.insertRow(rowIndex),
  19724. cell,
  19725. thead = null,
  19726. isInsertTitle =
  19727. typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";
  19728. function replaceTdToTh(colIndex, cell, tableRow) {
  19729. if (colIndex == 0) {
  19730. var tr = tableRow.nextSibling || tableRow.previousSibling,
  19731. th = tr.cells[colIndex];
  19732. if (th.tagName == "TH") {
  19733. th = cell.ownerDocument.createElement("th");
  19734. th.appendChild(cell.firstChild);
  19735. tableRow.insertBefore(th, cell);
  19736. domUtils.remove(cell);
  19737. }
  19738. } else {
  19739. if (cell.tagName == "TH") {
  19740. var td = cell.ownerDocument.createElement("td");
  19741. td.appendChild(cell.firstChild);
  19742. tableRow.insertBefore(td, cell);
  19743. domUtils.remove(cell);
  19744. }
  19745. }
  19746. }
  19747. //首行直接插入,无需考虑部分单元格被rowspan的情况
  19748. if (rowIndex == 0 || rowIndex == this.rowsNum) {
  19749. for (var colIndex = 0; colIndex < numCols; colIndex++) {
  19750. cell = this.cloneCell(sourceCell, true);
  19751. this.setCellContent(cell);
  19752. cell.getAttribute("vAlign") &&
  19753. cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  19754. row.appendChild(cell);
  19755. if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
  19756. }
  19757. if (isInsertTitle) {
  19758. thead = table.createTHead();
  19759. thead.insertBefore(row, thead.firstChild);
  19760. }
  19761. } else {
  19762. var infoRow = this.indexTable[rowIndex],
  19763. cellIndex = 0;
  19764. for (colIndex = 0; colIndex < numCols; colIndex++) {
  19765. var cellInfo = infoRow[colIndex];
  19766. //如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
  19767. if (cellInfo.rowIndex < rowIndex) {
  19768. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19769. cell.rowSpan = cellInfo.rowSpan + 1;
  19770. } else {
  19771. cell = this.cloneCell(sourceCell, true);
  19772. this.setCellContent(cell);
  19773. row.appendChild(cell);
  19774. }
  19775. if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
  19776. }
  19777. }
  19778. //框选时插入不触发contentchange,需要手动更新索引。
  19779. this.update();
  19780. return row;
  19781. },
  19782. /**
  19783. * 删除一行单元格
  19784. * @param rowIndex
  19785. */
  19786. deleteRow: function(rowIndex) {
  19787. var row = this.table.rows[rowIndex],
  19788. infoRow = this.indexTable[rowIndex],
  19789. colsNum = this.colsNum,
  19790. count = 0; //处理计数
  19791. for (var colIndex = 0; colIndex < colsNum; ) {
  19792. var cellInfo = infoRow[colIndex],
  19793. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19794. if (cell.rowSpan > 1) {
  19795. if (cellInfo.rowIndex == rowIndex) {
  19796. var clone = cell.cloneNode(true);
  19797. clone.rowSpan = cell.rowSpan - 1;
  19798. clone.innerHTML = "";
  19799. cell.rowSpan = 1;
  19800. var nextRowIndex = rowIndex + 1,
  19801. nextRow = this.table.rows[nextRowIndex],
  19802. insertCellIndex,
  19803. preMerged =
  19804. this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count;
  19805. if (preMerged < colIndex) {
  19806. insertCellIndex = colIndex - preMerged - 1;
  19807. //nextRow.insertCell(insertCellIndex);
  19808. domUtils.insertAfter(nextRow.cells[insertCellIndex], clone);
  19809. } else {
  19810. if (nextRow.cells.length)
  19811. nextRow.insertBefore(clone, nextRow.cells[0]);
  19812. }
  19813. count += 1;
  19814. //cell.parentNode.removeChild(cell);
  19815. }
  19816. }
  19817. colIndex += cell.colSpan || 1;
  19818. }
  19819. var deleteTds = [],
  19820. cacheMap = {};
  19821. for (colIndex = 0; colIndex < colsNum; colIndex++) {
  19822. var tmpRowIndex = infoRow[colIndex].rowIndex,
  19823. tmpCellIndex = infoRow[colIndex].cellIndex,
  19824. key = tmpRowIndex + "_" + tmpCellIndex;
  19825. if (cacheMap[key]) continue;
  19826. cacheMap[key] = 1;
  19827. cell = this.getCell(tmpRowIndex, tmpCellIndex);
  19828. deleteTds.push(cell);
  19829. }
  19830. var mergeTds = [];
  19831. utils.each(deleteTds, function(td) {
  19832. if (td.rowSpan == 1) {
  19833. td.parentNode.removeChild(td);
  19834. } else {
  19835. mergeTds.push(td);
  19836. }
  19837. });
  19838. utils.each(mergeTds, function(td) {
  19839. td.rowSpan--;
  19840. });
  19841. row.parentNode.removeChild(row);
  19842. //浏览器方法本身存在bug,采用自定义方法删除
  19843. //this.table.deleteRow(rowIndex);
  19844. this.update();
  19845. },
  19846. insertCol: function(colIndex, sourceCell, defaultValue) {
  19847. var rowsNum = this.rowsNum,
  19848. rowIndex = 0,
  19849. tableRow,
  19850. cell,
  19851. backWidth = parseInt(
  19852. (this.table.offsetWidth -
  19853. (this.colsNum + 1) * 20 -
  19854. (this.colsNum + 1)) /
  19855. (this.colsNum + 1),
  19856. 10
  19857. ),
  19858. isInsertTitleCol =
  19859. typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";
  19860. function replaceTdToTh(rowIndex, cell, tableRow) {
  19861. if (rowIndex == 0) {
  19862. var th = cell.nextSibling || cell.previousSibling;
  19863. if (th.tagName == "TH") {
  19864. th = cell.ownerDocument.createElement("th");
  19865. th.appendChild(cell.firstChild);
  19866. tableRow.insertBefore(th, cell);
  19867. domUtils.remove(cell);
  19868. }
  19869. } else {
  19870. if (cell.tagName == "TH") {
  19871. var td = cell.ownerDocument.createElement("td");
  19872. td.appendChild(cell.firstChild);
  19873. tableRow.insertBefore(td, cell);
  19874. domUtils.remove(cell);
  19875. }
  19876. }
  19877. }
  19878. var preCell;
  19879. if (colIndex == 0 || colIndex == this.colsNum) {
  19880. for (; rowIndex < rowsNum; rowIndex++) {
  19881. tableRow = this.table.rows[rowIndex];
  19882. preCell =
  19883. tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
  19884. cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
  19885. this.setCellContent(cell);
  19886. cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  19887. preCell && cell.setAttribute("width", preCell.getAttribute("width"));
  19888. if (!colIndex) {
  19889. tableRow.insertBefore(cell, tableRow.cells[0]);
  19890. } else {
  19891. domUtils.insertAfter(
  19892. tableRow.cells[tableRow.cells.length - 1],
  19893. cell
  19894. );
  19895. }
  19896. if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
  19897. }
  19898. } else {
  19899. for (; rowIndex < rowsNum; rowIndex++) {
  19900. var cellInfo = this.indexTable[rowIndex][colIndex];
  19901. if (cellInfo.colIndex < colIndex) {
  19902. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19903. cell.colSpan = cellInfo.colSpan + 1;
  19904. } else {
  19905. tableRow = this.table.rows[rowIndex];
  19906. preCell = tableRow.cells[cellInfo.cellIndex];
  19907. cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(cellInfo.cellIndex);
  19908. this.setCellContent(cell);
  19909. cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  19910. preCell &&
  19911. cell.setAttribute("width", preCell.getAttribute("width"));
  19912. //防止IE下报错
  19913. preCell
  19914. ? tableRow.insertBefore(cell, preCell)
  19915. : tableRow.appendChild(cell);
  19916. }
  19917. if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
  19918. }
  19919. }
  19920. //框选时插入不触发contentchange,需要手动更新索引
  19921. this.update();
  19922. this.updateWidth(
  19923. backWidth,
  19924. defaultValue || { tdPadding: 10, tdBorder: 1 }
  19925. );
  19926. },
  19927. updateWidth: function(width, defaultValue) {
  19928. var table = this.table,
  19929. tmpWidth =
  19930. UETable.getWidth(table) -
  19931. defaultValue.tdPadding * 2 -
  19932. defaultValue.tdBorder +
  19933. width;
  19934. if (tmpWidth < table.ownerDocument.body.offsetWidth) {
  19935. table.setAttribute("width", tmpWidth);
  19936. return;
  19937. }
  19938. var tds = domUtils.getElementsByTagName(this.table, "td th");
  19939. utils.each(tds, function(td) {
  19940. td.setAttribute("width", width);
  19941. });
  19942. },
  19943. deleteCol: function(colIndex) {
  19944. var indexTable = this.indexTable,
  19945. tableRows = this.table.rows,
  19946. backTableWidth = this.table.getAttribute("width"),
  19947. backTdWidth = 0,
  19948. rowsNum = this.rowsNum,
  19949. cacheMap = {};
  19950. for (var rowIndex = 0; rowIndex < rowsNum; ) {
  19951. var infoRow = indexTable[rowIndex],
  19952. cellInfo = infoRow[colIndex],
  19953. key = cellInfo.rowIndex + "_" + cellInfo.colIndex;
  19954. // 跳过已经处理过的Cell
  19955. if (cacheMap[key]) continue;
  19956. cacheMap[key] = 1;
  19957. var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  19958. if (!backTdWidth)
  19959. backTdWidth =
  19960. cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0);
  19961. // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
  19962. if (cell.colSpan > 1) {
  19963. cell.colSpan--;
  19964. } else {
  19965. tableRows[rowIndex].deleteCell(cellInfo.cellIndex);
  19966. }
  19967. rowIndex += cellInfo.rowSpan || 1;
  19968. }
  19969. this.table.setAttribute("width", backTableWidth - backTdWidth);
  19970. this.update();
  19971. },
  19972. splitToCells: function(cell) {
  19973. var me = this,
  19974. cells = this.splitToRows(cell);
  19975. utils.each(cells, function(cell) {
  19976. me.splitToCols(cell);
  19977. });
  19978. },
  19979. splitToRows: function(cell) {
  19980. var cellInfo = this.getCellInfo(cell),
  19981. rowIndex = cellInfo.rowIndex,
  19982. colIndex = cellInfo.colIndex,
  19983. results = [];
  19984. // 修改Cell的rowSpan
  19985. cell.rowSpan = 1;
  19986. results.push(cell);
  19987. // 补齐单元格
  19988. for (
  19989. var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan;
  19990. i < endRow;
  19991. i++
  19992. ) {
  19993. if (i == rowIndex) continue;
  19994. var tableRow = this.table.rows[i],
  19995. tmpCell = tableRow.insertCell(
  19996. colIndex - this.getPreviewMergedCellsNum(i, colIndex)
  19997. );
  19998. tmpCell.colSpan = cellInfo.colSpan;
  19999. this.setCellContent(tmpCell);
  20000. tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  20001. tmpCell.setAttribute("align", cell.getAttribute("align"));
  20002. if (cell.style.cssText) {
  20003. tmpCell.style.cssText = cell.style.cssText;
  20004. }
  20005. results.push(tmpCell);
  20006. }
  20007. this.update();
  20008. return results;
  20009. },
  20010. getPreviewMergedCellsNum: function(rowIndex, colIndex) {
  20011. var indexRow = this.indexTable[rowIndex],
  20012. num = 0;
  20013. for (var i = 0; i < colIndex; ) {
  20014. var colSpan = indexRow[i].colSpan,
  20015. tmpRowIndex = indexRow[i].rowIndex;
  20016. num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0);
  20017. i += colSpan;
  20018. }
  20019. return num;
  20020. },
  20021. splitToCols: function(cell) {
  20022. var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
  20023. cellInfo = this.getCellInfo(cell),
  20024. rowIndex = cellInfo.rowIndex,
  20025. colIndex = cellInfo.colIndex,
  20026. results = [];
  20027. // 修改Cell的rowSpan
  20028. cell.colSpan = 1;
  20029. cell.setAttribute("width", backWidth);
  20030. results.push(cell);
  20031. // 补齐单元格
  20032. for (
  20033. var j = colIndex, endCol = colIndex + cellInfo.colSpan;
  20034. j < endCol;
  20035. j++
  20036. ) {
  20037. if (j == colIndex) continue;
  20038. var tableRow = this.table.rows[rowIndex],
  20039. tmpCell = tableRow.insertCell(
  20040. this.indexTable[rowIndex][j].cellIndex + 1
  20041. );
  20042. tmpCell.rowSpan = cellInfo.rowSpan;
  20043. this.setCellContent(tmpCell);
  20044. tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
  20045. tmpCell.setAttribute("align", cell.getAttribute("align"));
  20046. tmpCell.setAttribute("width", backWidth);
  20047. if (cell.style.cssText) {
  20048. tmpCell.style.cssText = cell.style.cssText;
  20049. }
  20050. //处理th的情况
  20051. if (cell.tagName == "TH") {
  20052. var th = cell.ownerDocument.createElement("th");
  20053. th.appendChild(tmpCell.firstChild);
  20054. th.setAttribute("vAlign", cell.getAttribute("vAlign"));
  20055. th.rowSpan = tmpCell.rowSpan;
  20056. tableRow.insertBefore(th, tmpCell);
  20057. domUtils.remove(tmpCell);
  20058. }
  20059. results.push(tmpCell);
  20060. }
  20061. this.update();
  20062. return results;
  20063. },
  20064. isLastCell: function(cell, rowsNum, colsNum) {
  20065. rowsNum = rowsNum || this.rowsNum;
  20066. colsNum = colsNum || this.colsNum;
  20067. var cellInfo = this.getCellInfo(cell);
  20068. return (
  20069. cellInfo.rowIndex + cellInfo.rowSpan == rowsNum &&
  20070. cellInfo.colIndex + cellInfo.colSpan == colsNum
  20071. );
  20072. },
  20073. getLastCell: function(cells) {
  20074. cells = cells || this.table.getElementsByTagName("td");
  20075. var firstInfo = this.getCellInfo(cells[0]);
  20076. var me = this,
  20077. last = cells[0],
  20078. tr = last.parentNode,
  20079. cellsNum = 0,
  20080. cols = 0,
  20081. rows;
  20082. utils.each(cells, function(cell) {
  20083. if (cell.parentNode == tr) cols += cell.colSpan || 1;
  20084. cellsNum += cell.rowSpan * cell.colSpan || 1;
  20085. });
  20086. rows = cellsNum / cols;
  20087. utils.each(cells, function(cell) {
  20088. if (me.isLastCell(cell, rows, cols)) {
  20089. last = cell;
  20090. return false;
  20091. }
  20092. });
  20093. return last;
  20094. },
  20095. selectRow: function(rowIndex) {
  20096. var indexRow = this.indexTable[rowIndex],
  20097. start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
  20098. end = this.getCell(
  20099. indexRow[this.colsNum - 1].rowIndex,
  20100. indexRow[this.colsNum - 1].cellIndex
  20101. ),
  20102. range = this.getCellsRange(start, end);
  20103. this.setSelected(range);
  20104. },
  20105. selectTable: function() {
  20106. var tds = this.table.getElementsByTagName("td"),
  20107. range = this.getCellsRange(tds[0], tds[tds.length - 1]);
  20108. this.setSelected(range);
  20109. },
  20110. setBackground: function(cells, value) {
  20111. if (typeof value === "string") {
  20112. utils.each(cells, function(cell) {
  20113. cell.style.backgroundColor = value;
  20114. });
  20115. } else if (typeof value === "object") {
  20116. value = utils.extend(
  20117. {
  20118. repeat: true,
  20119. colorList: ["#ddd", "#fff"]
  20120. },
  20121. value
  20122. );
  20123. var rowIndex = this.getCellInfo(cells[0]).rowIndex,
  20124. count = 0,
  20125. colors = value.colorList,
  20126. getColor = function(list, index, repeat) {
  20127. return list[index]
  20128. ? list[index]
  20129. : repeat ? list[index % list.length] : "";
  20130. };
  20131. for (var i = 0, cell; (cell = cells[i++]); ) {
  20132. var cellInfo = this.getCellInfo(cell);
  20133. cell.style.backgroundColor = getColor(
  20134. colors,
  20135. rowIndex + count == cellInfo.rowIndex ? count : ++count,
  20136. value.repeat
  20137. );
  20138. }
  20139. }
  20140. },
  20141. removeBackground: function(cells) {
  20142. utils.each(cells, function(cell) {
  20143. cell.style.backgroundColor = "";
  20144. });
  20145. }
  20146. };
  20147. function showError(e) {}
  20148. })();
  20149. // plugins/table.cmds.js
  20150. /**
  20151. * Created with JetBrains PhpStorm.
  20152. * User: taoqili
  20153. * Date: 13-2-20
  20154. * Time: 下午6:25
  20155. * To change this template use File | Settings | File Templates.
  20156. */
  20157. ;(function() {
  20158. var UT = UE.UETable,
  20159. getTableItemsByRange = function(editor) {
  20160. return UT.getTableItemsByRange(editor);
  20161. },
  20162. getUETableBySelected = function(editor) {
  20163. return UT.getUETableBySelected(editor);
  20164. },
  20165. getDefaultValue = function(editor, table) {
  20166. return UT.getDefaultValue(editor, table);
  20167. },
  20168. getUETable = function(tdOrTable) {
  20169. return UT.getUETable(tdOrTable);
  20170. };
  20171. UE.commands["inserttable"] = {
  20172. queryCommandState: function() {
  20173. return getTableItemsByRange(this).table ? -1 : 0;
  20174. },
  20175. execCommand: function(cmd, opt) {
  20176. function createTable(opt, tdWidth) {
  20177. var html = [],
  20178. rowsNum = opt.numRows,
  20179. colsNum = opt.numCols;
  20180. for (var r = 0; r < rowsNum; r++) {
  20181. html.push("<tr" + (r == 0 ? ' class="firstRow"' : "") + ">");
  20182. for (var c = 0; c < colsNum; c++) {
  20183. html.push(
  20184. '<td width="' +
  20185. tdWidth +
  20186. '" vAlign="' +
  20187. opt.tdvalign +
  20188. '" >' +
  20189. (browser.ie && browser.version < 11
  20190. ? domUtils.fillChar
  20191. : "<br/>") +
  20192. "</td>"
  20193. );
  20194. }
  20195. html.push("</tr>");
  20196. }
  20197. //禁止指定table-width
  20198. return "<table><tbody>" + html.join("") + "</tbody></table>";
  20199. }
  20200. if (!opt) {
  20201. opt = utils.extend(
  20202. {},
  20203. {
  20204. numCols: this.options.defaultCols,
  20205. numRows: this.options.defaultRows,
  20206. tdvalign: this.options.tdvalign
  20207. }
  20208. );
  20209. }
  20210. var me = this;
  20211. var range = this.selection.getRange(),
  20212. start = range.startContainer,
  20213. firstParentBlock =
  20214. domUtils.findParent(
  20215. start,
  20216. function(node) {
  20217. return domUtils.isBlockElm(node);
  20218. },
  20219. true
  20220. ) || me.body;
  20221. var defaultValue = getDefaultValue(me),
  20222. tableWidth = firstParentBlock.offsetWidth,
  20223. tdWidth = Math.floor(
  20224. tableWidth / opt.numCols -
  20225. defaultValue.tdPadding * 2 -
  20226. defaultValue.tdBorder
  20227. );
  20228. //todo其他属性
  20229. !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
  20230. me.execCommand("inserthtml", createTable(opt, tdWidth));
  20231. }
  20232. };
  20233. UE.commands["insertparagraphbeforetable"] = {
  20234. queryCommandState: function() {
  20235. return getTableItemsByRange(this).cell ? 0 : -1;
  20236. },
  20237. execCommand: function() {
  20238. var table = getTableItemsByRange(this).table;
  20239. if (table) {
  20240. var p = this.document.createElement("p");
  20241. p.innerHTML = browser.ie ? "&nbsp;" : "<br />";
  20242. table.parentNode.insertBefore(p, table);
  20243. this.selection.getRange().setStart(p, 0).setCursor();
  20244. }
  20245. }
  20246. };
  20247. UE.commands["deletetable"] = {
  20248. queryCommandState: function() {
  20249. var rng = this.selection.getRange();
  20250. return domUtils.findParentByTagName(rng.startContainer, "table", true)
  20251. ? 0
  20252. : -1;
  20253. },
  20254. execCommand: function(cmd, table) {
  20255. var rng = this.selection.getRange();
  20256. table =
  20257. table ||
  20258. domUtils.findParentByTagName(rng.startContainer, "table", true);
  20259. if (table) {
  20260. var next = table.nextSibling;
  20261. if (!next) {
  20262. next = domUtils.createElement(this.document, "p", {
  20263. innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
  20264. });
  20265. table.parentNode.insertBefore(next, table);
  20266. }
  20267. domUtils.remove(table);
  20268. rng = this.selection.getRange();
  20269. if (next.nodeType == 3) {
  20270. rng.setStartBefore(next);
  20271. } else {
  20272. rng.setStart(next, 0);
  20273. }
  20274. rng.setCursor(false, true);
  20275. this.fireEvent("tablehasdeleted");
  20276. }
  20277. }
  20278. };
  20279. UE.commands["cellalign"] = {
  20280. queryCommandState: function() {
  20281. return getSelectedArr(this).length ? 0 : -1;
  20282. },
  20283. execCommand: function(cmd, align) {
  20284. var selectedTds = getSelectedArr(this);
  20285. if (selectedTds.length) {
  20286. for (var i = 0, ci; (ci = selectedTds[i++]); ) {
  20287. ci.setAttribute("align", align);
  20288. }
  20289. }
  20290. }
  20291. };
  20292. UE.commands["cellvalign"] = {
  20293. queryCommandState: function() {
  20294. return getSelectedArr(this).length ? 0 : -1;
  20295. },
  20296. execCommand: function(cmd, valign) {
  20297. var selectedTds = getSelectedArr(this);
  20298. if (selectedTds.length) {
  20299. for (var i = 0, ci; (ci = selectedTds[i++]); ) {
  20300. ci.setAttribute("vAlign", valign);
  20301. }
  20302. }
  20303. }
  20304. };
  20305. UE.commands["insertcaption"] = {
  20306. queryCommandState: function() {
  20307. var table = getTableItemsByRange(this).table;
  20308. if (table) {
  20309. return table.getElementsByTagName("caption").length == 0 ? 1 : -1;
  20310. }
  20311. return -1;
  20312. },
  20313. execCommand: function() {
  20314. var table = getTableItemsByRange(this).table;
  20315. if (table) {
  20316. var caption = this.document.createElement("caption");
  20317. caption.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
  20318. table.insertBefore(caption, table.firstChild);
  20319. var range = this.selection.getRange();
  20320. range.setStart(caption, 0).setCursor();
  20321. }
  20322. }
  20323. };
  20324. UE.commands["deletecaption"] = {
  20325. queryCommandState: function() {
  20326. var rng = this.selection.getRange(),
  20327. table = domUtils.findParentByTagName(rng.startContainer, "table");
  20328. if (table) {
  20329. return table.getElementsByTagName("caption").length == 0 ? -1 : 1;
  20330. }
  20331. return -1;
  20332. },
  20333. execCommand: function() {
  20334. var rng = this.selection.getRange(),
  20335. table = domUtils.findParentByTagName(rng.startContainer, "table");
  20336. if (table) {
  20337. domUtils.remove(table.getElementsByTagName("caption")[0]);
  20338. var range = this.selection.getRange();
  20339. range.setStart(table.rows[0].cells[0], 0).setCursor();
  20340. }
  20341. }
  20342. };
  20343. UE.commands["inserttitle"] = {
  20344. queryCommandState: function() {
  20345. var table = getTableItemsByRange(this).table;
  20346. if (table) {
  20347. var firstRow = table.rows[0];
  20348. return firstRow.cells[
  20349. firstRow.cells.length - 1
  20350. ].tagName.toLowerCase() != "th"
  20351. ? 0
  20352. : -1;
  20353. }
  20354. return -1;
  20355. },
  20356. execCommand: function() {
  20357. var table = getTableItemsByRange(this).table;
  20358. if (table) {
  20359. getUETable(table).insertRow(0, "th");
  20360. }
  20361. var th = table.getElementsByTagName("th")[0];
  20362. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  20363. }
  20364. };
  20365. UE.commands["deletetitle"] = {
  20366. queryCommandState: function() {
  20367. var table = getTableItemsByRange(this).table;
  20368. if (table) {
  20369. var firstRow = table.rows[0];
  20370. return firstRow.cells[
  20371. firstRow.cells.length - 1
  20372. ].tagName.toLowerCase() == "th"
  20373. ? 0
  20374. : -1;
  20375. }
  20376. return -1;
  20377. },
  20378. execCommand: function() {
  20379. var table = getTableItemsByRange(this).table;
  20380. if (table) {
  20381. domUtils.remove(table.rows[0]);
  20382. }
  20383. var td = table.getElementsByTagName("td")[0];
  20384. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  20385. }
  20386. };
  20387. UE.commands["inserttitlecol"] = {
  20388. queryCommandState: function() {
  20389. var table = getTableItemsByRange(this).table;
  20390. if (table) {
  20391. var lastRow = table.rows[table.rows.length - 1];
  20392. return lastRow.getElementsByTagName("th").length ? -1 : 0;
  20393. }
  20394. return -1;
  20395. },
  20396. execCommand: function(cmd) {
  20397. var table = getTableItemsByRange(this).table;
  20398. if (table) {
  20399. getUETable(table).insertCol(0, "th");
  20400. }
  20401. resetTdWidth(table, this);
  20402. var th = table.getElementsByTagName("th")[0];
  20403. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  20404. }
  20405. };
  20406. UE.commands["deletetitlecol"] = {
  20407. queryCommandState: function() {
  20408. var table = getTableItemsByRange(this).table;
  20409. if (table) {
  20410. var lastRow = table.rows[table.rows.length - 1];
  20411. return lastRow.getElementsByTagName("th").length ? 0 : -1;
  20412. }
  20413. return -1;
  20414. },
  20415. execCommand: function() {
  20416. var table = getTableItemsByRange(this).table;
  20417. if (table) {
  20418. for (var i = 0; i < table.rows.length; i++) {
  20419. domUtils.remove(table.rows[i].children[0]);
  20420. }
  20421. }
  20422. resetTdWidth(table, this);
  20423. var td = table.getElementsByTagName("td")[0];
  20424. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  20425. }
  20426. };
  20427. UE.commands["mergeright"] = {
  20428. queryCommandState: function(cmd) {
  20429. var tableItems = getTableItemsByRange(this),
  20430. table = tableItems.table,
  20431. cell = tableItems.cell;
  20432. if (!table || !cell) return -1;
  20433. var ut = getUETable(table);
  20434. if (ut.selectedTds.length) return -1;
  20435. var cellInfo = ut.getCellInfo(cell),
  20436. rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
  20437. if (rightColIndex >= ut.colsNum) return -1; // 如果处于最右边则不能向右合并
  20438. var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
  20439. rightCell =
  20440. table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex];
  20441. if (!rightCell || cell.tagName != rightCell.tagName) return -1; // TH和TD不能相互合并
  20442. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  20443. return rightCellInfo.rowIndex == cellInfo.rowIndex &&
  20444. rightCellInfo.rowSpan == cellInfo.rowSpan
  20445. ? 0
  20446. : -1;
  20447. },
  20448. execCommand: function(cmd) {
  20449. var rng = this.selection.getRange(),
  20450. bk = rng.createBookmark(true);
  20451. var cell = getTableItemsByRange(this).cell,
  20452. ut = getUETable(cell);
  20453. ut.mergeRight(cell);
  20454. rng.moveToBookmark(bk).select();
  20455. }
  20456. };
  20457. UE.commands["mergedown"] = {
  20458. queryCommandState: function(cmd) {
  20459. var tableItems = getTableItemsByRange(this),
  20460. table = tableItems.table,
  20461. cell = tableItems.cell;
  20462. if (!table || !cell) return -1;
  20463. var ut = getUETable(table);
  20464. if (ut.selectedTds.length) return -1;
  20465. var cellInfo = ut.getCellInfo(cell),
  20466. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
  20467. if (downRowIndex >= ut.rowsNum) return -1; // 如果处于最下边则不能向下合并
  20468. var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
  20469. downCell =
  20470. table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex];
  20471. if (!downCell || cell.tagName != downCell.tagName) return -1; // TH和TD不能相互合并
  20472. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  20473. return downCellInfo.colIndex == cellInfo.colIndex &&
  20474. downCellInfo.colSpan == cellInfo.colSpan
  20475. ? 0
  20476. : -1;
  20477. },
  20478. execCommand: function() {
  20479. var rng = this.selection.getRange(),
  20480. bk = rng.createBookmark(true);
  20481. var cell = getTableItemsByRange(this).cell,
  20482. ut = getUETable(cell);
  20483. ut.mergeDown(cell);
  20484. rng.moveToBookmark(bk).select();
  20485. }
  20486. };
  20487. UE.commands["mergecells"] = {
  20488. queryCommandState: function() {
  20489. return getUETableBySelected(this) ? 0 : -1;
  20490. },
  20491. execCommand: function() {
  20492. var ut = getUETableBySelected(this);
  20493. if (ut && ut.selectedTds.length) {
  20494. var cell = ut.selectedTds[0];
  20495. ut.mergeRange();
  20496. var rng = this.selection.getRange();
  20497. if (domUtils.isEmptyBlock(cell)) {
  20498. rng.setStart(cell, 0).collapse(true);
  20499. } else {
  20500. rng.selectNodeContents(cell);
  20501. }
  20502. rng.select();
  20503. }
  20504. }
  20505. };
  20506. UE.commands["insertrow"] = {
  20507. queryCommandState: function() {
  20508. var tableItems = getTableItemsByRange(this),
  20509. cell = tableItems.cell;
  20510. return cell &&
  20511. (cell.tagName == "TD" ||
  20512. (cell.tagName == "TH" &&
  20513. tableItems.tr !== tableItems.table.rows[0])) &&
  20514. getUETable(tableItems.table).rowsNum < this.options.maxRowNum
  20515. ? 0
  20516. : -1;
  20517. },
  20518. execCommand: function() {
  20519. var rng = this.selection.getRange(),
  20520. bk = rng.createBookmark(true);
  20521. var tableItems = getTableItemsByRange(this),
  20522. cell = tableItems.cell,
  20523. table = tableItems.table,
  20524. ut = getUETable(table),
  20525. cellInfo = ut.getCellInfo(cell);
  20526. //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
  20527. if (!ut.selectedTds.length) {
  20528. ut.insertRow(cellInfo.rowIndex, cell);
  20529. } else {
  20530. var range = ut.cellsRange;
  20531. for (
  20532. var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
  20533. i < len;
  20534. i++
  20535. ) {
  20536. ut.insertRow(range.beginRowIndex, cell);
  20537. }
  20538. }
  20539. rng.moveToBookmark(bk).select();
  20540. if (table.getAttribute("interlaced") === "enabled")
  20541. this.fireEvent("interlacetable", table);
  20542. }
  20543. };
  20544. //后插入行
  20545. UE.commands["insertrownext"] = {
  20546. queryCommandState: function() {
  20547. var tableItems = getTableItemsByRange(this),
  20548. cell = tableItems.cell;
  20549. return cell &&
  20550. cell.tagName == "TD" &&
  20551. getUETable(tableItems.table).rowsNum < this.options.maxRowNum
  20552. ? 0
  20553. : -1;
  20554. },
  20555. execCommand: function() {
  20556. var rng = this.selection.getRange(),
  20557. bk = rng.createBookmark(true);
  20558. var tableItems = getTableItemsByRange(this),
  20559. cell = tableItems.cell,
  20560. table = tableItems.table,
  20561. ut = getUETable(table),
  20562. cellInfo = ut.getCellInfo(cell);
  20563. //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
  20564. if (!ut.selectedTds.length) {
  20565. ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell);
  20566. } else {
  20567. var range = ut.cellsRange;
  20568. for (
  20569. var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
  20570. i < len;
  20571. i++
  20572. ) {
  20573. ut.insertRow(range.endRowIndex + 1, cell);
  20574. }
  20575. }
  20576. rng.moveToBookmark(bk).select();
  20577. if (table.getAttribute("interlaced") === "enabled")
  20578. this.fireEvent("interlacetable", table);
  20579. }
  20580. };
  20581. UE.commands["deleterow"] = {
  20582. queryCommandState: function() {
  20583. var tableItems = getTableItemsByRange(this);
  20584. return tableItems.cell ? 0 : -1;
  20585. },
  20586. execCommand: function() {
  20587. var cell = getTableItemsByRange(this).cell,
  20588. ut = getUETable(cell),
  20589. cellsRange = ut.cellsRange,
  20590. cellInfo = ut.getCellInfo(cell),
  20591. preCell = ut.getVSideCell(cell),
  20592. nextCell = ut.getVSideCell(cell, true),
  20593. rng = this.selection.getRange();
  20594. if (utils.isEmptyObject(cellsRange)) {
  20595. ut.deleteRow(cellInfo.rowIndex);
  20596. } else {
  20597. for (
  20598. var i = cellsRange.beginRowIndex;
  20599. i < cellsRange.endRowIndex + 1;
  20600. i++
  20601. ) {
  20602. ut.deleteRow(cellsRange.beginRowIndex);
  20603. }
  20604. }
  20605. var table = ut.table;
  20606. if (!table.getElementsByTagName("td").length) {
  20607. var nextSibling = table.nextSibling;
  20608. domUtils.remove(table);
  20609. if (nextSibling) {
  20610. rng.setStart(nextSibling, 0).setCursor(false, true);
  20611. }
  20612. } else {
  20613. if (
  20614. cellInfo.rowSpan == 1 ||
  20615. cellInfo.rowSpan ==
  20616. cellsRange.endRowIndex - cellsRange.beginRowIndex + 1
  20617. ) {
  20618. if (nextCell || preCell)
  20619. rng.selectNodeContents(nextCell || preCell).setCursor(false, true);
  20620. } else {
  20621. var newCell = ut.getCell(
  20622. cellInfo.rowIndex,
  20623. ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex
  20624. );
  20625. if (newCell) rng.selectNodeContents(newCell).setCursor(false, true);
  20626. }
  20627. }
  20628. if (table.getAttribute("interlaced") === "enabled")
  20629. this.fireEvent("interlacetable", table);
  20630. }
  20631. };
  20632. UE.commands["insertcol"] = {
  20633. queryCommandState: function(cmd) {
  20634. var tableItems = getTableItemsByRange(this),
  20635. cell = tableItems.cell;
  20636. return cell &&
  20637. (cell.tagName == "TD" ||
  20638. (cell.tagName == "TH" && cell !== tableItems.tr.cells[0])) &&
  20639. getUETable(tableItems.table).colsNum < this.options.maxColNum
  20640. ? 0
  20641. : -1;
  20642. },
  20643. execCommand: function(cmd) {
  20644. var rng = this.selection.getRange(),
  20645. bk = rng.createBookmark(true);
  20646. if (this.queryCommandState(cmd) == -1) return;
  20647. var cell = getTableItemsByRange(this).cell,
  20648. ut = getUETable(cell),
  20649. cellInfo = ut.getCellInfo(cell);
  20650. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
  20651. if (!ut.selectedTds.length) {
  20652. ut.insertCol(cellInfo.colIndex, cell);
  20653. } else {
  20654. var range = ut.cellsRange;
  20655. for (
  20656. var i = 0, len = range.endColIndex - range.beginColIndex + 1;
  20657. i < len;
  20658. i++
  20659. ) {
  20660. ut.insertCol(range.beginColIndex, cell);
  20661. }
  20662. }
  20663. rng.moveToBookmark(bk).select(true);
  20664. }
  20665. };
  20666. UE.commands["insertcolnext"] = {
  20667. queryCommandState: function() {
  20668. var tableItems = getTableItemsByRange(this),
  20669. cell = tableItems.cell;
  20670. return cell &&
  20671. getUETable(tableItems.table).colsNum < this.options.maxColNum
  20672. ? 0
  20673. : -1;
  20674. },
  20675. execCommand: function() {
  20676. var rng = this.selection.getRange(),
  20677. bk = rng.createBookmark(true);
  20678. var cell = getTableItemsByRange(this).cell,
  20679. ut = getUETable(cell),
  20680. cellInfo = ut.getCellInfo(cell);
  20681. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
  20682. if (!ut.selectedTds.length) {
  20683. ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell);
  20684. } else {
  20685. var range = ut.cellsRange;
  20686. for (
  20687. var i = 0, len = range.endColIndex - range.beginColIndex + 1;
  20688. i < len;
  20689. i++
  20690. ) {
  20691. ut.insertCol(range.endColIndex + 1, cell);
  20692. }
  20693. }
  20694. rng.moveToBookmark(bk).select();
  20695. }
  20696. };
  20697. UE.commands["deletecol"] = {
  20698. queryCommandState: function() {
  20699. var tableItems = getTableItemsByRange(this);
  20700. return tableItems.cell ? 0 : -1;
  20701. },
  20702. execCommand: function() {
  20703. var cell = getTableItemsByRange(this).cell,
  20704. ut = getUETable(cell),
  20705. range = ut.cellsRange,
  20706. cellInfo = ut.getCellInfo(cell),
  20707. preCell = ut.getHSideCell(cell),
  20708. nextCell = ut.getHSideCell(cell, true);
  20709. if (utils.isEmptyObject(range)) {
  20710. ut.deleteCol(cellInfo.colIndex);
  20711. } else {
  20712. for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
  20713. ut.deleteCol(range.beginColIndex);
  20714. }
  20715. }
  20716. var table = ut.table,
  20717. rng = this.selection.getRange();
  20718. if (!table.getElementsByTagName("td").length) {
  20719. var nextSibling = table.nextSibling;
  20720. domUtils.remove(table);
  20721. if (nextSibling) {
  20722. rng.setStart(nextSibling, 0).setCursor(false, true);
  20723. }
  20724. } else {
  20725. if (domUtils.inDoc(cell, this.document)) {
  20726. rng.setStart(cell, 0).setCursor(false, true);
  20727. } else {
  20728. if (nextCell && domUtils.inDoc(nextCell, this.document)) {
  20729. rng.selectNodeContents(nextCell).setCursor(false, true);
  20730. } else {
  20731. if (preCell && domUtils.inDoc(preCell, this.document)) {
  20732. rng.selectNodeContents(preCell).setCursor(true, true);
  20733. }
  20734. }
  20735. }
  20736. }
  20737. }
  20738. };
  20739. UE.commands["splittocells"] = {
  20740. queryCommandState: function() {
  20741. var tableItems = getTableItemsByRange(this),
  20742. cell = tableItems.cell;
  20743. if (!cell) return -1;
  20744. var ut = getUETable(tableItems.table);
  20745. if (ut.selectedTds.length > 0) return -1;
  20746. return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1;
  20747. },
  20748. execCommand: function() {
  20749. var rng = this.selection.getRange(),
  20750. bk = rng.createBookmark(true);
  20751. var cell = getTableItemsByRange(this).cell,
  20752. ut = getUETable(cell);
  20753. ut.splitToCells(cell);
  20754. rng.moveToBookmark(bk).select();
  20755. }
  20756. };
  20757. UE.commands["splittorows"] = {
  20758. queryCommandState: function() {
  20759. var tableItems = getTableItemsByRange(this),
  20760. cell = tableItems.cell;
  20761. if (!cell) return -1;
  20762. var ut = getUETable(tableItems.table);
  20763. if (ut.selectedTds.length > 0) return -1;
  20764. return cell && cell.rowSpan > 1 ? 0 : -1;
  20765. },
  20766. execCommand: function() {
  20767. var rng = this.selection.getRange(),
  20768. bk = rng.createBookmark(true);
  20769. var cell = getTableItemsByRange(this).cell,
  20770. ut = getUETable(cell);
  20771. ut.splitToRows(cell);
  20772. rng.moveToBookmark(bk).select();
  20773. }
  20774. };
  20775. UE.commands["splittocols"] = {
  20776. queryCommandState: function() {
  20777. var tableItems = getTableItemsByRange(this),
  20778. cell = tableItems.cell;
  20779. if (!cell) return -1;
  20780. var ut = getUETable(tableItems.table);
  20781. if (ut.selectedTds.length > 0) return -1;
  20782. return cell && cell.colSpan > 1 ? 0 : -1;
  20783. },
  20784. execCommand: function() {
  20785. var rng = this.selection.getRange(),
  20786. bk = rng.createBookmark(true);
  20787. var cell = getTableItemsByRange(this).cell,
  20788. ut = getUETable(cell);
  20789. ut.splitToCols(cell);
  20790. rng.moveToBookmark(bk).select();
  20791. }
  20792. };
  20793. UE.commands["adaptbytext"] = UE.commands["adaptbywindow"] = {
  20794. queryCommandState: function() {
  20795. return getTableItemsByRange(this).table ? 0 : -1;
  20796. },
  20797. execCommand: function(cmd) {
  20798. var tableItems = getTableItemsByRange(this),
  20799. table = tableItems.table;
  20800. if (table) {
  20801. if (cmd == "adaptbywindow") {
  20802. resetTdWidth(table, this);
  20803. } else {
  20804. var cells = domUtils.getElementsByTagName(table, "td th");
  20805. utils.each(cells, function(cell) {
  20806. cell.removeAttribute("width");
  20807. });
  20808. table.removeAttribute("width");
  20809. }
  20810. }
  20811. }
  20812. };
  20813. //平均分配各列
  20814. UE.commands["averagedistributecol"] = {
  20815. queryCommandState: function() {
  20816. var ut = getUETableBySelected(this);
  20817. if (!ut) return -1;
  20818. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  20819. },
  20820. execCommand: function(cmd) {
  20821. var me = this,
  20822. ut = getUETableBySelected(me);
  20823. function getAverageWidth() {
  20824. var tb = ut.table,
  20825. averageWidth,
  20826. sumWidth = 0,
  20827. colsNum = 0,
  20828. tbAttr = getDefaultValue(me, tb);
  20829. if (ut.isFullRow()) {
  20830. sumWidth = tb.offsetWidth;
  20831. colsNum = ut.colsNum;
  20832. } else {
  20833. var begin = ut.cellsRange.beginColIndex,
  20834. end = ut.cellsRange.endColIndex,
  20835. node;
  20836. for (var i = begin; i <= end; ) {
  20837. node = ut.selectedTds[i];
  20838. sumWidth += node.offsetWidth;
  20839. i += node.colSpan;
  20840. colsNum += 1;
  20841. }
  20842. }
  20843. averageWidth =
  20844. Math.ceil(sumWidth / colsNum) -
  20845. tbAttr.tdBorder * 2 -
  20846. tbAttr.tdPadding * 2;
  20847. return averageWidth;
  20848. }
  20849. function setAverageWidth(averageWidth) {
  20850. utils.each(domUtils.getElementsByTagName(ut.table, "th"), function(
  20851. node
  20852. ) {
  20853. node.setAttribute("width", "");
  20854. });
  20855. var cells = ut.isFullRow()
  20856. ? domUtils.getElementsByTagName(ut.table, "td")
  20857. : ut.selectedTds;
  20858. utils.each(cells, function(node) {
  20859. if (node.colSpan == 1) {
  20860. node.setAttribute("width", averageWidth);
  20861. }
  20862. });
  20863. }
  20864. if (ut && ut.selectedTds.length) {
  20865. setAverageWidth(getAverageWidth());
  20866. }
  20867. }
  20868. };
  20869. //平均分配各行
  20870. UE.commands["averagedistributerow"] = {
  20871. queryCommandState: function() {
  20872. var ut = getUETableBySelected(this);
  20873. if (!ut) return -1;
  20874. if (ut.selectedTds && /th/gi.test(ut.selectedTds[0].tagName)) return -1;
  20875. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  20876. },
  20877. execCommand: function(cmd) {
  20878. var me = this,
  20879. ut = getUETableBySelected(me);
  20880. function getAverageHeight() {
  20881. var averageHeight,
  20882. rowNum,
  20883. sumHeight = 0,
  20884. tb = ut.table,
  20885. tbAttr = getDefaultValue(me, tb),
  20886. tdpadding = parseInt(
  20887. domUtils.getComputedStyle(
  20888. tb.getElementsByTagName("td")[0],
  20889. "padding-top"
  20890. )
  20891. );
  20892. if (ut.isFullCol()) {
  20893. var captionArr = domUtils.getElementsByTagName(tb, "caption"),
  20894. thArr = domUtils.getElementsByTagName(tb, "th"),
  20895. captionHeight,
  20896. thHeight;
  20897. if (captionArr.length > 0) {
  20898. captionHeight = captionArr[0].offsetHeight;
  20899. }
  20900. if (thArr.length > 0) {
  20901. thHeight = thArr[0].offsetHeight;
  20902. }
  20903. sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0);
  20904. rowNum = thArr.length == 0 ? ut.rowsNum : ut.rowsNum - 1;
  20905. } else {
  20906. var begin = ut.cellsRange.beginRowIndex,
  20907. end = ut.cellsRange.endRowIndex,
  20908. count = 0,
  20909. trs = domUtils.getElementsByTagName(tb, "tr");
  20910. for (var i = begin; i <= end; i++) {
  20911. sumHeight += trs[i].offsetHeight;
  20912. count += 1;
  20913. }
  20914. rowNum = count;
  20915. }
  20916. //ie8下是混杂模式
  20917. if (browser.ie && browser.version < 9) {
  20918. averageHeight = Math.ceil(sumHeight / rowNum);
  20919. } else {
  20920. averageHeight =
  20921. Math.ceil(sumHeight / rowNum) - tbAttr.tdBorder * 2 - tdpadding * 2;
  20922. }
  20923. return averageHeight;
  20924. }
  20925. function setAverageHeight(averageHeight) {
  20926. var cells = ut.isFullCol()
  20927. ? domUtils.getElementsByTagName(ut.table, "td")
  20928. : ut.selectedTds;
  20929. utils.each(cells, function(node) {
  20930. if (node.rowSpan == 1) {
  20931. node.setAttribute("height", averageHeight);
  20932. }
  20933. });
  20934. }
  20935. if (ut && ut.selectedTds.length) {
  20936. setAverageHeight(getAverageHeight());
  20937. }
  20938. }
  20939. };
  20940. //单元格对齐方式
  20941. UE.commands["cellalignment"] = {
  20942. queryCommandState: function() {
  20943. return getTableItemsByRange(this).table ? 0 : -1;
  20944. },
  20945. execCommand: function(cmd, data) {
  20946. var me = this,
  20947. ut = getUETableBySelected(me);
  20948. if (!ut) {
  20949. var start = me.selection.getStart(),
  20950. cell =
  20951. start &&
  20952. domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  20953. if (!/caption/gi.test(cell.tagName)) {
  20954. domUtils.setAttributes(cell, data);
  20955. } else {
  20956. cell.style.textAlign = data.align;
  20957. cell.style.verticalAlign = data.vAlign;
  20958. }
  20959. me.selection.getRange().setCursor(true);
  20960. } else {
  20961. utils.each(ut.selectedTds, function(cell) {
  20962. domUtils.setAttributes(cell, data);
  20963. });
  20964. }
  20965. },
  20966. /**
  20967. * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
  20968. * @see UE.UETable.getTableCellAlignState
  20969. */
  20970. queryCommandValue: function(cmd) {
  20971. var activeMenuCell = getTableItemsByRange(this).cell;
  20972. if (!activeMenuCell) {
  20973. activeMenuCell = getSelectedArr(this)[0];
  20974. }
  20975. if (!activeMenuCell) {
  20976. return null;
  20977. } else {
  20978. //获取同时选中的其他单元格
  20979. var cells = UE.UETable.getUETable(activeMenuCell).selectedTds;
  20980. !cells.length && (cells = activeMenuCell);
  20981. return UE.UETable.getTableCellAlignState(cells);
  20982. }
  20983. }
  20984. };
  20985. //表格对齐方式
  20986. UE.commands["tablealignment"] = {
  20987. queryCommandState: function() {
  20988. if (browser.ie && browser.version < 8) {
  20989. return -1;
  20990. }
  20991. return getTableItemsByRange(this).table ? 0 : -1;
  20992. },
  20993. execCommand: function(cmd, value) {
  20994. var me = this,
  20995. start = me.selection.getStart(),
  20996. table = start && domUtils.findParentByTagName(start, ["table"], true);
  20997. if (table) {
  20998. table.setAttribute("align", value);
  20999. }
  21000. }
  21001. };
  21002. //表格属性
  21003. UE.commands["edittable"] = {
  21004. queryCommandState: function() {
  21005. return getTableItemsByRange(this).table ? 0 : -1;
  21006. },
  21007. execCommand: function(cmd, color) {
  21008. var rng = this.selection.getRange(),
  21009. table = domUtils.findParentByTagName(rng.startContainer, "table");
  21010. if (table) {
  21011. var arr = domUtils
  21012. .getElementsByTagName(table, "td")
  21013. .concat(
  21014. domUtils.getElementsByTagName(table, "th"),
  21015. domUtils.getElementsByTagName(table, "caption")
  21016. );
  21017. utils.each(arr, function(node) {
  21018. node.style.borderColor = color;
  21019. });
  21020. }
  21021. }
  21022. };
  21023. //单元格属性
  21024. UE.commands["edittd"] = {
  21025. queryCommandState: function() {
  21026. return getTableItemsByRange(this).table ? 0 : -1;
  21027. },
  21028. execCommand: function(cmd, bkColor) {
  21029. var me = this,
  21030. ut = getUETableBySelected(me);
  21031. if (!ut) {
  21032. var start = me.selection.getStart(),
  21033. cell =
  21034. start &&
  21035. domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  21036. if (cell) {
  21037. cell.style.backgroundColor = bkColor;
  21038. }
  21039. } else {
  21040. utils.each(ut.selectedTds, function(cell) {
  21041. cell.style.backgroundColor = bkColor;
  21042. });
  21043. }
  21044. }
  21045. };
  21046. UE.commands["settablebackground"] = {
  21047. queryCommandState: function() {
  21048. return getSelectedArr(this).length > 1 ? 0 : -1;
  21049. },
  21050. execCommand: function(cmd, value) {
  21051. var cells, ut;
  21052. cells = getSelectedArr(this);
  21053. ut = getUETable(cells[0]);
  21054. ut.setBackground(cells, value);
  21055. }
  21056. };
  21057. UE.commands["cleartablebackground"] = {
  21058. queryCommandState: function() {
  21059. var cells = getSelectedArr(this);
  21060. if (!cells.length) return -1;
  21061. for (var i = 0, cell; (cell = cells[i++]); ) {
  21062. if (cell.style.backgroundColor !== "") return 0;
  21063. }
  21064. return -1;
  21065. },
  21066. execCommand: function() {
  21067. var cells = getSelectedArr(this),
  21068. ut = getUETable(cells[0]);
  21069. ut.removeBackground(cells);
  21070. }
  21071. };
  21072. UE.commands["interlacetable"] = UE.commands["uninterlacetable"] = {
  21073. queryCommandState: function(cmd) {
  21074. var table = getTableItemsByRange(this).table;
  21075. if (!table) return -1;
  21076. var interlaced = table.getAttribute("interlaced");
  21077. if (cmd == "interlacetable") {
  21078. //TODO 待定
  21079. //是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
  21080. return interlaced === "enabled" ? -1 : 0;
  21081. } else {
  21082. return !interlaced || interlaced === "disabled" ? -1 : 0;
  21083. }
  21084. },
  21085. execCommand: function(cmd, classList) {
  21086. var table = getTableItemsByRange(this).table;
  21087. if (cmd == "interlacetable") {
  21088. table.setAttribute("interlaced", "enabled");
  21089. this.fireEvent("interlacetable", table, classList);
  21090. } else {
  21091. table.setAttribute("interlaced", "disabled");
  21092. this.fireEvent("uninterlacetable", table);
  21093. }
  21094. }
  21095. };
  21096. UE.commands["setbordervisible"] = {
  21097. queryCommandState: function(cmd) {
  21098. var table = getTableItemsByRange(this).table;
  21099. if (!table) return -1;
  21100. return 0;
  21101. },
  21102. execCommand: function() {
  21103. var table = getTableItemsByRange(this).table;
  21104. utils.each(domUtils.getElementsByTagName(table, "td"), function(td) {
  21105. td.style.borderWidth = "1px";
  21106. td.style.borderStyle = "solid";
  21107. });
  21108. }
  21109. };
  21110. function resetTdWidth(table, editor) {
  21111. var tds = domUtils.getElementsByTagName(table, "td th");
  21112. utils.each(tds, function(td) {
  21113. td.removeAttribute("width");
  21114. });
  21115. table.setAttribute(
  21116. "width",
  21117. getTableWidth(editor, true, getDefaultValue(editor, table))
  21118. );
  21119. var tdsWidths = [];
  21120. setTimeout(function() {
  21121. utils.each(tds, function(td) {
  21122. td.colSpan == 1 && tdsWidths.push(td.offsetWidth);
  21123. });
  21124. utils.each(tds, function(td, i) {
  21125. td.colSpan == 1 && td.setAttribute("width", tdsWidths[i] + "");
  21126. });
  21127. }, 0);
  21128. }
  21129. function getTableWidth(editor, needIEHack, defaultValue) {
  21130. var body = editor.body;
  21131. return (
  21132. body.offsetWidth -
  21133. (needIEHack
  21134. ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
  21135. : 0) -
  21136. defaultValue.tableBorder * 2 -
  21137. (editor.options.offsetWidth || 0)
  21138. );
  21139. }
  21140. function getSelectedArr(editor) {
  21141. var cell = getTableItemsByRange(editor).cell;
  21142. if (cell) {
  21143. var ut = getUETable(cell);
  21144. return ut.selectedTds.length ? ut.selectedTds : [cell];
  21145. } else {
  21146. return [];
  21147. }
  21148. }
  21149. })();
  21150. // plugins/table.action.js
  21151. /**
  21152. * Created with JetBrains PhpStorm.
  21153. * User: taoqili
  21154. * Date: 12-10-12
  21155. * Time: 上午10:05
  21156. * To change this template use File | Settings | File Templates.
  21157. */
  21158. UE.plugins["table"] = function() {
  21159. var me = this,
  21160. tabTimer = null,
  21161. //拖动计时器
  21162. tableDragTimer = null,
  21163. //双击计时器
  21164. tableResizeTimer = null,
  21165. //单元格最小宽度
  21166. cellMinWidth = 5,
  21167. isInResizeBuffer = false,
  21168. //单元格边框大小
  21169. cellBorderWidth = 5,
  21170. //鼠标偏移距离
  21171. offsetOfTableCell = 10,
  21172. //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
  21173. singleClickState = 0,
  21174. userActionStatus = null,
  21175. //双击允许的时间范围
  21176. dblclickTime = 360,
  21177. UT = UE.UETable,
  21178. getUETable = function(tdOrTable) {
  21179. return UT.getUETable(tdOrTable);
  21180. },
  21181. getUETableBySelected = function(editor) {
  21182. return UT.getUETableBySelected(editor);
  21183. },
  21184. getDefaultValue = function(editor, table) {
  21185. return UT.getDefaultValue(editor, table);
  21186. },
  21187. removeSelectedClass = function(cells) {
  21188. return UT.removeSelectedClass(cells);
  21189. };
  21190. function showError(e) {
  21191. // throw e;
  21192. }
  21193. me.ready(function() {
  21194. var me = this;
  21195. var orgGetText = me.selection.getText;
  21196. me.selection.getText = function() {
  21197. var table = getUETableBySelected(me);
  21198. if (table) {
  21199. var str = "";
  21200. utils.each(table.selectedTds, function(td) {
  21201. str += td[browser.ie ? "innerText" : "textContent"];
  21202. });
  21203. return str;
  21204. } else {
  21205. return orgGetText.call(me.selection);
  21206. }
  21207. };
  21208. });
  21209. //处理拖动及框选相关方法
  21210. var startTd = null, //鼠标按下时的锚点td
  21211. currentTd = null, //当前鼠标经过时的td
  21212. onDrag = "", //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
  21213. onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
  21214. dragButton = null,
  21215. dragOver = false,
  21216. dragLine = null, //模拟的拖动线
  21217. dragTd = null; //发生拖动的目标td
  21218. var mousedown = false,
  21219. //todo 判断混乱模式
  21220. needIEHack = true;
  21221. me.setOpt({
  21222. maxColNum: 20,
  21223. maxRowNum: 100,
  21224. defaultCols: 5,
  21225. defaultRows: 5,
  21226. tdvalign: "top",
  21227. cursorpath: me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
  21228. tableDragable: false,
  21229. classList: [
  21230. "ue-table-interlace-color-single",
  21231. "ue-table-interlace-color-double"
  21232. ]
  21233. });
  21234. me.getUETable = getUETable;
  21235. var commands = {
  21236. deletetable: 1,
  21237. inserttable: 1,
  21238. cellvalign: 1,
  21239. insertcaption: 1,
  21240. deletecaption: 1,
  21241. inserttitle: 1,
  21242. deletetitle: 1,
  21243. mergeright: 1,
  21244. mergedown: 1,
  21245. mergecells: 1,
  21246. insertrow: 1,
  21247. insertrownext: 1,
  21248. deleterow: 1,
  21249. insertcol: 1,
  21250. insertcolnext: 1,
  21251. deletecol: 1,
  21252. splittocells: 1,
  21253. splittorows: 1,
  21254. splittocols: 1,
  21255. adaptbytext: 1,
  21256. adaptbywindow: 1,
  21257. adaptbycustomer: 1,
  21258. insertparagraph: 1,
  21259. insertparagraphbeforetable: 1,
  21260. averagedistributecol: 1,
  21261. averagedistributerow: 1
  21262. };
  21263. me.ready(function() {
  21264. utils.cssRule(
  21265. "table",
  21266. //选中的td上的样式
  21267. ".selectTdClass{background-color:#edf5fa !important}" +
  21268. "table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}" +
  21269. //插入的表格的默认样式
  21270. "table{margin-bottom:10px;border-collapse:collapse;display:table;}" +
  21271. "td,th{padding: 5px 10px;border: 1px solid #DDD;}" +
  21272. "caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}" +
  21273. "th{border-top:1px solid #BBB;background-color:#F7F7F7;}" +
  21274. "table tr.firstRow th{border-top-width:2px;}" +
  21275. ".ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }" +
  21276. "td p{margin:0;padding:0;}",
  21277. me.document
  21278. );
  21279. var tableCopyList, isFullCol, isFullRow;
  21280. //注册del/backspace事件
  21281. me.addListener("keydown", function(cmd, evt) {
  21282. var me = this;
  21283. var keyCode = evt.keyCode || evt.which;
  21284. if (keyCode == 8) {
  21285. var ut = getUETableBySelected(me);
  21286. if (ut && ut.selectedTds.length) {
  21287. if (ut.isFullCol()) {
  21288. me.execCommand("deletecol");
  21289. } else if (ut.isFullRow()) {
  21290. me.execCommand("deleterow");
  21291. } else {
  21292. me.fireEvent("delcells");
  21293. }
  21294. domUtils.preventDefault(evt);
  21295. }
  21296. var caption = domUtils.findParentByTagName(
  21297. me.selection.getStart(),
  21298. "caption",
  21299. true
  21300. ),
  21301. range = me.selection.getRange();
  21302. if (range.collapsed && caption && isEmptyBlock(caption)) {
  21303. me.fireEvent("saveScene");
  21304. var table = caption.parentNode;
  21305. domUtils.remove(caption);
  21306. if (table) {
  21307. range.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  21308. }
  21309. me.fireEvent("saveScene");
  21310. }
  21311. }
  21312. if (keyCode == 46) {
  21313. ut = getUETableBySelected(me);
  21314. if (ut) {
  21315. me.fireEvent("saveScene");
  21316. for (var i = 0, ci; (ci = ut.selectedTds[i++]); ) {
  21317. domUtils.fillNode(me.document, ci);
  21318. }
  21319. me.fireEvent("saveScene");
  21320. domUtils.preventDefault(evt);
  21321. }
  21322. }
  21323. if (keyCode == 13) {
  21324. var rng = me.selection.getRange(),
  21325. caption = domUtils.findParentByTagName(
  21326. rng.startContainer,
  21327. "caption",
  21328. true
  21329. );
  21330. if (caption) {
  21331. var table = domUtils.findParentByTagName(caption, "table");
  21332. if (!rng.collapsed) {
  21333. rng.deleteContents();
  21334. me.fireEvent("saveScene");
  21335. } else {
  21336. if (caption) {
  21337. rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  21338. }
  21339. }
  21340. domUtils.preventDefault(evt);
  21341. return;
  21342. }
  21343. if (rng.collapsed) {
  21344. var table = domUtils.findParentByTagName(rng.startContainer, "table");
  21345. if (table) {
  21346. var cell = table.rows[0].cells[0],
  21347. start = domUtils.findParentByTagName(
  21348. me.selection.getStart(),
  21349. ["td", "th"],
  21350. true
  21351. ),
  21352. preNode = table.previousSibling;
  21353. if (
  21354. cell === start &&
  21355. (!preNode ||
  21356. (preNode.nodeType == 1 && preNode.tagName == "TABLE")) &&
  21357. domUtils.isStartInblock(rng)
  21358. ) {
  21359. var first = domUtils.findParent(
  21360. me.selection.getStart(),
  21361. function(n) {
  21362. return domUtils.isBlockElm(n);
  21363. },
  21364. true
  21365. );
  21366. if (
  21367. first &&
  21368. (/t(h|d)/i.test(first.tagName) || first === start.firstChild)
  21369. ) {
  21370. me.execCommand("insertparagraphbeforetable");
  21371. domUtils.preventDefault(evt);
  21372. }
  21373. }
  21374. }
  21375. }
  21376. }
  21377. if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == "67") {
  21378. tableCopyList = null;
  21379. var ut = getUETableBySelected(me);
  21380. if (ut) {
  21381. var tds = ut.selectedTds;
  21382. isFullCol = ut.isFullCol();
  21383. isFullRow = ut.isFullRow();
  21384. tableCopyList = [[ut.cloneCell(tds[0], null, true)]];
  21385. for (var i = 1, ci; (ci = tds[i]); i++) {
  21386. if (ci.parentNode !== tds[i - 1].parentNode) {
  21387. tableCopyList.push([ut.cloneCell(ci, null, true)]);
  21388. } else {
  21389. tableCopyList[tableCopyList.length - 1].push(
  21390. ut.cloneCell(ci, null, true)
  21391. );
  21392. }
  21393. }
  21394. }
  21395. }
  21396. });
  21397. me.addListener("tablehasdeleted", function() {
  21398. toggleDraggableState(this, false, "", null);
  21399. if (dragButton) domUtils.remove(dragButton);
  21400. });
  21401. me.addListener("beforepaste", function(cmd, html) {
  21402. var me = this;
  21403. var rng = me.selection.getRange();
  21404. if (domUtils.findParentByTagName(rng.startContainer, "caption", true)) {
  21405. var div = me.document.createElement("div");
  21406. div.innerHTML = html.html;
  21407. //trace:3729
  21408. html.html = div[browser.ie9below ? "innerText" : "textContent"];
  21409. return;
  21410. }
  21411. var table = getUETableBySelected(me);
  21412. if (tableCopyList) {
  21413. me.fireEvent("saveScene");
  21414. var rng = me.selection.getRange();
  21415. var td = domUtils.findParentByTagName(
  21416. rng.startContainer,
  21417. ["td", "th"],
  21418. true
  21419. ),
  21420. tmpNode,
  21421. preNode;
  21422. if (td) {
  21423. var ut = getUETable(td);
  21424. if (isFullRow) {
  21425. var rowIndex = ut.getCellInfo(td).rowIndex;
  21426. if (td.tagName == "TH") {
  21427. rowIndex++;
  21428. }
  21429. for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
  21430. var tr = ut.insertRow(rowIndex++, "td");
  21431. for (var j = 0, cj; (cj = ci[j]); j++) {
  21432. var cell = tr.cells[j];
  21433. if (!cell) {
  21434. cell = tr.insertCell(j);
  21435. }
  21436. cell.innerHTML = cj.innerHTML;
  21437. cj.getAttribute("width") &&
  21438. cell.setAttribute("width", cj.getAttribute("width"));
  21439. cj.getAttribute("vAlign") &&
  21440. cell.setAttribute("vAlign", cj.getAttribute("vAlign"));
  21441. cj.getAttribute("align") &&
  21442. cell.setAttribute("align", cj.getAttribute("align"));
  21443. cj.style.cssText && (cell.style.cssText = cj.style.cssText);
  21444. }
  21445. for (var j = 0, cj; (cj = tr.cells[j]); j++) {
  21446. if (!ci[j]) break;
  21447. cj.innerHTML = ci[j].innerHTML;
  21448. ci[j].getAttribute("width") &&
  21449. cj.setAttribute("width", ci[j].getAttribute("width"));
  21450. ci[j].getAttribute("vAlign") &&
  21451. cj.setAttribute("vAlign", ci[j].getAttribute("vAlign"));
  21452. ci[j].getAttribute("align") &&
  21453. cj.setAttribute("align", ci[j].getAttribute("align"));
  21454. ci[j].style.cssText && (cj.style.cssText = ci[j].style.cssText);
  21455. }
  21456. }
  21457. } else {
  21458. if (isFullCol) {
  21459. cellInfo = ut.getCellInfo(td);
  21460. var maxColNum = 0;
  21461. for (var j = 0, ci = tableCopyList[0], cj; (cj = ci[j++]); ) {
  21462. maxColNum += cj.colSpan || 1;
  21463. }
  21464. me.__hasEnterExecCommand = true;
  21465. for (i = 0; i < maxColNum; i++) {
  21466. me.execCommand("insertcol");
  21467. }
  21468. me.__hasEnterExecCommand = false;
  21469. td = ut.table.rows[0].cells[cellInfo.cellIndex];
  21470. if (td.tagName == "TH") {
  21471. td = ut.table.rows[1].cells[cellInfo.cellIndex];
  21472. }
  21473. }
  21474. for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
  21475. tmpNode = td;
  21476. for (var j = 0, cj; (cj = ci[j++]); ) {
  21477. if (td) {
  21478. td.innerHTML = cj.innerHTML;
  21479. //todo 定制处理
  21480. cj.getAttribute("width") &&
  21481. td.setAttribute("width", cj.getAttribute("width"));
  21482. cj.getAttribute("vAlign") &&
  21483. td.setAttribute("vAlign", cj.getAttribute("vAlign"));
  21484. cj.getAttribute("align") &&
  21485. td.setAttribute("align", cj.getAttribute("align"));
  21486. cj.style.cssText && (td.style.cssText = cj.style.cssText);
  21487. preNode = td;
  21488. td = td.nextSibling;
  21489. } else {
  21490. var cloneTd = cj.cloneNode(true);
  21491. domUtils.removeAttributes(cloneTd, [
  21492. "class",
  21493. "rowSpan",
  21494. "colSpan"
  21495. ]);
  21496. preNode.parentNode.appendChild(cloneTd);
  21497. }
  21498. }
  21499. td = ut.getNextCell(tmpNode, true, true);
  21500. if (!tableCopyList[i]) break;
  21501. if (!td) {
  21502. var cellInfo = ut.getCellInfo(tmpNode);
  21503. ut.table.insertRow(ut.table.rows.length);
  21504. ut.update();
  21505. td = ut.getVSideCell(tmpNode, true);
  21506. }
  21507. }
  21508. }
  21509. ut.update();
  21510. } else {
  21511. table = me.document.createElement("table");
  21512. for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
  21513. var tr = table.insertRow(table.rows.length);
  21514. for (var j = 0, cj; (cj = ci[j++]); ) {
  21515. cloneTd = UT.cloneCell(cj, null, true);
  21516. domUtils.removeAttributes(cloneTd, ["class"]);
  21517. tr.appendChild(cloneTd);
  21518. }
  21519. if (j == 2 && cloneTd.rowSpan > 1) {
  21520. cloneTd.rowSpan = 1;
  21521. }
  21522. }
  21523. var defaultValue = getDefaultValue(me),
  21524. width =
  21525. me.body.offsetWidth -
  21526. (needIEHack
  21527. ? parseInt(
  21528. domUtils.getComputedStyle(me.body, "margin-left"),
  21529. 10
  21530. ) * 2
  21531. : 0) -
  21532. defaultValue.tableBorder * 2 -
  21533. (me.options.offsetWidth || 0);
  21534. me.execCommand(
  21535. "insertHTML",
  21536. "<table " +
  21537. (isFullCol && isFullRow ? 'width="' + width + '"' : "") +
  21538. ">" +
  21539. table.innerHTML
  21540. .replace(/>\s*</g, "><")
  21541. .replace(/\bth\b/gi, "td") +
  21542. "</table>"
  21543. );
  21544. }
  21545. me.fireEvent("contentchange");
  21546. me.fireEvent("saveScene");
  21547. html.html = "";
  21548. return true;
  21549. } else {
  21550. var div = me.document.createElement("div"),
  21551. tables;
  21552. div.innerHTML = html.html;
  21553. tables = div.getElementsByTagName("table");
  21554. if (domUtils.findParentByTagName(me.selection.getStart(), "table")) {
  21555. utils.each(tables, function(t) {
  21556. domUtils.remove(t);
  21557. });
  21558. if (
  21559. domUtils.findParentByTagName(
  21560. me.selection.getStart(),
  21561. "caption",
  21562. true
  21563. )
  21564. ) {
  21565. div.innerHTML = div[browser.ie ? "innerText" : "textContent"];
  21566. }
  21567. } else {
  21568. utils.each(tables, function(table) {
  21569. removeStyleSize(table, true);
  21570. domUtils.removeAttributes(table, ["style", "border"]);
  21571. utils.each(domUtils.getElementsByTagName(table, "td"), function(
  21572. td
  21573. ) {
  21574. if (isEmptyBlock(td)) {
  21575. domUtils.fillNode(me.document, td);
  21576. }
  21577. removeStyleSize(td, true);
  21578. // domUtils.removeAttributes(td, ['style'])
  21579. });
  21580. });
  21581. }
  21582. html.html = div.innerHTML;
  21583. }
  21584. });
  21585. me.addListener("afterpaste", function() {
  21586. utils.each(domUtils.getElementsByTagName(me.body, "table"), function(
  21587. table
  21588. ) {
  21589. if (table.offsetWidth > me.body.offsetWidth) {
  21590. var defaultValue = getDefaultValue(me, table);
  21591. table.style.width =
  21592. me.body.offsetWidth -
  21593. (needIEHack
  21594. ? parseInt(
  21595. domUtils.getComputedStyle(me.body, "margin-left"),
  21596. 10
  21597. ) * 2
  21598. : 0) -
  21599. defaultValue.tableBorder * 2 -
  21600. (me.options.offsetWidth || 0) +
  21601. "px";
  21602. }
  21603. });
  21604. });
  21605. me.addListener("blur", function() {
  21606. tableCopyList = null;
  21607. });
  21608. var timer;
  21609. me.addListener("keydown", function() {
  21610. clearTimeout(timer);
  21611. timer = setTimeout(function() {
  21612. var rng = me.selection.getRange(),
  21613. cell = domUtils.findParentByTagName(
  21614. rng.startContainer,
  21615. ["th", "td"],
  21616. true
  21617. );
  21618. if (cell) {
  21619. var table = cell.parentNode.parentNode.parentNode;
  21620. if (table.offsetWidth > table.getAttribute("width")) {
  21621. cell.style.wordBreak = "break-all";
  21622. }
  21623. }
  21624. }, 100);
  21625. });
  21626. me.addListener("selectionchange", function() {
  21627. toggleDraggableState(me, false, "", null);
  21628. });
  21629. //内容变化时触发索引更新
  21630. //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
  21631. me.addListener("contentchange", function() {
  21632. var me = this;
  21633. //尽可能排除一些不需要更新的状况
  21634. hideDragLine(me);
  21635. if (getUETableBySelected(me)) return;
  21636. var rng = me.selection.getRange();
  21637. var start = rng.startContainer;
  21638. start = domUtils.findParentByTagName(start, ["td", "th"], true);
  21639. utils.each(domUtils.getElementsByTagName(me.document, "table"), function(
  21640. table
  21641. ) {
  21642. if (me.fireEvent("excludetable", table) === true) return;
  21643. table.ueTable = new UT(table);
  21644. //trace:3742
  21645. // utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
  21646. //
  21647. // if (domUtils.isEmptyBlock(td) && td !== start) {
  21648. // domUtils.fillNode(me.document, td);
  21649. // if (browser.ie && browser.version == 6) {
  21650. // td.innerHTML = '&nbsp;'
  21651. // }
  21652. // }
  21653. // });
  21654. // utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
  21655. // if (domUtils.isEmptyBlock(th) && th !== start) {
  21656. // domUtils.fillNode(me.document, th);
  21657. // if (browser.ie && browser.version == 6) {
  21658. // th.innerHTML = '&nbsp;'
  21659. // }
  21660. // }
  21661. // });
  21662. table.onmouseover = function() {
  21663. me.fireEvent("tablemouseover", table);
  21664. };
  21665. table.onmousemove = function() {
  21666. me.fireEvent("tablemousemove", table);
  21667. me.options.tableDragable && toggleDragButton(true, this, me);
  21668. utils.defer(function() {
  21669. me.fireEvent("contentchange", 50);
  21670. }, true);
  21671. };
  21672. table.onmouseout = function() {
  21673. me.fireEvent("tablemouseout", table);
  21674. toggleDraggableState(me, false, "", null);
  21675. hideDragLine(me);
  21676. };
  21677. table.onclick = function(evt) {
  21678. evt = me.window.event || evt;
  21679. var target = getParentTdOrTh(evt.target || evt.srcElement);
  21680. if (!target) return;
  21681. var ut = getUETable(target),
  21682. table = ut.table,
  21683. cellInfo = ut.getCellInfo(target),
  21684. cellsRange,
  21685. rng = me.selection.getRange();
  21686. // if ("topLeft" == inPosition(table, mouseCoords(evt))) {
  21687. // cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
  21688. // ut.setSelected(cellsRange);
  21689. // return;
  21690. // }
  21691. // if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
  21692. //
  21693. // return;
  21694. // }
  21695. if (inTableSide(table, target, evt, true)) {
  21696. var endTdCol = ut.getCell(
  21697. ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex,
  21698. ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex
  21699. );
  21700. if (evt.shiftKey && ut.selectedTds.length) {
  21701. if (ut.selectedTds[0] !== endTdCol) {
  21702. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol);
  21703. ut.setSelected(cellsRange);
  21704. } else {
  21705. rng && rng.selectNodeContents(endTdCol).select();
  21706. }
  21707. } else {
  21708. if (target !== endTdCol) {
  21709. cellsRange = ut.getCellsRange(target, endTdCol);
  21710. ut.setSelected(cellsRange);
  21711. } else {
  21712. rng && rng.selectNodeContents(endTdCol).select();
  21713. }
  21714. }
  21715. return;
  21716. }
  21717. if (inTableSide(table, target, evt)) {
  21718. var endTdRow = ut.getCell(
  21719. ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex,
  21720. ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex
  21721. );
  21722. if (evt.shiftKey && ut.selectedTds.length) {
  21723. if (ut.selectedTds[0] !== endTdRow) {
  21724. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow);
  21725. ut.setSelected(cellsRange);
  21726. } else {
  21727. rng && rng.selectNodeContents(endTdRow).select();
  21728. }
  21729. } else {
  21730. if (target !== endTdRow) {
  21731. cellsRange = ut.getCellsRange(target, endTdRow);
  21732. ut.setSelected(cellsRange);
  21733. } else {
  21734. rng && rng.selectNodeContents(endTdRow).select();
  21735. }
  21736. }
  21737. }
  21738. };
  21739. });
  21740. switchBorderColor(me, true);
  21741. });
  21742. domUtils.on(me.document, "mousemove", mouseMoveEvent);
  21743. domUtils.on(me.document, "mouseout", function(evt) {
  21744. var target = evt.target || evt.srcElement;
  21745. if (target.tagName == "TABLE") {
  21746. toggleDraggableState(me, false, "", null);
  21747. }
  21748. });
  21749. /**
  21750. * 表格隔行变色
  21751. */
  21752. me.addListener("interlacetable", function(type, table, classList) {
  21753. if (!table) return;
  21754. var me = this,
  21755. rows = table.rows,
  21756. len = rows.length,
  21757. getClass = function(list, index, repeat) {
  21758. return list[index]
  21759. ? list[index]
  21760. : repeat ? list[index % list.length] : "";
  21761. };
  21762. for (var i = 0; i < len; i++) {
  21763. rows[i].className = getClass(
  21764. classList || me.options.classList,
  21765. i,
  21766. true
  21767. );
  21768. }
  21769. });
  21770. me.addListener("uninterlacetable", function(type, table) {
  21771. if (!table) return;
  21772. var me = this,
  21773. rows = table.rows,
  21774. classList = me.options.classList,
  21775. len = rows.length;
  21776. for (var i = 0; i < len; i++) {
  21777. domUtils.removeClasses(rows[i], classList);
  21778. }
  21779. });
  21780. me.addListener("mousedown", mouseDownEvent);
  21781. me.addListener("mouseup", mouseUpEvent);
  21782. //拖动的时候触发mouseup
  21783. domUtils.on(me.body, "dragstart", function(evt) {
  21784. mouseUpEvent.call(me, "dragstart", evt);
  21785. });
  21786. me.addOutputRule(function(root) {
  21787. utils.each(root.getNodesByTagName("div"), function(n) {
  21788. if (n.getAttr("id") == "ue_tableDragLine") {
  21789. n.parentNode.removeChild(n);
  21790. }
  21791. });
  21792. });
  21793. var currentRowIndex = 0;
  21794. me.addListener("mousedown", function() {
  21795. currentRowIndex = 0;
  21796. });
  21797. me.addListener("tabkeydown", function() {
  21798. var range = this.selection.getRange(),
  21799. common = range.getCommonAncestor(true, true),
  21800. table = domUtils.findParentByTagName(common, "table");
  21801. if (table) {
  21802. if (domUtils.findParentByTagName(common, "caption", true)) {
  21803. var cell = domUtils.getElementsByTagName(table, "th td");
  21804. if (cell && cell.length) {
  21805. range.setStart(cell[0], 0).setCursor(false, true);
  21806. }
  21807. } else {
  21808. var cell = domUtils.findParentByTagName(common, ["td", "th"], true),
  21809. ua = getUETable(cell);
  21810. currentRowIndex = cell.rowSpan > 1
  21811. ? currentRowIndex
  21812. : ua.getCellInfo(cell).rowIndex;
  21813. var nextCell = ua.getTabNextCell(cell, currentRowIndex);
  21814. if (nextCell) {
  21815. if (isEmptyBlock(nextCell)) {
  21816. range.setStart(nextCell, 0).setCursor(false, true);
  21817. } else {
  21818. range.selectNodeContents(nextCell).select();
  21819. }
  21820. } else {
  21821. me.fireEvent("saveScene");
  21822. me.__hasEnterExecCommand = true;
  21823. this.execCommand("insertrownext");
  21824. me.__hasEnterExecCommand = false;
  21825. range = this.selection.getRange();
  21826. range
  21827. .setStart(table.rows[table.rows.length - 1].cells[0], 0)
  21828. .setCursor();
  21829. me.fireEvent("saveScene");
  21830. }
  21831. }
  21832. return true;
  21833. }
  21834. });
  21835. browser.ie &&
  21836. me.addListener("selectionchange", function() {
  21837. toggleDraggableState(this, false, "", null);
  21838. });
  21839. me.addListener("keydown", function(type, evt) {
  21840. var me = this;
  21841. //处理在表格的最后一个输入tab产生新的表格
  21842. var keyCode = evt.keyCode || evt.which;
  21843. if (keyCode == 8 || keyCode == 46) {
  21844. return;
  21845. }
  21846. var notCtrlKey =
  21847. !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey;
  21848. notCtrlKey &&
  21849. removeSelectedClass(domUtils.getElementsByTagName(me.body, "td"));
  21850. var ut = getUETableBySelected(me);
  21851. if (!ut) return;
  21852. notCtrlKey && ut.clearSelected();
  21853. });
  21854. me.addListener("beforegetcontent", function() {
  21855. switchBorderColor(this, false);
  21856. browser.ie &&
  21857. utils.each(this.document.getElementsByTagName("caption"), function(ci) {
  21858. if (domUtils.isEmptyNode(ci)) {
  21859. ci.innerHTML = "&nbsp;";
  21860. }
  21861. });
  21862. });
  21863. me.addListener("aftergetcontent", function() {
  21864. switchBorderColor(this, true);
  21865. });
  21866. me.addListener("getAllHtml", function() {
  21867. removeSelectedClass(me.document.getElementsByTagName("td"));
  21868. });
  21869. //修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
  21870. me.addListener("fullscreenchanged", function(type, fullscreen) {
  21871. if (!fullscreen) {
  21872. var ratio = this.body.offsetWidth / document.body.offsetWidth,
  21873. tables = domUtils.getElementsByTagName(this.body, "table");
  21874. utils.each(tables, function(table) {
  21875. if (table.offsetWidth < me.body.offsetWidth) return false;
  21876. var tds = domUtils.getElementsByTagName(table, "td"),
  21877. backWidths = [];
  21878. utils.each(tds, function(td) {
  21879. backWidths.push(td.offsetWidth);
  21880. });
  21881. for (var i = 0, td; (td = tds[i]); i++) {
  21882. td.setAttribute("width", Math.floor(backWidths[i] * ratio));
  21883. }
  21884. table.setAttribute(
  21885. "width",
  21886. Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me)))
  21887. );
  21888. });
  21889. }
  21890. });
  21891. //重写execCommand命令,用于处理框选时的处理
  21892. var oldExecCommand = me.execCommand;
  21893. me.execCommand = function(cmd, datatat) {
  21894. var me = this,
  21895. args = arguments;
  21896. cmd = cmd.toLowerCase();
  21897. var ut = getUETableBySelected(me),
  21898. tds,
  21899. range = new dom.Range(me.document),
  21900. cmdFun = me.commands[cmd] || UE.commands[cmd],
  21901. result;
  21902. if (!cmdFun) return;
  21903. if (
  21904. ut &&
  21905. !commands[cmd] &&
  21906. !cmdFun.notNeedUndo &&
  21907. !me.__hasEnterExecCommand
  21908. ) {
  21909. me.__hasEnterExecCommand = true;
  21910. me.fireEvent("beforeexeccommand", cmd);
  21911. tds = ut.selectedTds;
  21912. var lastState = -2,
  21913. lastValue = -2,
  21914. value,
  21915. state;
  21916. for (var i = 0, td; (td = tds[i]); i++) {
  21917. if (isEmptyBlock(td)) {
  21918. range.setStart(td, 0).setCursor(false, true);
  21919. } else {
  21920. range.selectNode(td).select(true);
  21921. }
  21922. state = me.queryCommandState(cmd);
  21923. value = me.queryCommandValue(cmd);
  21924. if (state != -1) {
  21925. if (lastState !== state || lastValue !== value) {
  21926. me._ignoreContentChange = true;
  21927. result = oldExecCommand.apply(me, arguments);
  21928. me._ignoreContentChange = false;
  21929. }
  21930. lastState = me.queryCommandState(cmd);
  21931. lastValue = me.queryCommandValue(cmd);
  21932. if (domUtils.isEmptyBlock(td)) {
  21933. domUtils.fillNode(me.document, td);
  21934. }
  21935. }
  21936. }
  21937. range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true);
  21938. me.fireEvent("contentchange");
  21939. me.fireEvent("afterexeccommand", cmd);
  21940. me.__hasEnterExecCommand = false;
  21941. me._selectionChange();
  21942. } else {
  21943. result = oldExecCommand.apply(me, arguments);
  21944. }
  21945. return result;
  21946. };
  21947. });
  21948. /**
  21949. * 删除obj的宽高style,改成属性宽高
  21950. * @param obj
  21951. * @param replaceToProperty
  21952. */
  21953. function removeStyleSize(obj, replaceToProperty) {
  21954. removeStyle(obj, "width", true);
  21955. removeStyle(obj, "height", true);
  21956. }
  21957. function removeStyle(obj, styleName, replaceToProperty) {
  21958. if (obj.style[styleName]) {
  21959. replaceToProperty &&
  21960. obj.setAttribute(styleName, parseInt(obj.style[styleName], 10));
  21961. obj.style[styleName] = "";
  21962. }
  21963. }
  21964. function getParentTdOrTh(ele) {
  21965. if (ele.tagName == "TD" || ele.tagName == "TH") return ele;
  21966. var td;
  21967. if (
  21968. (td =
  21969. domUtils.findParentByTagName(ele, "td", true) ||
  21970. domUtils.findParentByTagName(ele, "th", true))
  21971. )
  21972. return td;
  21973. return null;
  21974. }
  21975. function isEmptyBlock(node) {
  21976. var reg = new RegExp(domUtils.fillChar, "g");
  21977. if (
  21978. node[browser.ie ? "innerText" : "textContent"]
  21979. .replace(/^\s*$/, "")
  21980. .replace(reg, "").length > 0
  21981. ) {
  21982. return 0;
  21983. }
  21984. for (var n in dtd.$isNotEmpty) {
  21985. if (node.getElementsByTagName(n).length) {
  21986. return 0;
  21987. }
  21988. }
  21989. return 1;
  21990. }
  21991. function mouseCoords(evt) {
  21992. if (evt.pageX || evt.pageY) {
  21993. return { x: evt.pageX, y: evt.pageY };
  21994. }
  21995. return {
  21996. x:
  21997. evt.clientX + me.document.body.scrollLeft - me.document.body.clientLeft,
  21998. y: evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
  21999. };
  22000. }
  22001. function mouseMoveEvent(evt) {
  22002. if (isEditorDisabled()) {
  22003. return;
  22004. }
  22005. try {
  22006. //普通状态下鼠标移动
  22007. var target = getParentTdOrTh(evt.target || evt.srcElement),
  22008. pos;
  22009. //区分用户的行为是拖动还是双击
  22010. if (isInResizeBuffer) {
  22011. me.body.style.webkitUserSelect = "none";
  22012. if (
  22013. Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell ||
  22014. Math.abs(userActionStatus.y - evt.clientY) > offsetOfTableCell
  22015. ) {
  22016. clearTableDragTimer();
  22017. isInResizeBuffer = false;
  22018. singleClickState = 0;
  22019. //drag action
  22020. tableBorderDrag(evt);
  22021. }
  22022. }
  22023. //修改单元格大小时的鼠标移动
  22024. if (onDrag && dragTd) {
  22025. singleClickState = 0;
  22026. me.body.style.webkitUserSelect = "none";
  22027. me.selection.getNative()[
  22028. browser.ie9below ? "empty" : "removeAllRanges"
  22029. ]();
  22030. pos = mouseCoords(evt);
  22031. toggleDraggableState(me, true, onDrag, pos, target);
  22032. if (onDrag == "h") {
  22033. dragLine.style.left = getPermissionX(dragTd, evt) + "px";
  22034. } else if (onDrag == "v") {
  22035. dragLine.style.top = getPermissionY(dragTd, evt) + "px";
  22036. }
  22037. return;
  22038. }
  22039. //当鼠标处于table上时,修改移动过程中的光标状态
  22040. if (target) {
  22041. //针对使用table作为容器的组件不触发拖拽效果
  22042. if (me.fireEvent("excludetable", target) === true) return;
  22043. pos = mouseCoords(evt);
  22044. var state = getRelation(target, pos),
  22045. table = domUtils.findParentByTagName(target, "table", true);
  22046. if (inTableSide(table, target, evt, true)) {
  22047. if (me.fireEvent("excludetable", table) === true) return;
  22048. me.body.style.cursor =
  22049. "url(" + me.options.cursorpath + "h.png),pointer";
  22050. } else if (inTableSide(table, target, evt)) {
  22051. if (me.fireEvent("excludetable", table) === true) return;
  22052. me.body.style.cursor =
  22053. "url(" + me.options.cursorpath + "v.png),pointer";
  22054. } else {
  22055. me.body.style.cursor = "text";
  22056. var curCell = target;
  22057. if (/\d/.test(state)) {
  22058. state = state.replace(/\d/, "");
  22059. target = getUETable(target).getPreviewCell(target, state == "v");
  22060. }
  22061. //位于第一行的顶部或者第一列的左边时不可拖动
  22062. toggleDraggableState(
  22063. me,
  22064. target ? !!state : false,
  22065. target ? state : "",
  22066. pos,
  22067. target
  22068. );
  22069. }
  22070. } else {
  22071. toggleDragButton(false, table, me);
  22072. }
  22073. } catch (e) {
  22074. showError(e);
  22075. }
  22076. }
  22077. var dragButtonTimer;
  22078. function toggleDragButton(show, table, editor) {
  22079. if (!show) {
  22080. if (dragOver) return;
  22081. dragButtonTimer = setTimeout(function() {
  22082. !dragOver &&
  22083. dragButton &&
  22084. dragButton.parentNode &&
  22085. dragButton.parentNode.removeChild(dragButton);
  22086. }, 2000);
  22087. } else {
  22088. createDragButton(table, editor);
  22089. }
  22090. }
  22091. function createDragButton(table, editor) {
  22092. var pos = domUtils.getXY(table),
  22093. doc = table.ownerDocument;
  22094. if (dragButton && dragButton.parentNode) return dragButton;
  22095. dragButton = doc.createElement("div");
  22096. dragButton.contentEditable = false;
  22097. dragButton.innerHTML = "";
  22098. dragButton.style.cssText =
  22099. "width:15px;height:15px;background-image:url(" +
  22100. editor.options.UEDITOR_HOME_URL +
  22101. "dialogs/table/dragicon.png);position: absolute;cursor:move;top:" +
  22102. (pos.y - 15) +
  22103. "px;left:" +
  22104. pos.x +
  22105. "px;";
  22106. domUtils.unSelectable(dragButton);
  22107. dragButton.onmouseover = function(evt) {
  22108. dragOver = true;
  22109. };
  22110. dragButton.onmouseout = function(evt) {
  22111. dragOver = false;
  22112. };
  22113. domUtils.on(dragButton, "click", function(type, evt) {
  22114. doClick(evt, this);
  22115. });
  22116. domUtils.on(dragButton, "dblclick", function(type, evt) {
  22117. doDblClick(evt);
  22118. });
  22119. domUtils.on(dragButton, "dragstart", function(type, evt) {
  22120. domUtils.preventDefault(evt);
  22121. });
  22122. var timer;
  22123. function doClick(evt, button) {
  22124. // 部分浏览器下需要清理
  22125. clearTimeout(timer);
  22126. timer = setTimeout(function() {
  22127. editor.fireEvent("tableClicked", table, button);
  22128. }, 300);
  22129. }
  22130. function doDblClick(evt) {
  22131. clearTimeout(timer);
  22132. var ut = getUETable(table),
  22133. start = table.rows[0].cells[0],
  22134. end = ut.getLastCell(),
  22135. range = ut.getCellsRange(start, end);
  22136. editor.selection.getRange().setStart(start, 0).setCursor(false, true);
  22137. ut.setSelected(range);
  22138. }
  22139. doc.body.appendChild(dragButton);
  22140. }
  22141. // function inPosition(table, pos) {
  22142. // var tablePos = domUtils.getXY(table),
  22143. // width = table.offsetWidth,
  22144. // height = table.offsetHeight;
  22145. // if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
  22146. // return "topLeft";
  22147. // } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
  22148. // return "bottomRight";
  22149. // }
  22150. // }
  22151. function inTableSide(table, cell, evt, top) {
  22152. var pos = mouseCoords(evt),
  22153. state = getRelation(cell, pos);
  22154. if (top) {
  22155. var caption = table.getElementsByTagName("caption")[0],
  22156. capHeight = caption ? caption.offsetHeight : 0;
  22157. return state == "v1" && pos.y - domUtils.getXY(table).y - capHeight < 8;
  22158. } else {
  22159. return state == "h1" && pos.x - domUtils.getXY(table).x < 8;
  22160. }
  22161. }
  22162. /**
  22163. * 获取拖动时允许的X轴坐标
  22164. * @param dragTd
  22165. * @param evt
  22166. */
  22167. function getPermissionX(dragTd, evt) {
  22168. var ut = getUETable(dragTd);
  22169. if (ut) {
  22170. var preTd = ut.getSameEndPosCells(dragTd, "x")[0],
  22171. nextTd = ut.getSameStartPosXCells(dragTd)[0],
  22172. mouseX = mouseCoords(evt).x,
  22173. left =
  22174. (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20,
  22175. right = nextTd
  22176. ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20
  22177. : me.body.offsetWidth + 5 ||
  22178. parseInt(domUtils.getComputedStyle(me.body, "width"), 10);
  22179. left += cellMinWidth;
  22180. right -= cellMinWidth;
  22181. return mouseX < left ? left : mouseX > right ? right : mouseX;
  22182. }
  22183. }
  22184. /**
  22185. * 获取拖动时允许的Y轴坐标
  22186. */
  22187. function getPermissionY(dragTd, evt) {
  22188. try {
  22189. var top = domUtils.getXY(dragTd).y,
  22190. mousePosY = mouseCoords(evt).y;
  22191. return mousePosY < top ? top : mousePosY;
  22192. } catch (e) {
  22193. showError(e);
  22194. }
  22195. }
  22196. /**
  22197. * 移动状态切换
  22198. */
  22199. function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
  22200. try {
  22201. editor.body.style.cursor = dir == "h"
  22202. ? "col-resize"
  22203. : dir == "v" ? "row-resize" : "text";
  22204. if (browser.ie) {
  22205. if (dir && !mousedown && !getUETableBySelected(editor)) {
  22206. getDragLine(editor, editor.document);
  22207. showDragLineAt(dir, cell);
  22208. } else {
  22209. hideDragLine(editor);
  22210. }
  22211. }
  22212. onBorder = draggable;
  22213. } catch (e) {
  22214. showError(e);
  22215. }
  22216. }
  22217. /**
  22218. * 获取与UETable相关的resize line
  22219. * @param uetable UETable对象
  22220. */
  22221. function getResizeLineByUETable() {
  22222. var lineId = "_UETableResizeLine",
  22223. line = this.document.getElementById(lineId);
  22224. if (!line) {
  22225. line = this.document.createElement("div");
  22226. line.id = lineId;
  22227. line.contnetEditable = false;
  22228. line.setAttribute("unselectable", "on");
  22229. var styles = {
  22230. width: 2 * cellBorderWidth + 1 + "px",
  22231. position: "absolute",
  22232. "z-index": 100000,
  22233. cursor: "col-resize",
  22234. background: "red",
  22235. display: "none"
  22236. };
  22237. //切换状态
  22238. line.onmouseout = function() {
  22239. this.style.display = "none";
  22240. };
  22241. utils.extend(line.style, styles);
  22242. this.document.body.appendChild(line);
  22243. }
  22244. return line;
  22245. }
  22246. /**
  22247. * 更新resize-line
  22248. */
  22249. function updateResizeLine(cell, uetable) {
  22250. var line = getResizeLineByUETable.call(this),
  22251. table = uetable.table,
  22252. styles = {
  22253. top: domUtils.getXY(table).y + "px",
  22254. left:
  22255. domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + "px",
  22256. display: "block",
  22257. height: table.offsetHeight + "px"
  22258. };
  22259. utils.extend(line.style, styles);
  22260. }
  22261. /**
  22262. * 显示resize-line
  22263. */
  22264. function showResizeLine(cell) {
  22265. var uetable = getUETable(cell);
  22266. updateResizeLine.call(this, cell, uetable);
  22267. }
  22268. /**
  22269. * 获取鼠标与当前单元格的相对位置
  22270. * @param ele
  22271. * @param mousePos
  22272. */
  22273. function getRelation(ele, mousePos) {
  22274. var elePos = domUtils.getXY(ele);
  22275. if (!elePos) {
  22276. return "";
  22277. }
  22278. if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
  22279. return "h";
  22280. }
  22281. if (mousePos.x - elePos.x < cellBorderWidth) {
  22282. return "h1";
  22283. }
  22284. if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
  22285. return "v";
  22286. }
  22287. if (mousePos.y - elePos.y < cellBorderWidth) {
  22288. return "v1";
  22289. }
  22290. return "";
  22291. }
  22292. function mouseDownEvent(type, evt) {
  22293. if (isEditorDisabled()) {
  22294. return;
  22295. }
  22296. userActionStatus = {
  22297. x: evt.clientX,
  22298. y: evt.clientY
  22299. };
  22300. //右键菜单单独处理
  22301. if (evt.button == 2) {
  22302. var ut = getUETableBySelected(me),
  22303. flag = false;
  22304. if (ut) {
  22305. var td = getTargetTd(me, evt);
  22306. utils.each(ut.selectedTds, function(ti) {
  22307. if (ti === td) {
  22308. flag = true;
  22309. }
  22310. });
  22311. if (!flag) {
  22312. removeSelectedClass(domUtils.getElementsByTagName(me.body, "th td"));
  22313. ut.clearSelected();
  22314. } else {
  22315. td = ut.selectedTds[0];
  22316. setTimeout(function() {
  22317. me.selection.getRange().setStart(td, 0).setCursor(false, true);
  22318. }, 0);
  22319. }
  22320. }
  22321. } else {
  22322. tableClickHander(evt);
  22323. }
  22324. }
  22325. //清除表格的计时器
  22326. function clearTableTimer() {
  22327. tabTimer && clearTimeout(tabTimer);
  22328. tabTimer = null;
  22329. }
  22330. //双击收缩
  22331. function tableDbclickHandler(evt) {
  22332. singleClickState = 0;
  22333. evt = evt || me.window.event;
  22334. var target = getParentTdOrTh(evt.target || evt.srcElement);
  22335. if (target) {
  22336. var h;
  22337. if ((h = getRelation(target, mouseCoords(evt)))) {
  22338. hideDragLine(me);
  22339. if (h == "h1") {
  22340. h = "h";
  22341. if (
  22342. inTableSide(
  22343. domUtils.findParentByTagName(target, "table"),
  22344. target,
  22345. evt
  22346. )
  22347. ) {
  22348. me.execCommand("adaptbywindow");
  22349. } else {
  22350. target = getUETable(target).getPreviewCell(target);
  22351. if (target) {
  22352. var rng = me.selection.getRange();
  22353. rng.selectNodeContents(target).setCursor(true, true);
  22354. }
  22355. }
  22356. }
  22357. if (h == "h") {
  22358. var ut = getUETable(target),
  22359. table = ut.table,
  22360. cells = getCellsByMoveBorder(target, table, true);
  22361. cells = extractArray(cells, "left");
  22362. ut.width = ut.offsetWidth;
  22363. var oldWidth = [],
  22364. newWidth = [];
  22365. utils.each(cells, function(cell) {
  22366. oldWidth.push(cell.offsetWidth);
  22367. });
  22368. utils.each(cells, function(cell) {
  22369. cell.removeAttribute("width");
  22370. });
  22371. window.setTimeout(function() {
  22372. //是否允许改变
  22373. var changeable = true;
  22374. utils.each(cells, function(cell, index) {
  22375. var width = cell.offsetWidth;
  22376. if (width > oldWidth[index]) {
  22377. changeable = false;
  22378. return false;
  22379. }
  22380. newWidth.push(width);
  22381. });
  22382. var change = changeable ? newWidth : oldWidth;
  22383. utils.each(cells, function(cell, index) {
  22384. cell.width = change[index] - getTabcellSpace();
  22385. });
  22386. }, 0);
  22387. // minWidth -= cellMinWidth;
  22388. //
  22389. // table.removeAttribute("width");
  22390. // utils.each(cells, function (cell) {
  22391. // cell.style.width = "";
  22392. // cell.width -= minWidth;
  22393. // });
  22394. }
  22395. }
  22396. }
  22397. }
  22398. function tableClickHander(evt) {
  22399. removeSelectedClass(domUtils.getElementsByTagName(me.body, "td th"));
  22400. //trace:3113
  22401. //选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
  22402. utils.each(me.document.getElementsByTagName("table"), function(t) {
  22403. t.ueTable = null;
  22404. });
  22405. startTd = getTargetTd(me, evt);
  22406. if (!startTd) return;
  22407. var table = domUtils.findParentByTagName(startTd, "table", true);
  22408. ut = getUETable(table);
  22409. ut && ut.clearSelected();
  22410. //判断当前鼠标状态
  22411. if (!onBorder) {
  22412. me.document.body.style.webkitUserSelect = "";
  22413. mousedown = true;
  22414. me.addListener("mouseover", mouseOverEvent);
  22415. } else {
  22416. //边框上的动作处理
  22417. borderActionHandler(evt);
  22418. }
  22419. }
  22420. //处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
  22421. function borderActionHandler(evt) {
  22422. if (browser.ie) {
  22423. evt = reconstruct(evt);
  22424. }
  22425. clearTableDragTimer();
  22426. //是否正在等待resize的缓冲中
  22427. isInResizeBuffer = true;
  22428. tableDragTimer = setTimeout(function() {
  22429. tableBorderDrag(evt);
  22430. }, dblclickTime);
  22431. }
  22432. function extractArray(originArr, key) {
  22433. var result = [],
  22434. tmp = null;
  22435. for (var i = 0, len = originArr.length; i < len; i++) {
  22436. tmp = originArr[i][key];
  22437. if (tmp) {
  22438. result.push(tmp);
  22439. }
  22440. }
  22441. return result;
  22442. }
  22443. function clearTableDragTimer() {
  22444. tableDragTimer && clearTimeout(tableDragTimer);
  22445. tableDragTimer = null;
  22446. }
  22447. function reconstruct(obj) {
  22448. var attrs = [
  22449. "pageX",
  22450. "pageY",
  22451. "clientX",
  22452. "clientY",
  22453. "srcElement",
  22454. "target"
  22455. ],
  22456. newObj = {};
  22457. if (obj) {
  22458. for (var i = 0, key, val; (key = attrs[i]); i++) {
  22459. val = obj[key];
  22460. val && (newObj[key] = val);
  22461. }
  22462. }
  22463. return newObj;
  22464. }
  22465. //边框拖动
  22466. function tableBorderDrag(evt) {
  22467. isInResizeBuffer = false;
  22468. startTd = evt.target || evt.srcElement;
  22469. if (!startTd) return;
  22470. var state = getRelation(startTd, mouseCoords(evt));
  22471. if (/\d/.test(state)) {
  22472. state = state.replace(/\d/, "");
  22473. startTd = getUETable(startTd).getPreviewCell(startTd, state == "v");
  22474. }
  22475. hideDragLine(me);
  22476. getDragLine(me, me.document);
  22477. me.fireEvent("saveScene");
  22478. showDragLineAt(state, startTd);
  22479. mousedown = true;
  22480. //拖动开始
  22481. onDrag = state;
  22482. dragTd = startTd;
  22483. }
  22484. function mouseUpEvent(type, evt) {
  22485. if (isEditorDisabled()) {
  22486. return;
  22487. }
  22488. clearTableDragTimer();
  22489. isInResizeBuffer = false;
  22490. if (onBorder) {
  22491. singleClickState = ++singleClickState % 3;
  22492. userActionStatus = {
  22493. x: evt.clientX,
  22494. y: evt.clientY
  22495. };
  22496. tableResizeTimer = setTimeout(function() {
  22497. singleClickState > 0 && singleClickState--;
  22498. }, dblclickTime);
  22499. if (singleClickState === 2) {
  22500. singleClickState = 0;
  22501. tableDbclickHandler(evt);
  22502. return;
  22503. }
  22504. }
  22505. if (evt.button == 2) return;
  22506. var me = this;
  22507. //清除表格上原生跨选问题
  22508. var range = me.selection.getRange(),
  22509. start = domUtils.findParentByTagName(range.startContainer, "table", true),
  22510. end = domUtils.findParentByTagName(range.endContainer, "table", true);
  22511. if (start || end) {
  22512. if (start === end) {
  22513. start = domUtils.findParentByTagName(
  22514. range.startContainer,
  22515. ["td", "th", "caption"],
  22516. true
  22517. );
  22518. end = domUtils.findParentByTagName(
  22519. range.endContainer,
  22520. ["td", "th", "caption"],
  22521. true
  22522. );
  22523. if (start !== end) {
  22524. me.selection.clearRange();
  22525. }
  22526. } else {
  22527. me.selection.clearRange();
  22528. }
  22529. }
  22530. mousedown = false;
  22531. me.document.body.style.webkitUserSelect = "";
  22532. //拖拽状态下的mouseUP
  22533. if (onDrag && dragTd) {
  22534. me.selection.getNative()[
  22535. browser.ie9below ? "empty" : "removeAllRanges"
  22536. ]();
  22537. singleClickState = 0;
  22538. dragLine = me.document.getElementById("ue_tableDragLine");
  22539. // trace 3973
  22540. if (dragLine) {
  22541. var dragTdPos = domUtils.getXY(dragTd),
  22542. dragLinePos = domUtils.getXY(dragLine);
  22543. switch (onDrag) {
  22544. case "h":
  22545. changeColWidth(dragTd, dragLinePos.x - dragTdPos.x);
  22546. break;
  22547. case "v":
  22548. changeRowHeight(
  22549. dragTd,
  22550. dragLinePos.y - dragTdPos.y - dragTd.offsetHeight
  22551. );
  22552. break;
  22553. default:
  22554. }
  22555. onDrag = "";
  22556. dragTd = null;
  22557. hideDragLine(me);
  22558. me.fireEvent("saveScene");
  22559. return;
  22560. }
  22561. }
  22562. //正常状态下的mouseup
  22563. if (!startTd) {
  22564. var target = domUtils.findParentByTagName(
  22565. evt.target || evt.srcElement,
  22566. "td",
  22567. true
  22568. );
  22569. if (!target)
  22570. target = domUtils.findParentByTagName(
  22571. evt.target || evt.srcElement,
  22572. "th",
  22573. true
  22574. );
  22575. if (target && (target.tagName == "TD" || target.tagName == "TH")) {
  22576. if (me.fireEvent("excludetable", target) === true) return;
  22577. range = new dom.Range(me.document);
  22578. range.setStart(target, 0).setCursor(false, true);
  22579. }
  22580. } else {
  22581. var ut = getUETable(startTd),
  22582. cell = ut ? ut.selectedTds[0] : null;
  22583. if (cell) {
  22584. range = new dom.Range(me.document);
  22585. if (domUtils.isEmptyBlock(cell)) {
  22586. range.setStart(cell, 0).setCursor(false, true);
  22587. } else {
  22588. range
  22589. .selectNodeContents(cell)
  22590. .shrinkBoundary()
  22591. .setCursor(false, true);
  22592. }
  22593. } else {
  22594. range = me.selection.getRange().shrinkBoundary();
  22595. if (!range.collapsed) {
  22596. var start = domUtils.findParentByTagName(
  22597. range.startContainer,
  22598. ["td", "th"],
  22599. true
  22600. ),
  22601. end = domUtils.findParentByTagName(
  22602. range.endContainer,
  22603. ["td", "th"],
  22604. true
  22605. );
  22606. //在table里边的不能清除
  22607. if (
  22608. (start && !end) ||
  22609. (!start && end) ||
  22610. (start && end && start !== end)
  22611. ) {
  22612. range.setCursor(false, true);
  22613. }
  22614. }
  22615. }
  22616. startTd = null;
  22617. me.removeListener("mouseover", mouseOverEvent);
  22618. }
  22619. me._selectionChange(250, evt);
  22620. }
  22621. function mouseOverEvent(type, evt) {
  22622. if (isEditorDisabled()) {
  22623. return;
  22624. }
  22625. var me = this,
  22626. tar = evt.target || evt.srcElement;
  22627. currentTd =
  22628. domUtils.findParentByTagName(tar, "td", true) ||
  22629. domUtils.findParentByTagName(tar, "th", true);
  22630. //需要判断两个TD是否位于同一个表格内
  22631. if (
  22632. startTd &&
  22633. currentTd &&
  22634. ((startTd.tagName == "TD" && currentTd.tagName == "TD") ||
  22635. (startTd.tagName == "TH" && currentTd.tagName == "TH")) &&
  22636. domUtils.findParentByTagName(startTd, "table") ==
  22637. domUtils.findParentByTagName(currentTd, "table")
  22638. ) {
  22639. var ut = getUETable(currentTd);
  22640. if (startTd != currentTd) {
  22641. me.document.body.style.webkitUserSelect = "none";
  22642. me.selection.getNative()[
  22643. browser.ie9below ? "empty" : "removeAllRanges"
  22644. ]();
  22645. var range = ut.getCellsRange(startTd, currentTd);
  22646. ut.setSelected(range);
  22647. } else {
  22648. me.document.body.style.webkitUserSelect = "";
  22649. ut.clearSelected();
  22650. }
  22651. }
  22652. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  22653. }
  22654. function setCellHeight(cell, height, backHeight) {
  22655. var lineHight = parseInt(
  22656. domUtils.getComputedStyle(cell, "line-height"),
  22657. 10
  22658. ),
  22659. tmpHeight = backHeight + height;
  22660. height = tmpHeight < lineHight ? lineHight : tmpHeight;
  22661. if (cell.style.height) cell.style.height = "";
  22662. cell.rowSpan == 1
  22663. ? cell.setAttribute("height", height)
  22664. : cell.removeAttribute && cell.removeAttribute("height");
  22665. }
  22666. function getWidth(cell) {
  22667. if (!cell) return 0;
  22668. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  22669. }
  22670. function changeColWidth(cell, changeValue) {
  22671. var ut = getUETable(cell);
  22672. if (ut) {
  22673. //根据当前移动的边框获取相关的单元格
  22674. var table = ut.table,
  22675. cells = getCellsByMoveBorder(cell, table);
  22676. table.style.width = "";
  22677. table.removeAttribute("width");
  22678. //修正改变量
  22679. changeValue = correctChangeValue(changeValue, cell, cells);
  22680. if (cell.nextSibling) {
  22681. var i = 0;
  22682. utils.each(cells, function(cellGroup) {
  22683. cellGroup.left.width = +cellGroup.left.width + changeValue;
  22684. cellGroup.right &&
  22685. (cellGroup.right.width = +cellGroup.right.width - changeValue);
  22686. });
  22687. } else {
  22688. utils.each(cells, function(cellGroup) {
  22689. cellGroup.left.width -= -changeValue;
  22690. });
  22691. }
  22692. }
  22693. }
  22694. function isEditorDisabled() {
  22695. return me.body.contentEditable === "false";
  22696. }
  22697. function changeRowHeight(td, changeValue) {
  22698. if (Math.abs(changeValue) < 10) return;
  22699. var ut = getUETable(td);
  22700. if (ut) {
  22701. var cells = ut.getSameEndPosCells(td, "y"),
  22702. //备份需要连带变化的td的原始高度,否则后期无法获取正确的值
  22703. backHeight = cells[0] ? cells[0].offsetHeight : 0;
  22704. for (var i = 0, cell; (cell = cells[i++]); ) {
  22705. setCellHeight(cell, changeValue, backHeight);
  22706. }
  22707. }
  22708. }
  22709. /**
  22710. * 获取调整单元格大小的相关单元格
  22711. * @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
  22712. */
  22713. function getCellsByMoveBorder(cell, table, isContainMergeCell) {
  22714. if (!table) {
  22715. table = domUtils.findParentByTagName(cell, "table");
  22716. }
  22717. if (!table) {
  22718. return null;
  22719. }
  22720. //获取到该单元格所在行的序列号
  22721. var index = domUtils.getNodeIndex(cell),
  22722. temp = cell,
  22723. rows = table.rows,
  22724. colIndex = 0;
  22725. while (temp) {
  22726. //获取到当前单元格在未发生单元格合并时的序列
  22727. if (temp.nodeType === 1) {
  22728. colIndex += temp.colSpan || 1;
  22729. }
  22730. temp = temp.previousSibling;
  22731. }
  22732. temp = null;
  22733. //记录想关的单元格
  22734. var borderCells = [];
  22735. utils.each(rows, function(tabRow) {
  22736. var cells = tabRow.cells,
  22737. currIndex = 0;
  22738. utils.each(cells, function(tabCell) {
  22739. currIndex += tabCell.colSpan || 1;
  22740. if (currIndex === colIndex) {
  22741. borderCells.push({
  22742. left: tabCell,
  22743. right: tabCell.nextSibling || null
  22744. });
  22745. return false;
  22746. } else if (currIndex > colIndex) {
  22747. if (isContainMergeCell) {
  22748. borderCells.push({
  22749. left: tabCell
  22750. });
  22751. }
  22752. return false;
  22753. }
  22754. });
  22755. });
  22756. return borderCells;
  22757. }
  22758. /**
  22759. * 通过给定的单元格集合获取最小的单元格width
  22760. */
  22761. function getMinWidthByTableCells(cells) {
  22762. var minWidth = Number.MAX_VALUE;
  22763. for (var i = 0, curCell; (curCell = cells[i]); i++) {
  22764. minWidth = Math.min(
  22765. minWidth,
  22766. curCell.width || getTableCellWidth(curCell)
  22767. );
  22768. }
  22769. return minWidth;
  22770. }
  22771. function correctChangeValue(changeValue, relatedCell, cells) {
  22772. //为单元格的paading预留空间
  22773. changeValue -= getTabcellSpace();
  22774. if (changeValue < 0) {
  22775. return 0;
  22776. }
  22777. changeValue -= getTableCellWidth(relatedCell);
  22778. //确定方向
  22779. var direction = changeValue < 0 ? "left" : "right";
  22780. changeValue = Math.abs(changeValue);
  22781. //只关心非最后一个单元格就可以
  22782. utils.each(cells, function(cellGroup) {
  22783. var curCell = cellGroup[direction];
  22784. //为单元格保留最小空间
  22785. if (curCell) {
  22786. changeValue = Math.min(
  22787. changeValue,
  22788. getTableCellWidth(curCell) - cellMinWidth
  22789. );
  22790. }
  22791. });
  22792. //修正越界
  22793. changeValue = changeValue < 0 ? 0 : changeValue;
  22794. return direction === "left" ? -changeValue : changeValue;
  22795. }
  22796. function getTableCellWidth(cell) {
  22797. var width = 0,
  22798. //偏移纠正量
  22799. offset = 0,
  22800. width = cell.offsetWidth - getTabcellSpace();
  22801. //最后一个节点纠正一下
  22802. if (!cell.nextSibling) {
  22803. width -= getTableCellOffset(cell);
  22804. }
  22805. width = width < 0 ? 0 : width;
  22806. try {
  22807. cell.width = width;
  22808. } catch (e) {}
  22809. return width;
  22810. }
  22811. /**
  22812. * 获取单元格所在表格的最末单元格的偏移量
  22813. */
  22814. function getTableCellOffset(cell) {
  22815. tab = domUtils.findParentByTagName(cell, "table", false);
  22816. if (tab.offsetVal === undefined) {
  22817. var prev = cell.previousSibling;
  22818. if (prev) {
  22819. //最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
  22820. tab.offsetVal = cell.offsetWidth - prev.offsetWidth === UT.borderWidth
  22821. ? UT.borderWidth
  22822. : 0;
  22823. } else {
  22824. tab.offsetVal = 0;
  22825. }
  22826. }
  22827. return tab.offsetVal;
  22828. }
  22829. function getTabcellSpace() {
  22830. if (UT.tabcellSpace === undefined) {
  22831. var cell = null,
  22832. tab = me.document.createElement("table"),
  22833. tbody = me.document.createElement("tbody"),
  22834. trow = me.document.createElement("tr"),
  22835. tabcell = me.document.createElement("td"),
  22836. mirror = null;
  22837. tabcell.style.cssText = "border: 0;";
  22838. tabcell.width = 1;
  22839. trow.appendChild(tabcell);
  22840. trow.appendChild((mirror = tabcell.cloneNode(false)));
  22841. tbody.appendChild(trow);
  22842. tab.appendChild(tbody);
  22843. tab.style.cssText = "visibility: hidden;";
  22844. me.body.appendChild(tab);
  22845. UT.paddingSpace = tabcell.offsetWidth - 1;
  22846. var tmpTabWidth = tab.offsetWidth;
  22847. tabcell.style.cssText = "";
  22848. mirror.style.cssText = "";
  22849. UT.borderWidth = (tab.offsetWidth - tmpTabWidth) / 3;
  22850. UT.tabcellSpace = UT.paddingSpace + UT.borderWidth;
  22851. me.body.removeChild(tab);
  22852. }
  22853. getTabcellSpace = function() {
  22854. return UT.tabcellSpace;
  22855. };
  22856. return UT.tabcellSpace;
  22857. }
  22858. function getDragLine(editor, doc) {
  22859. if (mousedown) return;
  22860. dragLine = editor.document.createElement("div");
  22861. domUtils.setAttributes(dragLine, {
  22862. id: "ue_tableDragLine",
  22863. unselectable: "on",
  22864. contenteditable: false,
  22865. onresizestart: "return false",
  22866. ondragstart: "return false",
  22867. onselectstart: "return false",
  22868. style:
  22869. "background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)"
  22870. });
  22871. editor.body.appendChild(dragLine);
  22872. }
  22873. function hideDragLine(editor) {
  22874. if (mousedown) return;
  22875. var line;
  22876. while ((line = editor.document.getElementById("ue_tableDragLine"))) {
  22877. domUtils.remove(line);
  22878. }
  22879. }
  22880. /**
  22881. * 依据state(v|h)在cell位置显示横线
  22882. * @param state
  22883. * @param cell
  22884. */
  22885. function showDragLineAt(state, cell) {
  22886. if (!cell) return;
  22887. var table = domUtils.findParentByTagName(cell, "table"),
  22888. caption = table.getElementsByTagName("caption"),
  22889. width = table.offsetWidth,
  22890. height =
  22891. table.offsetHeight - (caption.length > 0 ? caption[0].offsetHeight : 0),
  22892. tablePos = domUtils.getXY(table),
  22893. cellPos = domUtils.getXY(cell),
  22894. css;
  22895. switch (state) {
  22896. case "h":
  22897. css =
  22898. "height:" +
  22899. height +
  22900. "px;top:" +
  22901. (tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) +
  22902. "px;left:" +
  22903. (cellPos.x + cell.offsetWidth);
  22904. dragLine.style.cssText =
  22905. css +
  22906. "px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)";
  22907. break;
  22908. case "v":
  22909. css =
  22910. "width:" +
  22911. width +
  22912. "px;left:" +
  22913. tablePos.x +
  22914. "px;top:" +
  22915. (cellPos.y + cell.offsetHeight);
  22916. //必须加上border:0和color:blue,否则低版ie不支持背景色显示
  22917. dragLine.style.cssText =
  22918. css +
  22919. "px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)";
  22920. break;
  22921. default:
  22922. }
  22923. }
  22924. /**
  22925. * 当表格边框颜色为白色时设置为虚线,true为添加虚线
  22926. * @param editor
  22927. * @param flag
  22928. */
  22929. function switchBorderColor(editor, flag) {
  22930. var tableArr = domUtils.getElementsByTagName(editor.body, "table"),
  22931. color;
  22932. for (var i = 0, node; (node = tableArr[i++]); ) {
  22933. var td = domUtils.getElementsByTagName(node, "td");
  22934. if (td[0]) {
  22935. if (flag) {
  22936. color = td[0].style.borderColor.replace(/\s/g, "");
  22937. if (/(#ffffff)|(rgb\(255,255,255\))/gi.test(color))
  22938. domUtils.addClass(node, "noBorderTable");
  22939. } else {
  22940. domUtils.removeClasses(node, "noBorderTable");
  22941. }
  22942. }
  22943. }
  22944. }
  22945. function getTableWidth(editor, needIEHack, defaultValue) {
  22946. var body = editor.body;
  22947. return (
  22948. body.offsetWidth -
  22949. (needIEHack
  22950. ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
  22951. : 0) -
  22952. defaultValue.tableBorder * 2 -
  22953. (editor.options.offsetWidth || 0)
  22954. );
  22955. }
  22956. /**
  22957. * 获取当前拖动的单元格
  22958. */
  22959. function getTargetTd(editor, evt) {
  22960. var target = domUtils.findParentByTagName(
  22961. evt.target || evt.srcElement,
  22962. ["td", "th"],
  22963. true
  22964. ),
  22965. dir = null;
  22966. if (!target) {
  22967. return null;
  22968. }
  22969. dir = getRelation(target, mouseCoords(evt));
  22970. //如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td
  22971. if (!target) {
  22972. return null;
  22973. }
  22974. if (dir === "h1" && target.previousSibling) {
  22975. var position = domUtils.getXY(target),
  22976. cellWidth = target.offsetWidth;
  22977. if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
  22978. target = target.previousSibling;
  22979. }
  22980. } else if (dir === "v1" && target.parentNode.previousSibling) {
  22981. var position = domUtils.getXY(target),
  22982. cellHeight = target.offsetHeight;
  22983. if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
  22984. target = target.parentNode.previousSibling.firstChild;
  22985. }
  22986. }
  22987. //排除了非td内部以及用于代码高亮部分的td
  22988. return target && !(editor.fireEvent("excludetable", target) === true)
  22989. ? target
  22990. : null;
  22991. }
  22992. };
  22993. // plugins/table.sort.js
  22994. /**
  22995. * Created with JetBrains PhpStorm.
  22996. * User: Jinqn
  22997. * Date: 13-10-12
  22998. * Time: 上午10:20
  22999. * To change this template use File | Settings | File Templates.
  23000. */
  23001. UE.UETable.prototype.sortTable = function(sortByCellIndex, compareFn) {
  23002. var table = this.table,
  23003. rows = table.rows,
  23004. trArray = [],
  23005. flag = rows[0].cells[0].tagName === "TH",
  23006. lastRowIndex = 0;
  23007. if (this.selectedTds.length) {
  23008. var range = this.cellsRange,
  23009. len = range.endRowIndex + 1;
  23010. for (var i = range.beginRowIndex; i < len; i++) {
  23011. trArray[i] = rows[i];
  23012. }
  23013. trArray.splice(0, range.beginRowIndex);
  23014. lastRowIndex = range.endRowIndex + 1 === this.rowsNum
  23015. ? 0
  23016. : range.endRowIndex + 1;
  23017. } else {
  23018. for (var i = 0, len = rows.length; i < len; i++) {
  23019. trArray[i] = rows[i];
  23020. }
  23021. }
  23022. var Fn = {
  23023. reversecurrent: function(td1, td2) {
  23024. return 1;
  23025. },
  23026. orderbyasc: function(td1, td2) {
  23027. var value1 = td1.innerText || td1.textContent,
  23028. value2 = td2.innerText || td2.textContent;
  23029. return value1.localeCompare(value2);
  23030. },
  23031. reversebyasc: function(td1, td2) {
  23032. var value1 = td1.innerHTML,
  23033. value2 = td2.innerHTML;
  23034. return value2.localeCompare(value1);
  23035. },
  23036. orderbynum: function(td1, td2) {
  23037. var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
  23038. value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
  23039. if (value1) value1 = +value1[0];
  23040. if (value2) value2 = +value2[0];
  23041. return (value1 || 0) - (value2 || 0);
  23042. },
  23043. reversebynum: function(td1, td2) {
  23044. var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
  23045. value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
  23046. if (value1) value1 = +value1[0];
  23047. if (value2) value2 = +value2[0];
  23048. return (value2 || 0) - (value1 || 0);
  23049. }
  23050. };
  23051. //对表格设置排序的标记data-sort-type
  23052. table.setAttribute(
  23053. "data-sort-type",
  23054. compareFn && typeof compareFn === "string" && Fn[compareFn] ? compareFn : ""
  23055. );
  23056. //th不参与排序
  23057. flag && trArray.splice(0, 1);
  23058. trArray = utils.sort(trArray, function(tr1, tr2) {
  23059. var result;
  23060. if (compareFn && typeof compareFn === "function") {
  23061. result = compareFn.call(
  23062. this,
  23063. tr1.cells[sortByCellIndex],
  23064. tr2.cells[sortByCellIndex]
  23065. );
  23066. } else if (compareFn && typeof compareFn === "number") {
  23067. result = 1;
  23068. } else if (compareFn && typeof compareFn === "string" && Fn[compareFn]) {
  23069. result = Fn[compareFn].call(
  23070. this,
  23071. tr1.cells[sortByCellIndex],
  23072. tr2.cells[sortByCellIndex]
  23073. );
  23074. } else {
  23075. result = Fn["orderbyasc"].call(
  23076. this,
  23077. tr1.cells[sortByCellIndex],
  23078. tr2.cells[sortByCellIndex]
  23079. );
  23080. }
  23081. return result;
  23082. });
  23083. var fragment = table.ownerDocument.createDocumentFragment();
  23084. for (var j = 0, len = trArray.length; j < len; j++) {
  23085. fragment.appendChild(trArray[j]);
  23086. }
  23087. var tbody = table.getElementsByTagName("tbody")[0];
  23088. if (!lastRowIndex) {
  23089. tbody.appendChild(fragment);
  23090. } else {
  23091. tbody.insertBefore(
  23092. fragment,
  23093. rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1]
  23094. );
  23095. }
  23096. };
  23097. UE.plugins["tablesort"] = function() {
  23098. var me = this,
  23099. UT = UE.UETable,
  23100. getUETable = function(tdOrTable) {
  23101. return UT.getUETable(tdOrTable);
  23102. },
  23103. getTableItemsByRange = function(editor) {
  23104. return UT.getTableItemsByRange(editor);
  23105. };
  23106. me.ready(function() {
  23107. //添加表格可排序的样式
  23108. utils.cssRule(
  23109. "tablesort",
  23110. "table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;" +
  23111. " background-image:url(" +
  23112. me.options.themePath +
  23113. me.options.theme +
  23114. "/images/sortable.png);}",
  23115. me.document
  23116. );
  23117. //做单元格合并操作时,清除可排序标识
  23118. me.addListener("afterexeccommand", function(type, cmd) {
  23119. if (cmd == "mergeright" || cmd == "mergedown" || cmd == "mergecells") {
  23120. this.execCommand("disablesort");
  23121. }
  23122. });
  23123. });
  23124. //表格排序
  23125. UE.commands["sorttable"] = {
  23126. queryCommandState: function() {
  23127. var me = this,
  23128. tableItems = getTableItemsByRange(me);
  23129. if (!tableItems.cell) return -1;
  23130. var table = tableItems.table,
  23131. cells = table.getElementsByTagName("td");
  23132. for (var i = 0, cell; (cell = cells[i++]); ) {
  23133. if (cell.rowSpan != 1 || cell.colSpan != 1) return -1;
  23134. }
  23135. return 0;
  23136. },
  23137. execCommand: function(cmd, fn) {
  23138. var me = this,
  23139. range = me.selection.getRange(),
  23140. bk = range.createBookmark(true),
  23141. tableItems = getTableItemsByRange(me),
  23142. cell = tableItems.cell,
  23143. ut = getUETable(tableItems.table),
  23144. cellInfo = ut.getCellInfo(cell);
  23145. ut.sortTable(cellInfo.cellIndex, fn);
  23146. range.moveToBookmark(bk);
  23147. try {
  23148. range.select();
  23149. } catch (e) {}
  23150. }
  23151. };
  23152. //设置表格可排序,清除表格可排序
  23153. UE.commands["enablesort"] = UE.commands["disablesort"] = {
  23154. queryCommandState: function(cmd) {
  23155. var table = getTableItemsByRange(this).table;
  23156. if (table && cmd == "enablesort") {
  23157. var cells = domUtils.getElementsByTagName(table, "th td");
  23158. for (var i = 0; i < cells.length; i++) {
  23159. if (
  23160. cells[i].getAttribute("colspan") > 1 ||
  23161. cells[i].getAttribute("rowspan") > 1
  23162. )
  23163. return -1;
  23164. }
  23165. }
  23166. return !table
  23167. ? -1
  23168. : (cmd == "enablesort") ^
  23169. (table.getAttribute("data-sort") != "sortEnabled")
  23170. ? -1
  23171. : 0;
  23172. },
  23173. execCommand: function(cmd) {
  23174. var table = getTableItemsByRange(this).table;
  23175. table.setAttribute(
  23176. "data-sort",
  23177. cmd == "enablesort" ? "sortEnabled" : "sortDisabled"
  23178. );
  23179. cmd == "enablesort"
  23180. ? domUtils.addClass(table, "sortEnabled")
  23181. : domUtils.removeClasses(table, "sortEnabled");
  23182. }
  23183. };
  23184. };
  23185. // plugins/contextmenu.js
  23186. ///import core
  23187. ///commands 右键菜单
  23188. ///commandsName ContextMenu
  23189. ///commandsTitle 右键菜单
  23190. /**
  23191. * 右键菜单
  23192. * @function
  23193. * @name baidu.editor.plugins.contextmenu
  23194. * @author zhanyi
  23195. */
  23196. UE.plugins["contextmenu"] = function() {
  23197. var me = this;
  23198. me.setOpt("enableContextMenu", me.getOpt("enableContextMenu") || true);
  23199. if (me.getOpt("enableContextMenu") === false) {
  23200. return;
  23201. }
  23202. var lang = me.getLang("contextMenu"),
  23203. menu,
  23204. items = me.options.contextMenu || [
  23205. { label: lang["selectall"], cmdName: "selectall" },
  23206. {
  23207. label: lang.cleardoc,
  23208. cmdName: "cleardoc",
  23209. exec: function() {
  23210. if (confirm(lang.confirmclear)) {
  23211. this.execCommand("cleardoc");
  23212. }
  23213. }
  23214. },
  23215. "-",
  23216. {
  23217. label: lang.unlink,
  23218. cmdName: "unlink"
  23219. },
  23220. "-",
  23221. {
  23222. group: lang.paragraph,
  23223. icon: "justifyjustify",
  23224. subMenu: [
  23225. {
  23226. label: lang.justifyleft,
  23227. cmdName: "justify",
  23228. value: "left"
  23229. },
  23230. {
  23231. label: lang.justifyright,
  23232. cmdName: "justify",
  23233. value: "right"
  23234. },
  23235. {
  23236. label: lang.justifycenter,
  23237. cmdName: "justify",
  23238. value: "center"
  23239. },
  23240. {
  23241. label: lang.justifyjustify,
  23242. cmdName: "justify",
  23243. value: "justify"
  23244. }
  23245. ]
  23246. },
  23247. "-",
  23248. {
  23249. group: lang.table,
  23250. icon: "table",
  23251. subMenu: [
  23252. {
  23253. label: lang.inserttable,
  23254. cmdName: "inserttable"
  23255. },
  23256. {
  23257. label: lang.deletetable,
  23258. cmdName: "deletetable"
  23259. },
  23260. "-",
  23261. {
  23262. label: lang.deleterow,
  23263. cmdName: "deleterow"
  23264. },
  23265. {
  23266. label: lang.deletecol,
  23267. cmdName: "deletecol"
  23268. },
  23269. {
  23270. label: lang.insertcol,
  23271. cmdName: "insertcol"
  23272. },
  23273. {
  23274. label: lang.insertcolnext,
  23275. cmdName: "insertcolnext"
  23276. },
  23277. {
  23278. label: lang.insertrow,
  23279. cmdName: "insertrow"
  23280. },
  23281. {
  23282. label: lang.insertrownext,
  23283. cmdName: "insertrownext"
  23284. },
  23285. "-",
  23286. {
  23287. label: lang.insertcaption,
  23288. cmdName: "insertcaption"
  23289. },
  23290. {
  23291. label: lang.deletecaption,
  23292. cmdName: "deletecaption"
  23293. },
  23294. {
  23295. label: lang.inserttitle,
  23296. cmdName: "inserttitle"
  23297. },
  23298. {
  23299. label: lang.deletetitle,
  23300. cmdName: "deletetitle"
  23301. },
  23302. {
  23303. label: lang.inserttitlecol,
  23304. cmdName: "inserttitlecol"
  23305. },
  23306. {
  23307. label: lang.deletetitlecol,
  23308. cmdName: "deletetitlecol"
  23309. },
  23310. "-",
  23311. {
  23312. label: lang.mergecells,
  23313. cmdName: "mergecells"
  23314. },
  23315. {
  23316. label: lang.mergeright,
  23317. cmdName: "mergeright"
  23318. },
  23319. {
  23320. label: lang.mergedown,
  23321. cmdName: "mergedown"
  23322. },
  23323. "-",
  23324. {
  23325. label: lang.splittorows,
  23326. cmdName: "splittorows"
  23327. },
  23328. {
  23329. label: lang.splittocols,
  23330. cmdName: "splittocols"
  23331. },
  23332. {
  23333. label: lang.splittocells,
  23334. cmdName: "splittocells"
  23335. },
  23336. "-",
  23337. {
  23338. label: lang.averageDiseRow,
  23339. cmdName: "averagedistributerow"
  23340. },
  23341. {
  23342. label: lang.averageDisCol,
  23343. cmdName: "averagedistributecol"
  23344. },
  23345. "-",
  23346. {
  23347. label: lang.edittd,
  23348. cmdName: "edittd",
  23349. exec: function() {
  23350. if (UE.ui["edittd"]) {
  23351. new UE.ui["edittd"](this);
  23352. }
  23353. this.getDialog("edittd").open();
  23354. }
  23355. },
  23356. {
  23357. label: lang.edittable,
  23358. cmdName: "edittable",
  23359. exec: function() {
  23360. if (UE.ui["edittable"]) {
  23361. new UE.ui["edittable"](this);
  23362. }
  23363. this.getDialog("edittable").open();
  23364. }
  23365. },
  23366. {
  23367. label: lang.setbordervisible,
  23368. cmdName: "setbordervisible"
  23369. }
  23370. ]
  23371. },
  23372. {
  23373. group: lang.tablesort,
  23374. icon: "tablesort",
  23375. subMenu: [
  23376. {
  23377. label: lang.enablesort,
  23378. cmdName: "enablesort"
  23379. },
  23380. {
  23381. label: lang.disablesort,
  23382. cmdName: "disablesort"
  23383. },
  23384. "-",
  23385. {
  23386. label: lang.reversecurrent,
  23387. cmdName: "sorttable",
  23388. value: "reversecurrent"
  23389. },
  23390. {
  23391. label: lang.orderbyasc,
  23392. cmdName: "sorttable",
  23393. value: "orderbyasc"
  23394. },
  23395. {
  23396. label: lang.reversebyasc,
  23397. cmdName: "sorttable",
  23398. value: "reversebyasc"
  23399. },
  23400. {
  23401. label: lang.orderbynum,
  23402. cmdName: "sorttable",
  23403. value: "orderbynum"
  23404. },
  23405. {
  23406. label: lang.reversebynum,
  23407. cmdName: "sorttable",
  23408. value: "reversebynum"
  23409. }
  23410. ]
  23411. },
  23412. {
  23413. group: lang.borderbk,
  23414. icon: "borderBack",
  23415. subMenu: [
  23416. {
  23417. label: lang.setcolor,
  23418. cmdName: "interlacetable",
  23419. exec: function() {
  23420. this.execCommand("interlacetable");
  23421. }
  23422. },
  23423. {
  23424. label: lang.unsetcolor,
  23425. cmdName: "uninterlacetable",
  23426. exec: function() {
  23427. this.execCommand("uninterlacetable");
  23428. }
  23429. },
  23430. {
  23431. label: lang.setbackground,
  23432. cmdName: "settablebackground",
  23433. exec: function() {
  23434. this.execCommand("settablebackground", {
  23435. repeat: true,
  23436. colorList: ["#bbb", "#ccc"]
  23437. });
  23438. }
  23439. },
  23440. {
  23441. label: lang.unsetbackground,
  23442. cmdName: "cleartablebackground",
  23443. exec: function() {
  23444. this.execCommand("cleartablebackground");
  23445. }
  23446. },
  23447. {
  23448. label: lang.redandblue,
  23449. cmdName: "settablebackground",
  23450. exec: function() {
  23451. this.execCommand("settablebackground", {
  23452. repeat: true,
  23453. colorList: ["red", "blue"]
  23454. });
  23455. }
  23456. },
  23457. {
  23458. label: lang.threecolorgradient,
  23459. cmdName: "settablebackground",
  23460. exec: function() {
  23461. this.execCommand("settablebackground", {
  23462. repeat: true,
  23463. colorList: ["#aaa", "#bbb", "#ccc"]
  23464. });
  23465. }
  23466. }
  23467. ]
  23468. },
  23469. {
  23470. group: lang.aligntd,
  23471. icon: "aligntd",
  23472. subMenu: [
  23473. {
  23474. cmdName: "cellalignment",
  23475. value: { align: "left", vAlign: "top" }
  23476. },
  23477. {
  23478. cmdName: "cellalignment",
  23479. value: { align: "center", vAlign: "top" }
  23480. },
  23481. {
  23482. cmdName: "cellalignment",
  23483. value: { align: "right", vAlign: "top" }
  23484. },
  23485. {
  23486. cmdName: "cellalignment",
  23487. value: { align: "left", vAlign: "middle" }
  23488. },
  23489. {
  23490. cmdName: "cellalignment",
  23491. value: { align: "center", vAlign: "middle" }
  23492. },
  23493. {
  23494. cmdName: "cellalignment",
  23495. value: { align: "right", vAlign: "middle" }
  23496. },
  23497. {
  23498. cmdName: "cellalignment",
  23499. value: { align: "left", vAlign: "bottom" }
  23500. },
  23501. {
  23502. cmdName: "cellalignment",
  23503. value: { align: "center", vAlign: "bottom" }
  23504. },
  23505. {
  23506. cmdName: "cellalignment",
  23507. value: { align: "right", vAlign: "bottom" }
  23508. }
  23509. ]
  23510. },
  23511. {
  23512. group: lang.aligntable,
  23513. icon: "aligntable",
  23514. subMenu: [
  23515. {
  23516. cmdName: "tablealignment",
  23517. className: "left",
  23518. label: lang.tableleft,
  23519. value: "left"
  23520. },
  23521. {
  23522. cmdName: "tablealignment",
  23523. className: "center",
  23524. label: lang.tablecenter,
  23525. value: "center"
  23526. },
  23527. {
  23528. cmdName: "tablealignment",
  23529. className: "right",
  23530. label: lang.tableright,
  23531. value: "right"
  23532. }
  23533. ]
  23534. },
  23535. "-",
  23536. {
  23537. label: lang.insertparagraphbefore,
  23538. cmdName: "insertparagraph",
  23539. value: true
  23540. },
  23541. {
  23542. label: lang.insertparagraphafter,
  23543. cmdName: "insertparagraph"
  23544. },
  23545. {
  23546. label: lang["copy"],
  23547. cmdName: "copy"
  23548. },
  23549. {
  23550. label: lang["paste"],
  23551. cmdName: "paste"
  23552. }
  23553. ];
  23554. if (!items.length) {
  23555. return;
  23556. }
  23557. var uiUtils = UE.ui.uiUtils;
  23558. me.addListener("contextmenu", function(type, evt) {
  23559. var offset = uiUtils.getViewportOffsetByEvent(evt);
  23560. me.fireEvent("beforeselectionchange");
  23561. if (menu) {
  23562. menu.destroy();
  23563. }
  23564. for (var i = 0, ti, contextItems = []; (ti = items[i]); i++) {
  23565. var last;
  23566. (function(item) {
  23567. if (item == "-") {
  23568. if ((last = contextItems[contextItems.length - 1]) && last !== "-") {
  23569. contextItems.push("-");
  23570. }
  23571. } else if (item.hasOwnProperty("group")) {
  23572. for (var j = 0, cj, subMenu = []; (cj = item.subMenu[j]); j++) {
  23573. (function(subItem) {
  23574. if (subItem == "-") {
  23575. if ((last = subMenu[subMenu.length - 1]) && last !== "-") {
  23576. subMenu.push("-");
  23577. } else {
  23578. subMenu.splice(subMenu.length - 1);
  23579. }
  23580. } else {
  23581. if (
  23582. (me.commands[subItem.cmdName] ||
  23583. UE.commands[subItem.cmdName] ||
  23584. subItem.query) &&
  23585. (subItem.query
  23586. ? subItem.query()
  23587. : me.queryCommandState(subItem.cmdName)) > -1
  23588. ) {
  23589. subMenu.push({
  23590. label:
  23591. subItem.label ||
  23592. me.getLang(
  23593. "contextMenu." +
  23594. subItem.cmdName +
  23595. (subItem.value || "")
  23596. ) ||
  23597. "",
  23598. className:
  23599. "edui-for-" +
  23600. subItem.cmdName +
  23601. (subItem.className
  23602. ? " edui-for-" +
  23603. subItem.cmdName +
  23604. "-" +
  23605. subItem.className
  23606. : ""),
  23607. onclick: subItem.exec
  23608. ? function() {
  23609. subItem.exec.call(me);
  23610. }
  23611. : function() {
  23612. me.execCommand(subItem.cmdName, subItem.value);
  23613. }
  23614. });
  23615. }
  23616. }
  23617. })(cj);
  23618. }
  23619. if (subMenu.length) {
  23620. function getLabel() {
  23621. switch (item.icon) {
  23622. case "table":
  23623. return me.getLang("contextMenu.table");
  23624. case "justifyjustify":
  23625. return me.getLang("contextMenu.paragraph");
  23626. case "aligntd":
  23627. return me.getLang("contextMenu.aligntd");
  23628. case "aligntable":
  23629. return me.getLang("contextMenu.aligntable");
  23630. case "tablesort":
  23631. return lang.tablesort;
  23632. case "borderBack":
  23633. return lang.borderbk;
  23634. default:
  23635. return "";
  23636. }
  23637. }
  23638. contextItems.push({
  23639. //todo 修正成自动获取方式
  23640. label: getLabel(),
  23641. className: "edui-for-" + item.icon,
  23642. subMenu: {
  23643. items: subMenu,
  23644. editor: me
  23645. }
  23646. });
  23647. }
  23648. } else {
  23649. //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
  23650. if (
  23651. (me.commands[item.cmdName] ||
  23652. UE.commands[item.cmdName] ||
  23653. item.query) &&
  23654. (item.query
  23655. ? item.query.call(me)
  23656. : me.queryCommandState(item.cmdName)) > -1
  23657. ) {
  23658. contextItems.push({
  23659. label: item.label || me.getLang("contextMenu." + item.cmdName),
  23660. className:
  23661. "edui-for-" +
  23662. (item.icon ? item.icon : item.cmdName + (item.value || "")),
  23663. onclick: item.exec
  23664. ? function() {
  23665. item.exec.call(me);
  23666. }
  23667. : function() {
  23668. me.execCommand(item.cmdName, item.value);
  23669. }
  23670. });
  23671. }
  23672. }
  23673. })(ti);
  23674. }
  23675. if (contextItems[contextItems.length - 1] == "-") {
  23676. contextItems.pop();
  23677. }
  23678. menu = new UE.ui.Menu({
  23679. items: contextItems,
  23680. className: "edui-contextmenu",
  23681. editor: me
  23682. });
  23683. menu.render();
  23684. menu.showAt(offset);
  23685. me.fireEvent("aftershowcontextmenu", menu);
  23686. domUtils.preventDefault(evt);
  23687. if (browser.ie) {
  23688. var ieRange;
  23689. try {
  23690. ieRange = me.selection.getNative().createRange();
  23691. } catch (e) {
  23692. return;
  23693. }
  23694. if (ieRange.item) {
  23695. var range = new dom.Range(me.document);
  23696. range.selectNode(ieRange.item(0)).select(true, true);
  23697. }
  23698. }
  23699. });
  23700. // 添加复制的flash按钮
  23701. me.addListener("aftershowcontextmenu", function(type, menu) {
  23702. if (me.zeroclipboard) {
  23703. var items = menu.items;
  23704. for (var key in items) {
  23705. if (items[key].className == "edui-for-copy") {
  23706. me.zeroclipboard.clip(items[key].getDom());
  23707. }
  23708. }
  23709. }
  23710. });
  23711. };
  23712. // plugins/shortcutmenu.js
  23713. ///import core
  23714. ///commands 弹出菜单
  23715. // commandsName popupmenu
  23716. ///commandsTitle 弹出菜单
  23717. /**
  23718. * 弹出菜单
  23719. * @function
  23720. * @name baidu.editor.plugins.popupmenu
  23721. * @author xuheng
  23722. */
  23723. UE.plugins["shortcutmenu"] = function() {
  23724. var me = this,
  23725. menu,
  23726. items = me.options.shortcutMenu || [];
  23727. if (!items.length) {
  23728. return;
  23729. }
  23730. me.addListener("contextmenu mouseup", function(type, e) {
  23731. var me = this,
  23732. customEvt = {
  23733. type: type,
  23734. target: e.target || e.srcElement,
  23735. screenX: e.screenX,
  23736. screenY: e.screenY,
  23737. clientX: e.clientX,
  23738. clientY: e.clientY
  23739. };
  23740. setTimeout(function() {
  23741. var rng = me.selection.getRange();
  23742. if (rng.collapsed === false || type == "contextmenu") {
  23743. if (!menu) {
  23744. menu = new baidu.editor.ui.ShortCutMenu({
  23745. editor: me,
  23746. items: items,
  23747. theme: me.options.theme,
  23748. className: "edui-shortcutmenu"
  23749. });
  23750. menu.render();
  23751. me.fireEvent("afterrendershortcutmenu", menu);
  23752. }
  23753. menu.show(customEvt, !!UE.plugins["contextmenu"]);
  23754. }
  23755. });
  23756. if (type == "contextmenu") {
  23757. domUtils.preventDefault(e);
  23758. if (browser.ie9below) {
  23759. var ieRange;
  23760. try {
  23761. ieRange = me.selection.getNative().createRange();
  23762. } catch (e) {
  23763. return;
  23764. }
  23765. if (ieRange.item) {
  23766. var range = new dom.Range(me.document);
  23767. range.selectNode(ieRange.item(0)).select(true, true);
  23768. }
  23769. }
  23770. }
  23771. });
  23772. me.addListener("keydown", function(type) {
  23773. if (type == "keydown") {
  23774. menu && !menu.isHidden && menu.hide();
  23775. }
  23776. });
  23777. };
  23778. // plugins/basestyle.js
  23779. /**
  23780. * B、I、sub、super命令支持
  23781. * @file
  23782. * @since 1.2.6.1
  23783. */
  23784. UE.plugins["basestyle"] = function() {
  23785. /**
  23786. * 字体加粗
  23787. * @command bold
  23788. * @param { String } cmd 命令字符串
  23789. * @remind 对已加粗的文本内容执行该命令, 将取消加粗
  23790. * @method execCommand
  23791. * @example
  23792. * ```javascript
  23793. * //editor是编辑器实例
  23794. * //对当前选中的文本内容执行加粗操作
  23795. * //第一次执行, 文本内容加粗
  23796. * editor.execCommand( 'bold' );
  23797. *
  23798. * //第二次执行, 文本内容取消加粗
  23799. * editor.execCommand( 'bold' );
  23800. * ```
  23801. */
  23802. /**
  23803. * 字体倾斜
  23804. * @command italic
  23805. * @method execCommand
  23806. * @param { String } cmd 命令字符串
  23807. * @remind 对已倾斜的文本内容执行该命令, 将取消倾斜
  23808. * @example
  23809. * ```javascript
  23810. * //editor是编辑器实例
  23811. * //对当前选中的文本内容执行斜体操作
  23812. * //第一次操作, 文本内容将变成斜体
  23813. * editor.execCommand( 'italic' );
  23814. *
  23815. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23816. * editor.execCommand( 'italic' );
  23817. * ```
  23818. */
  23819. /**
  23820. * 下标文本,与“superscript”命令互斥
  23821. * @command subscript
  23822. * @method execCommand
  23823. * @remind 把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本
  23824. * @param { String } cmd 命令字符串
  23825. * @example
  23826. * ```javascript
  23827. * //editor是编辑器实例
  23828. * //对当前选中的文本内容执行下标操作
  23829. * //第一次操作, 文本内容将变成下标文本
  23830. * editor.execCommand( 'subscript' );
  23831. *
  23832. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23833. * editor.execCommand( 'subscript' );
  23834. * ```
  23835. */
  23836. /**
  23837. * 上标文本,与“subscript”命令互斥
  23838. * @command superscript
  23839. * @method execCommand
  23840. * @remind 把选中的文本内容切换成上标文本, 如果当前选中的文本已经是上标, 则该操作会把文本内容还原成正常文本
  23841. * @param { String } cmd 命令字符串
  23842. * @example
  23843. * ```javascript
  23844. * //editor是编辑器实例
  23845. * //对当前选中的文本内容执行上标操作
  23846. * //第一次操作, 文本内容将变成上标文本
  23847. * editor.execCommand( 'superscript' );
  23848. *
  23849. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23850. * editor.execCommand( 'superscript' );
  23851. * ```
  23852. */
  23853. var basestyles = {
  23854. bold: ["strong", "b"],
  23855. italic: ["em", "i"],
  23856. subscript: ["sub"],
  23857. superscript: ["sup"]
  23858. },
  23859. getObj = function(editor, tagNames) {
  23860. return domUtils.filterNodeList(
  23861. editor.selection.getStartElementPath(),
  23862. tagNames
  23863. );
  23864. },
  23865. me = this;
  23866. //添加快捷键
  23867. me.addshortcutkey({
  23868. Bold: "ctrl+66", //^B
  23869. Italic: "ctrl+73", //^I
  23870. Underline: "ctrl+85" //^U
  23871. });
  23872. me.addInputRule(function(root) {
  23873. utils.each(root.getNodesByTagName("b i"), function(node) {
  23874. switch (node.tagName) {
  23875. case "b":
  23876. node.tagName = "strong";
  23877. break;
  23878. case "i":
  23879. node.tagName = "em";
  23880. }
  23881. });
  23882. });
  23883. for (var style in basestyles) {
  23884. (function(cmd, tagNames) {
  23885. me.commands[cmd] = {
  23886. execCommand: function(cmdName) {
  23887. var range = me.selection.getRange(),
  23888. obj = getObj(this, tagNames);
  23889. if (range.collapsed) {
  23890. if (obj) {
  23891. var tmpText = me.document.createTextNode("");
  23892. range.insertNode(tmpText).removeInlineStyle(tagNames);
  23893. range.setStartBefore(tmpText);
  23894. domUtils.remove(tmpText);
  23895. } else {
  23896. var tmpNode = range.document.createElement(tagNames[0]);
  23897. if (cmdName == "superscript" || cmdName == "subscript") {
  23898. tmpText = me.document.createTextNode("");
  23899. range
  23900. .insertNode(tmpText)
  23901. .removeInlineStyle(["sub", "sup"])
  23902. .setStartBefore(tmpText)
  23903. .collapse(true);
  23904. }
  23905. range.insertNode(tmpNode).setStart(tmpNode, 0);
  23906. }
  23907. range.collapse(true);
  23908. } else {
  23909. if (cmdName == "superscript" || cmdName == "subscript") {
  23910. if (!obj || obj.tagName.toLowerCase() != cmdName) {
  23911. range.removeInlineStyle(["sub", "sup"]);
  23912. }
  23913. }
  23914. obj
  23915. ? range.removeInlineStyle(tagNames)
  23916. : range.applyInlineStyle(tagNames[0]);
  23917. }
  23918. range.select();
  23919. },
  23920. queryCommandState: function() {
  23921. return getObj(this, tagNames) ? 1 : 0;
  23922. }
  23923. };
  23924. })(style, basestyles[style]);
  23925. }
  23926. };
  23927. // plugins/elementpath.js
  23928. /**
  23929. * 选取路径命令
  23930. * @file
  23931. */
  23932. UE.plugins["elementpath"] = function() {
  23933. var currentLevel,
  23934. tagNames,
  23935. me = this;
  23936. me.setOpt("elementPathEnabled", true);
  23937. if (!me.options.elementPathEnabled) {
  23938. return;
  23939. }
  23940. me.commands["elementpath"] = {
  23941. execCommand: function(cmdName, level) {
  23942. var start = tagNames[level],
  23943. range = me.selection.getRange();
  23944. currentLevel = level * 1;
  23945. range.selectNode(start).select();
  23946. },
  23947. queryCommandValue: function() {
  23948. //产生一个副本,不能修改原来的startElementPath;
  23949. var parents = [].concat(this.selection.getStartElementPath()).reverse(),
  23950. names = [];
  23951. tagNames = parents;
  23952. for (var i = 0, ci; (ci = parents[i]); i++) {
  23953. if (ci.nodeType == 3) {
  23954. continue;
  23955. }
  23956. var name = ci.tagName.toLowerCase();
  23957. if (name == "img" && ci.getAttribute("anchorname")) {
  23958. name = "anchor";
  23959. }
  23960. names[i] = name;
  23961. if (currentLevel == i) {
  23962. currentLevel = -1;
  23963. break;
  23964. }
  23965. }
  23966. return names;
  23967. }
  23968. };
  23969. };
  23970. // plugins/formatmatch.js
  23971. /**
  23972. * 格式刷,只格式inline的
  23973. * @file
  23974. * @since 1.2.6.1
  23975. */
  23976. /**
  23977. * 格式刷
  23978. * @command formatmatch
  23979. * @method execCommand
  23980. * @remind 该操作不能复制段落格式
  23981. * @param { String } cmd 命令字符串
  23982. * @example
  23983. * ```javascript
  23984. * //editor是编辑器实例
  23985. * //获取格式刷
  23986. * editor.execCommand( 'formatmatch' );
  23987. * ```
  23988. */
  23989. UE.plugins["formatmatch"] = function() {
  23990. var me = this,
  23991. list = [],
  23992. img,
  23993. flag = 0;
  23994. me.addListener("reset", function() {
  23995. list = [];
  23996. flag = 0;
  23997. });
  23998. function addList(type, evt) {
  23999. if (browser.webkit) {
  24000. var target = evt.target.tagName == "IMG" ? evt.target : null;
  24001. }
  24002. function addFormat(range) {
  24003. if (text) {
  24004. range.selectNode(text);
  24005. }
  24006. return range.applyInlineStyle(list[list.length - 1].tagName, null, list);
  24007. }
  24008. me.undoManger && me.undoManger.save();
  24009. var range = me.selection.getRange(),
  24010. imgT = target || range.getClosedNode();
  24011. if (img && imgT && imgT.tagName == "IMG") {
  24012. //trace:964
  24013. imgT.style.cssText +=
  24014. ";float:" +
  24015. (img.style.cssFloat || img.style.styleFloat || "none") +
  24016. ";display:" +
  24017. (img.style.display || "inline");
  24018. img = null;
  24019. } else {
  24020. if (!img) {
  24021. var collapsed = range.collapsed;
  24022. if (collapsed) {
  24023. var text = me.document.createTextNode("match");
  24024. range.insertNode(text).select();
  24025. }
  24026. me.__hasEnterExecCommand = true;
  24027. //不能把block上的属性干掉
  24028. //trace:1553
  24029. var removeFormatAttributes = me.options.removeFormatAttributes;
  24030. me.options.removeFormatAttributes = "";
  24031. me.execCommand("removeformat");
  24032. me.options.removeFormatAttributes = removeFormatAttributes;
  24033. me.__hasEnterExecCommand = false;
  24034. //trace:969
  24035. range = me.selection.getRange();
  24036. if (list.length) {
  24037. addFormat(range);
  24038. }
  24039. if (text) {
  24040. range.setStartBefore(text).collapse(true);
  24041. }
  24042. range.select();
  24043. text && domUtils.remove(text);
  24044. }
  24045. }
  24046. me.undoManger && me.undoManger.save();
  24047. me.removeListener("mouseup", addList);
  24048. flag = 0;
  24049. }
  24050. me.commands["formatmatch"] = {
  24051. execCommand: function(cmdName) {
  24052. if (flag) {
  24053. flag = 0;
  24054. list = [];
  24055. me.removeListener("mouseup", addList);
  24056. return;
  24057. }
  24058. var range = me.selection.getRange();
  24059. img = range.getClosedNode();
  24060. if (!img || img.tagName != "IMG") {
  24061. range.collapse(true).shrinkBoundary();
  24062. var start = range.startContainer;
  24063. list = domUtils.findParents(start, true, function(node) {
  24064. return !domUtils.isBlockElm(node) && node.nodeType == 1;
  24065. });
  24066. //a不能加入格式刷, 并且克隆节点
  24067. for (var i = 0, ci; (ci = list[i]); i++) {
  24068. if (ci.tagName == "A") {
  24069. list.splice(i, 1);
  24070. break;
  24071. }
  24072. }
  24073. }
  24074. me.addListener("mouseup", addList);
  24075. flag = 1;
  24076. },
  24077. queryCommandState: function() {
  24078. return flag;
  24079. },
  24080. notNeedUndo: 1
  24081. };
  24082. };
  24083. // plugins/searchreplace.js
  24084. ///import core
  24085. ///commands 查找替换
  24086. ///commandsName SearchReplace
  24087. ///commandsTitle 查询替换
  24088. ///commandsDialog dialogs\searchreplace
  24089. /**
  24090. * @description 查找替换
  24091. * @author zhanyi
  24092. */
  24093. UE.plugin.register("searchreplace", function() {
  24094. var me = this;
  24095. var _blockElm = { table: 1, tbody: 1, tr: 1, ol: 1, ul: 1 };
  24096. var lastRng = null;
  24097. function getText(node) {
  24098. var text = node.nodeType == 3
  24099. ? node.nodeValue
  24100. : node[browser.ie ? "innerText" : "textContent"];
  24101. return text.replace(domUtils.fillChar, "");
  24102. }
  24103. function findTextInString(textContent, opt, currentIndex) {
  24104. var str = opt.searchStr;
  24105. var reg = new RegExp(str, "g" + (opt.casesensitive ? "" : "i")),
  24106. match;
  24107. if (opt.dir == -1) {
  24108. textContent = textContent.substr(0, currentIndex);
  24109. textContent = textContent.split("").reverse().join("");
  24110. str = str.split("").reverse().join("");
  24111. match = reg.exec(textContent);
  24112. if (match) {
  24113. return currentIndex - match.index - str.length;
  24114. }
  24115. } else {
  24116. textContent = textContent.substr(currentIndex);
  24117. match = reg.exec(textContent);
  24118. if (match) {
  24119. return match.index + currentIndex;
  24120. }
  24121. }
  24122. return -1;
  24123. }
  24124. function findTextBlockElm(node, currentIndex, opt) {
  24125. var textContent,
  24126. index,
  24127. methodName = opt.all || opt.dir == 1 ? "getNextDomNode" : "getPreDomNode";
  24128. if (domUtils.isBody(node)) {
  24129. node = node.firstChild;
  24130. }
  24131. var first = 1;
  24132. while (node) {
  24133. textContent = getText(node);
  24134. index = findTextInString(textContent, opt, currentIndex);
  24135. first = 0;
  24136. if (index != -1) {
  24137. return {
  24138. node: node,
  24139. index: index
  24140. };
  24141. }
  24142. node = domUtils[methodName](node);
  24143. while (node && _blockElm[node.nodeName.toLowerCase()]) {
  24144. node = domUtils[methodName](node, true);
  24145. }
  24146. if (node) {
  24147. currentIndex = opt.dir == -1 ? getText(node).length : 0;
  24148. }
  24149. }
  24150. }
  24151. function findNTextInBlockElm(node, index, str) {
  24152. var currentIndex = 0,
  24153. currentNode = node.firstChild,
  24154. currentNodeLength = 0,
  24155. result;
  24156. while (currentNode) {
  24157. if (currentNode.nodeType == 3) {
  24158. currentNodeLength = getText(currentNode).replace(
  24159. /(^[\t\r\n]+)|([\t\r\n]+$)/,
  24160. ""
  24161. ).length;
  24162. currentIndex += currentNodeLength;
  24163. if (currentIndex >= index) {
  24164. return {
  24165. node: currentNode,
  24166. index: currentNodeLength - (currentIndex - index)
  24167. };
  24168. }
  24169. } else if (!dtd.$empty[currentNode.tagName]) {
  24170. currentNodeLength = getText(currentNode).replace(
  24171. /(^[\t\r\n]+)|([\t\r\n]+$)/,
  24172. ""
  24173. ).length;
  24174. currentIndex += currentNodeLength;
  24175. if (currentIndex >= index) {
  24176. result = findNTextInBlockElm(
  24177. currentNode,
  24178. currentNodeLength - (currentIndex - index),
  24179. str
  24180. );
  24181. if (result) {
  24182. return result;
  24183. }
  24184. }
  24185. }
  24186. currentNode = domUtils.getNextDomNode(currentNode);
  24187. }
  24188. }
  24189. function searchReplace(me, opt) {
  24190. var rng = lastRng || me.selection.getRange(),
  24191. startBlockNode,
  24192. searchStr = opt.searchStr,
  24193. span = me.document.createElement("span");
  24194. span.innerHTML = "$$ueditor_searchreplace_key$$";
  24195. rng.shrinkBoundary(true);
  24196. //判断是不是第一次选中
  24197. if (!rng.collapsed) {
  24198. rng.select();
  24199. var rngText = me.selection.getText();
  24200. if (
  24201. new RegExp(
  24202. "^" + opt.searchStr + "$",
  24203. opt.casesensitive ? "" : "i"
  24204. ).test(rngText)
  24205. ) {
  24206. if (opt.replaceStr != undefined) {
  24207. replaceText(rng, opt.replaceStr);
  24208. rng.select();
  24209. return true;
  24210. } else {
  24211. rng.collapse(opt.dir == -1);
  24212. }
  24213. }
  24214. }
  24215. rng.insertNode(span);
  24216. rng.enlargeToBlockElm(true);
  24217. startBlockNode = rng.startContainer;
  24218. var currentIndex = getText(startBlockNode).indexOf(
  24219. "$$ueditor_searchreplace_key$$"
  24220. );
  24221. rng.setStartBefore(span);
  24222. domUtils.remove(span);
  24223. var result = findTextBlockElm(startBlockNode, currentIndex, opt);
  24224. if (result) {
  24225. var rngStart = findNTextInBlockElm(result.node, result.index, searchStr);
  24226. var rngEnd = findNTextInBlockElm(
  24227. result.node,
  24228. result.index + searchStr.length,
  24229. searchStr
  24230. );
  24231. rng
  24232. .setStart(rngStart.node, rngStart.index)
  24233. .setEnd(rngEnd.node, rngEnd.index);
  24234. if (opt.replaceStr !== undefined) {
  24235. replaceText(rng, opt.replaceStr);
  24236. }
  24237. rng.select();
  24238. return true;
  24239. } else {
  24240. rng.setCursor();
  24241. }
  24242. }
  24243. function replaceText(rng, str) {
  24244. str = me.document.createTextNode(str);
  24245. rng.deleteContents().insertNode(str);
  24246. }
  24247. return {
  24248. commands: {
  24249. searchreplace: {
  24250. execCommand: function(cmdName, opt) {
  24251. utils.extend(
  24252. opt,
  24253. {
  24254. all: false,
  24255. casesensitive: false,
  24256. dir: 1
  24257. },
  24258. true
  24259. );
  24260. var num = 0;
  24261. if (opt.all) {
  24262. lastRng = null;
  24263. var rng = me.selection.getRange(),
  24264. first = me.body.firstChild;
  24265. if (first && first.nodeType == 1) {
  24266. rng.setStart(first, 0);
  24267. rng.shrinkBoundary(true);
  24268. } else if (first.nodeType == 3) {
  24269. rng.setStartBefore(first);
  24270. }
  24271. rng.collapse(true).select(true);
  24272. if (opt.replaceStr !== undefined) {
  24273. me.fireEvent("saveScene");
  24274. }
  24275. while (searchReplace(this, opt)) {
  24276. num++;
  24277. lastRng = me.selection.getRange();
  24278. lastRng.collapse(opt.dir == -1);
  24279. }
  24280. if (num) {
  24281. me.fireEvent("saveScene");
  24282. }
  24283. } else {
  24284. if (opt.replaceStr !== undefined) {
  24285. me.fireEvent("saveScene");
  24286. }
  24287. if (searchReplace(this, opt)) {
  24288. num++;
  24289. lastRng = me.selection.getRange();
  24290. lastRng.collapse(opt.dir == -1);
  24291. }
  24292. if (num) {
  24293. me.fireEvent("saveScene");
  24294. }
  24295. }
  24296. return num;
  24297. },
  24298. notNeedUndo: 1
  24299. }
  24300. },
  24301. bindEvents: {
  24302. clearlastSearchResult: function() {
  24303. lastRng = null;
  24304. }
  24305. }
  24306. };
  24307. });
  24308. // plugins/customstyle.js
  24309. /**
  24310. * 自定义样式
  24311. * @file
  24312. * @since 1.2.6.1
  24313. */
  24314. /**
  24315. * 根据config配置文件里“customstyle”选项的值对匹配的标签执行样式替换。
  24316. * @command customstyle
  24317. * @method execCommand
  24318. * @param { String } cmd 命令字符串
  24319. * @example
  24320. * ```javascript
  24321. * editor.execCommand( 'customstyle' );
  24322. * ```
  24323. */
  24324. UE.plugins["customstyle"] = function() {
  24325. var me = this;
  24326. me.setOpt({
  24327. customstyle: [
  24328. {
  24329. tag: "h1",
  24330. name: "tc",
  24331. style:
  24332. "font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;"
  24333. },
  24334. {
  24335. tag: "h1",
  24336. name: "tl",
  24337. style:
  24338. "font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;margin:0 0 10px 0;"
  24339. },
  24340. {
  24341. tag: "span",
  24342. name: "im",
  24343. style:
  24344. "font-size:16px;font-style:italic;font-weight:bold;line-height:18px;"
  24345. },
  24346. {
  24347. tag: "span",
  24348. name: "hi",
  24349. style:
  24350. "font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;"
  24351. }
  24352. ]
  24353. });
  24354. me.commands["customstyle"] = {
  24355. execCommand: function(cmdName, obj) {
  24356. var me = this,
  24357. tagName = obj.tag,
  24358. node = domUtils.findParent(
  24359. me.selection.getStart(),
  24360. function(node) {
  24361. return node.getAttribute("label");
  24362. },
  24363. true
  24364. ),
  24365. range,
  24366. bk,
  24367. tmpObj = {};
  24368. for (var p in obj) {
  24369. if (obj[p] !== undefined) tmpObj[p] = obj[p];
  24370. }
  24371. delete tmpObj.tag;
  24372. if (node && node.getAttribute("label") == obj.label) {
  24373. range = this.selection.getRange();
  24374. bk = range.createBookmark();
  24375. if (range.collapsed) {
  24376. //trace:1732 删掉自定义标签,要有p来回填站位
  24377. if (dtd.$block[node.tagName]) {
  24378. var fillNode = me.document.createElement("p");
  24379. domUtils.moveChild(node, fillNode);
  24380. node.parentNode.insertBefore(fillNode, node);
  24381. domUtils.remove(node);
  24382. } else {
  24383. domUtils.remove(node, true);
  24384. }
  24385. } else {
  24386. var common = domUtils.getCommonAncestor(bk.start, bk.end),
  24387. nodes = domUtils.getElementsByTagName(common, tagName);
  24388. if (new RegExp(tagName, "i").test(common.tagName)) {
  24389. nodes.push(common);
  24390. }
  24391. for (var i = 0, ni; (ni = nodes[i++]); ) {
  24392. if (ni.getAttribute("label") == obj.label) {
  24393. var ps = domUtils.getPosition(ni, bk.start),
  24394. pe = domUtils.getPosition(ni, bk.end);
  24395. if (
  24396. (ps & domUtils.POSITION_FOLLOWING ||
  24397. ps & domUtils.POSITION_CONTAINS) &&
  24398. (pe & domUtils.POSITION_PRECEDING ||
  24399. pe & domUtils.POSITION_CONTAINS)
  24400. )
  24401. if (dtd.$block[tagName]) {
  24402. var fillNode = me.document.createElement("p");
  24403. domUtils.moveChild(ni, fillNode);
  24404. ni.parentNode.insertBefore(fillNode, ni);
  24405. }
  24406. domUtils.remove(ni, true);
  24407. }
  24408. }
  24409. node = domUtils.findParent(
  24410. common,
  24411. function(node) {
  24412. return node.getAttribute("label") == obj.label;
  24413. },
  24414. true
  24415. );
  24416. if (node) {
  24417. domUtils.remove(node, true);
  24418. }
  24419. }
  24420. range.moveToBookmark(bk).select();
  24421. } else {
  24422. if (dtd.$block[tagName]) {
  24423. this.execCommand("paragraph", tagName, tmpObj, "customstyle");
  24424. range = me.selection.getRange();
  24425. if (!range.collapsed) {
  24426. range.collapse();
  24427. node = domUtils.findParent(
  24428. me.selection.getStart(),
  24429. function(node) {
  24430. return node.getAttribute("label") == obj.label;
  24431. },
  24432. true
  24433. );
  24434. var pNode = me.document.createElement("p");
  24435. domUtils.insertAfter(node, pNode);
  24436. domUtils.fillNode(me.document, pNode);
  24437. range.setStart(pNode, 0).setCursor();
  24438. }
  24439. } else {
  24440. range = me.selection.getRange();
  24441. if (range.collapsed) {
  24442. node = me.document.createElement(tagName);
  24443. domUtils.setAttributes(node, tmpObj);
  24444. range.insertNode(node).setStart(node, 0).setCursor();
  24445. return;
  24446. }
  24447. bk = range.createBookmark();
  24448. range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select();
  24449. }
  24450. }
  24451. },
  24452. queryCommandValue: function() {
  24453. var parent = domUtils.filterNodeList(
  24454. this.selection.getStartElementPath(),
  24455. function(node) {
  24456. return node.getAttribute("label");
  24457. }
  24458. );
  24459. return parent ? parent.getAttribute("label") : "";
  24460. }
  24461. };
  24462. //当去掉customstyle是,如果是块元素,用p代替
  24463. me.addListener("keyup", function(type, evt) {
  24464. var keyCode = evt.keyCode || evt.which;
  24465. if (keyCode == 32 || keyCode == 13) {
  24466. var range = me.selection.getRange();
  24467. if (range.collapsed) {
  24468. var node = domUtils.findParent(
  24469. me.selection.getStart(),
  24470. function(node) {
  24471. return node.getAttribute("label");
  24472. },
  24473. true
  24474. );
  24475. if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
  24476. var p = me.document.createElement("p");
  24477. domUtils.insertAfter(node, p);
  24478. domUtils.fillNode(me.document, p);
  24479. domUtils.remove(node);
  24480. range.setStart(p, 0).setCursor();
  24481. }
  24482. }
  24483. }
  24484. });
  24485. };
  24486. // plugins/catchremoteimage.js
  24487. ///import core
  24488. ///commands 远程图片抓取
  24489. ///commandsName catchRemoteImage,catchremoteimageenable
  24490. ///commandsTitle 远程图片抓取
  24491. /**
  24492. * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
  24493. */
  24494. UE.plugins["catchremoteimage"] = function() {
  24495. var me = this,
  24496. ajax = UE.ajax;
  24497. /* 设置默认值 */
  24498. if (me.options.catchRemoteImageEnable === false) return;
  24499. me.setOpt({
  24500. catchRemoteImageEnable: false
  24501. });
  24502. me.addListener("afterpaste", function() {
  24503. me.fireEvent("catchRemoteImage");
  24504. });
  24505. me.addListener("catchRemoteImage", function() {
  24506. var catcherLocalDomain = me.getOpt("catcherLocalDomain"),
  24507. catcherActionUrl = me.getActionUrl(me.getOpt("catcherActionName")),
  24508. catcherUrlPrefix = me.getOpt("catcherUrlPrefix"),
  24509. catcherFieldName = me.getOpt("catcherFieldName");
  24510. var remoteImages = [],
  24511. loadingIMG = me.options.themePath + me.options.theme + '/images/spacer.gif',
  24512. imgs = me.document.querySelectorAll('[style*="url"],img'),
  24513. test = function(src, urls) {
  24514. if (src.indexOf(location.host) != -1 || /(^\.)|(^\/)/.test(src)) {
  24515. return true;
  24516. }
  24517. if (urls) {
  24518. for (var j = 0, url; (url = urls[j++]); ) {
  24519. if (src.indexOf(url) !== -1) {
  24520. return true;
  24521. }
  24522. }
  24523. }
  24524. return false;
  24525. };
  24526. for (var i = 0, ci; (ci = imgs[i++]); ) {
  24527. if (ci.getAttribute("word_img")) {
  24528. continue;
  24529. }
  24530. if(ci.nodeName == "IMG"){
  24531. var src = ci.getAttribute("_src") || ci.src || "";
  24532. if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
  24533. remoteImages.push(src);
  24534. // 添加上传时的uploading动画
  24535. domUtils.setAttributes(ci, {
  24536. class: "loadingclass",
  24537. _src: src,
  24538. src: loadingIMG
  24539. })
  24540. }
  24541. } else {
  24542. // 获取背景图片url
  24543. var backgroundImageurl = ci.style.cssText.replace(/.*\s?url\([\'\"]?/, '').replace(/[\'\"]?\).*/, '');
  24544. if (/^(https?|ftp):/i.test(backgroundImageurl) && !test(backgroundImageurl, catcherLocalDomain)) {
  24545. remoteImages.push(backgroundImageurl);
  24546. ci.style.cssText = ci.style.cssText.replace(backgroundImageurl, loadingIMG);
  24547. domUtils.setAttributes(ci, {
  24548. "data-background": backgroundImageurl
  24549. })
  24550. }
  24551. }
  24552. }
  24553. if (remoteImages.length) {
  24554. catchremoteimage(remoteImages, {
  24555. //成功抓取
  24556. success: function(r) {
  24557. try {
  24558. var info = r.state !== undefined
  24559. ? r
  24560. : eval("(" + r.responseText + ")");
  24561. } catch (e) {
  24562. return;
  24563. }
  24564. /* 获取源路径和新路径 */
  24565. var i,
  24566. j,
  24567. ci,
  24568. cj,
  24569. oldSrc,
  24570. newSrc,
  24571. list = info.list;
  24572. /* 抓取失败统计 */
  24573. var catchFailList = [];
  24574. /* 抓取成功统计 */
  24575. var catchSuccessList = [];
  24576. /* 抓取失败时显示的图片 */
  24577. var failIMG = me.options.themePath + me.options.theme + '/images/img-cracked.png';
  24578. for (i = 0; ci = imgs[i++];) {
  24579. oldSrc = ci.getAttribute("_src") || ci.src || "";
  24580. oldBgIMG = ci.getAttribute("data-background") || "";
  24581. for (j = 0; cj = list[j++];) {
  24582. if (oldSrc == cj.source && cj.state == "SUCCESS") {
  24583. newSrc = catcherUrlPrefix + cj.url;
  24584. // 上传成功是删除uploading动画
  24585. domUtils.removeClasses( ci, "loadingclass" );
  24586. domUtils.setAttributes(ci, {
  24587. "src": newSrc,
  24588. "_src": newSrc,
  24589. "data-catchResult":"img_catchSuccess" // 添加catch成功标记
  24590. });
  24591. catchSuccessList.push(ci);
  24592. break;
  24593. } else if (oldSrc == cj.source && cj.state == "FAIL") {
  24594. // 替换成统一的失败图片
  24595. domUtils.removeClasses( ci, "loadingclass" );
  24596. domUtils.setAttributes(ci, {
  24597. "src": failIMG,
  24598. "_src": failIMG,
  24599. "data-catchResult":"img_catchFail" // 添加catch失败标记
  24600. });
  24601. catchFailList.push(ci);
  24602. break;
  24603. } else if (oldBgIMG == cj.source && cj.state == "SUCCESS") {
  24604. newBgIMG = catcherUrlPrefix + cj.url;
  24605. ci.style.cssText = ci.style.cssText.replace(loadingIMG, newBgIMG);
  24606. domUtils.removeAttributes(ci,"data-background");
  24607. domUtils.setAttributes(ci, {
  24608. "data-catchResult":"img_catchSuccess" // 添加catch成功标记
  24609. });
  24610. catchSuccessList.push(ci);
  24611. break;
  24612. } else if (oldBgIMG == cj.source && cj.state == "FAIL"){
  24613. ci.style.cssText = ci.style.cssText.replace(loadingIMG, failIMG);
  24614. domUtils.removeAttributes(ci,"data-background");
  24615. domUtils.setAttributes(ci, {
  24616. "data-catchResult":"img_catchFail" // 添加catch失败标记
  24617. });
  24618. catchFailList.push(ci);
  24619. break;
  24620. }
  24621. }
  24622. }
  24623. // 监听事件添加成功抓取和抓取失败的dom列表参数
  24624. me.fireEvent('catchremotesuccess',catchSuccessList,catchFailList);
  24625. },
  24626. //回调失败,本次请求超时
  24627. error: function() {
  24628. me.fireEvent("catchremoteerror");
  24629. }
  24630. });
  24631. }
  24632. function catchremoteimage(imgs, callbacks) {
  24633. var params =
  24634. utils.serializeParam(me.queryCommandValue("serverparam")) || "",
  24635. url = utils.formatUrl(
  24636. catcherActionUrl +
  24637. (catcherActionUrl.indexOf("?") == -1 ? "?" : "&") +
  24638. params
  24639. ),
  24640. isJsonp = utils.isCrossDomainUrl(url),
  24641. opt = {
  24642. method: "POST",
  24643. dataType: isJsonp ? "jsonp" : "",
  24644. timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
  24645. onsuccess: callbacks["success"],
  24646. onerror: callbacks["error"]
  24647. };
  24648. opt[catcherFieldName] = imgs;
  24649. ajax.request(url, opt);
  24650. }
  24651. });
  24652. };
  24653. // plugins/snapscreen.js
  24654. /**
  24655. * 截屏插件,为UEditor提供插入支持
  24656. * @file
  24657. * @since 1.4.2
  24658. */
  24659. UE.plugin.register("snapscreen", function() {
  24660. var me = this;
  24661. var snapplugin;
  24662. function getLocation(url) {
  24663. var search,
  24664. a = document.createElement("a"),
  24665. params = utils.serializeParam(me.queryCommandValue("serverparam")) || "";
  24666. a.href = url;
  24667. if (browser.ie) {
  24668. a.href = a.href;
  24669. }
  24670. search = a.search;
  24671. if (params) {
  24672. search = search + (search.indexOf("?") == -1 ? "?" : "&") + params;
  24673. search = search.replace(/[&]+/gi, "&");
  24674. }
  24675. return {
  24676. port: a.port,
  24677. hostname: a.hostname,
  24678. path: a.pathname + search || +a.hash
  24679. };
  24680. }
  24681. return {
  24682. commands: {
  24683. /**
  24684. * 字体背景颜色
  24685. * @command snapscreen
  24686. * @method execCommand
  24687. * @param { String } cmd 命令字符串
  24688. * @example
  24689. * ```javascript
  24690. * editor.execCommand('snapscreen');
  24691. * ```
  24692. */
  24693. snapscreen: {
  24694. execCommand: function(cmd) {
  24695. var url, local, res;
  24696. var lang = me.getLang("snapScreen_plugin");
  24697. if (!snapplugin) {
  24698. var container = me.container;
  24699. var doc = me.container.ownerDocument || me.container.document;
  24700. snapplugin = doc.createElement("object");
  24701. try {
  24702. snapplugin.type = "application/x-pluginbaidusnap";
  24703. } catch (e) {
  24704. return;
  24705. }
  24706. snapplugin.style.cssText =
  24707. "position:absolute;left:-9999px;width:0;height:0;";
  24708. snapplugin.setAttribute("width", "0");
  24709. snapplugin.setAttribute("height", "0");
  24710. container.appendChild(snapplugin);
  24711. }
  24712. function onSuccess(rs) {
  24713. try {
  24714. rs = eval("(" + rs + ")");
  24715. if (rs.state == "SUCCESS") {
  24716. var opt = me.options;
  24717. me.execCommand("insertimage", {
  24718. src: opt.snapscreenUrlPrefix + rs.url,
  24719. _src: opt.snapscreenUrlPrefix + rs.url,
  24720. alt: rs.title || "",
  24721. floatStyle: opt.snapscreenImgAlign
  24722. });
  24723. } else {
  24724. alert(rs.state);
  24725. }
  24726. } catch (e) {
  24727. alert(lang.callBackErrorMsg);
  24728. }
  24729. }
  24730. url = me.getActionUrl(me.getOpt("snapscreenActionName"));
  24731. local = getLocation(url);
  24732. setTimeout(function() {
  24733. try {
  24734. res = snapplugin.saveSnapshot(
  24735. local.hostname,
  24736. local.path,
  24737. local.port
  24738. );
  24739. } catch (e) {
  24740. me.ui._dialogs["snapscreenDialog"].open();
  24741. return;
  24742. }
  24743. onSuccess(res);
  24744. }, 50);
  24745. },
  24746. queryCommandState: function() {
  24747. return navigator.userAgent.indexOf("Windows", 0) != -1 ? 0 : -1;
  24748. }
  24749. }
  24750. }
  24751. };
  24752. });
  24753. // plugins/insertparagraph.js
  24754. /**
  24755. * 插入段落
  24756. * @file
  24757. * @since 1.2.6.1
  24758. */
  24759. /**
  24760. * 插入段落
  24761. * @command insertparagraph
  24762. * @method execCommand
  24763. * @param { String } cmd 命令字符串
  24764. * @example
  24765. * ```javascript
  24766. * //editor是编辑器实例
  24767. * editor.execCommand( 'insertparagraph' );
  24768. * ```
  24769. */
  24770. UE.commands["insertparagraph"] = {
  24771. execCommand: function(cmdName, front) {
  24772. var me = this,
  24773. range = me.selection.getRange(),
  24774. start = range.startContainer,
  24775. tmpNode;
  24776. while (start) {
  24777. if (domUtils.isBody(start)) {
  24778. break;
  24779. }
  24780. tmpNode = start;
  24781. start = start.parentNode;
  24782. }
  24783. if (tmpNode) {
  24784. var p = me.document.createElement("p");
  24785. if (front) {
  24786. tmpNode.parentNode.insertBefore(p, tmpNode);
  24787. } else {
  24788. tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling);
  24789. }
  24790. domUtils.fillNode(me.document, p);
  24791. range.setStart(p, 0).setCursor(false, true);
  24792. }
  24793. }
  24794. };
  24795. // plugins/webapp.js
  24796. /**
  24797. * 百度应用
  24798. * @file
  24799. * @since 1.2.6.1
  24800. */
  24801. /**
  24802. * 插入百度应用
  24803. * @command webapp
  24804. * @method execCommand
  24805. * @remind 需要百度APPKey
  24806. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  24807. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  24808. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  24809. * @example
  24810. * ```javascript
  24811. * //editor是编辑器实例
  24812. * //在编辑器里插入一个“植物大战僵尸”的APP
  24813. * editor.execCommand( 'webapp' , {
  24814. * title: '植物大战僵尸',
  24815. * width: 560,
  24816. * height: 465,
  24817. * logo: '应用展示的图片',
  24818. * url: '百度应用的地址'
  24819. * } );
  24820. * ```
  24821. */
  24822. //UE.plugins['webapp'] = function () {
  24823. // var me = this;
  24824. // function createInsertStr( obj, toIframe, addParagraph ) {
  24825. // return !toIframe ?
  24826. // (addParagraph ? '<p>' : '') + '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
  24827. // ' 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 + '" />' +
  24828. // (addParagraph ? '</p>' : '')
  24829. // :
  24830. // '<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>';
  24831. // }
  24832. //
  24833. // function switchImgAndIframe( img2frame ) {
  24834. // var tmpdiv,
  24835. // nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
  24836. // for ( var i = 0, node; node = nodes[i++]; ) {
  24837. // if ( node.className != "edui-faked-webapp" ){
  24838. // continue;
  24839. // }
  24840. // tmpdiv = me.document.createElement( "div" );
  24841. // 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 );
  24842. // node.parentNode.replaceChild( tmpdiv.firstChild, node );
  24843. // }
  24844. // }
  24845. //
  24846. // me.addListener( "beforegetcontent", function () {
  24847. // switchImgAndIframe( true );
  24848. // } );
  24849. // me.addListener( 'aftersetcontent', function () {
  24850. // switchImgAndIframe( false );
  24851. // } );
  24852. // me.addListener( 'aftergetcontent', function ( cmdName ) {
  24853. // if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
  24854. // return;
  24855. // }
  24856. // switchImgAndIframe( false );
  24857. // } );
  24858. //
  24859. // me.commands['webapp'] = {
  24860. // execCommand:function ( cmd, obj ) {
  24861. // me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
  24862. // }
  24863. // };
  24864. //};
  24865. UE.plugin.register("webapp", function() {
  24866. var me = this;
  24867. function createInsertStr(obj, toEmbed) {
  24868. return !toEmbed
  24869. ? '<img title="' +
  24870. obj.title +
  24871. '" width="' +
  24872. obj.width +
  24873. '" height="' +
  24874. obj.height +
  24875. '"' +
  24876. ' src="' +
  24877. me.options.UEDITOR_HOME_URL +
  24878. 'themes/notadd/images/spacer.gif" _logo_url="' +
  24879. obj.logo +
  24880. '" style="background:url(' +
  24881. obj.logo +
  24882. ') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' +
  24883. obj.url +
  24884. '" ' +
  24885. (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : "") +
  24886. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : "") +
  24887. "/>"
  24888. : '<iframe class="edui-faked-webapp" title="' +
  24889. obj.title +
  24890. '" ' +
  24891. (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : "") +
  24892. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : "") +
  24893. 'width="' +
  24894. obj.width +
  24895. '" height="' +
  24896. obj.height +
  24897. '" scrolling="no" frameborder="0" src="' +
  24898. obj.url +
  24899. '" logo_url = "' +
  24900. obj.logo +
  24901. '"></iframe>';
  24902. }
  24903. return {
  24904. outputRule: function(root) {
  24905. utils.each(root.getNodesByTagName("img"), function(node) {
  24906. var html;
  24907. if (node.getAttr("class") == "edui-faked-webapp") {
  24908. html = createInsertStr(
  24909. {
  24910. title: node.getAttr("title"),
  24911. width: node.getAttr("width"),
  24912. height: node.getAttr("height"),
  24913. align: node.getAttr("align"),
  24914. cssfloat: node.getStyle("float"),
  24915. url: node.getAttr("_url"),
  24916. logo: node.getAttr("_logo_url")
  24917. },
  24918. true
  24919. );
  24920. var embed = UE.uNode.createElement(html);
  24921. node.parentNode.replaceChild(embed, node);
  24922. }
  24923. });
  24924. },
  24925. inputRule: function(root) {
  24926. utils.each(root.getNodesByTagName("iframe"), function(node) {
  24927. if (node.getAttr("class") == "edui-faked-webapp") {
  24928. var img = UE.uNode.createElement(
  24929. createInsertStr({
  24930. title: node.getAttr("title"),
  24931. width: node.getAttr("width"),
  24932. height: node.getAttr("height"),
  24933. align: node.getAttr("align"),
  24934. cssfloat: node.getStyle("float"),
  24935. url: node.getAttr("src"),
  24936. logo: node.getAttr("logo_url")
  24937. })
  24938. );
  24939. node.parentNode.replaceChild(img, node);
  24940. }
  24941. });
  24942. },
  24943. commands: {
  24944. /**
  24945. * 插入百度应用
  24946. * @command webapp
  24947. * @method execCommand
  24948. * @remind 需要百度APPKey
  24949. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  24950. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  24951. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  24952. * @example
  24953. * ```javascript
  24954. * //editor是编辑器实例
  24955. * //在编辑器里插入一个“植物大战僵尸”的APP
  24956. * editor.execCommand( 'webapp' , {
  24957. * title: '植物大战僵尸',
  24958. * width: 560,
  24959. * height: 465,
  24960. * logo: '应用展示的图片',
  24961. * url: '百度应用的地址'
  24962. * } );
  24963. * ```
  24964. */
  24965. webapp: {
  24966. execCommand: function(cmd, obj) {
  24967. var me = this,
  24968. str = createInsertStr(
  24969. utils.extend(obj, {
  24970. align: "none"
  24971. }),
  24972. false
  24973. );
  24974. me.execCommand("inserthtml", str);
  24975. },
  24976. queryCommandState: function() {
  24977. var me = this,
  24978. img = me.selection.getRange().getClosedNode(),
  24979. flag = img && img.className == "edui-faked-webapp";
  24980. return flag ? 1 : 0;
  24981. }
  24982. }
  24983. }
  24984. };
  24985. });
  24986. // plugins/template.js
  24987. ///import core
  24988. ///import plugins\inserthtml.js
  24989. ///import plugins\cleardoc.js
  24990. ///commands 模板
  24991. ///commandsName template
  24992. ///commandsTitle 模板
  24993. ///commandsDialog dialogs\template
  24994. UE.plugins["template"] = function() {
  24995. UE.commands["template"] = {
  24996. execCommand: function(cmd, obj) {
  24997. obj.html && this.execCommand("inserthtml", obj.html);
  24998. }
  24999. };
  25000. this.addListener("click", function(type, evt) {
  25001. var el = evt.target || evt.srcElement,
  25002. range = this.selection.getRange();
  25003. var tnode = domUtils.findParent(
  25004. el,
  25005. function(node) {
  25006. if (node.className && domUtils.hasClass(node, "ue_t")) {
  25007. return node;
  25008. }
  25009. },
  25010. true
  25011. );
  25012. tnode && range.selectNode(tnode).shrinkBoundary().select();
  25013. });
  25014. this.addListener("keydown", function(type, evt) {
  25015. var range = this.selection.getRange();
  25016. if (!range.collapsed) {
  25017. if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  25018. var tnode = domUtils.findParent(
  25019. range.startContainer,
  25020. function(node) {
  25021. if (node.className && domUtils.hasClass(node, "ue_t")) {
  25022. return node;
  25023. }
  25024. },
  25025. true
  25026. );
  25027. if (tnode) {
  25028. domUtils.removeClasses(tnode, ["ue_t"]);
  25029. }
  25030. }
  25031. }
  25032. });
  25033. };
  25034. // plugins/music.js
  25035. /**
  25036. * 插入音乐命令
  25037. * @file
  25038. */
  25039. UE.plugin.register("music", function() {
  25040. var me = this;
  25041. function creatInsertStr(url, width, height, align, cssfloat, toEmbed) {
  25042. return !toEmbed
  25043. ? "<img " +
  25044. (align && !cssfloat ? 'align="' + align + '"' : "") +
  25045. (cssfloat ? 'style="float:' + cssfloat + '"' : "") +
  25046. ' width="' +
  25047. width +
  25048. '" height="' +
  25049. height +
  25050. '" _url="' +
  25051. url +
  25052. '" class="edui-faked-music"' +
  25053. ' src="' +
  25054. me.options.langPath +
  25055. me.options.lang +
  25056. '/images/music.png" />'
  25057. : '<embed type="application/x-shockwave-flash" class="edui-faked-music" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  25058. ' src="' +
  25059. url +
  25060. '" width="' +
  25061. width +
  25062. '" height="' +
  25063. height +
  25064. '" ' +
  25065. (align && !cssfloat ? 'align="' + align + '"' : "") +
  25066. (cssfloat ? 'style="float:' + cssfloat + '"' : "") +
  25067. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  25068. }
  25069. return {
  25070. outputRule: function(root) {
  25071. utils.each(root.getNodesByTagName("img"), function(node) {
  25072. var html;
  25073. if (node.getAttr("class") == "edui-faked-music") {
  25074. var cssfloat = node.getStyle("float");
  25075. var align = node.getAttr("align");
  25076. html = creatInsertStr(
  25077. node.getAttr("_url"),
  25078. node.getAttr("width"),
  25079. node.getAttr("height"),
  25080. align,
  25081. cssfloat,
  25082. true
  25083. );
  25084. var embed = UE.uNode.createElement(html);
  25085. node.parentNode.replaceChild(embed, node);
  25086. }
  25087. });
  25088. },
  25089. inputRule: function(root) {
  25090. utils.each(root.getNodesByTagName("embed"), function(node) {
  25091. if (node.getAttr("class") == "edui-faked-music") {
  25092. var cssfloat = node.getStyle("float");
  25093. var align = node.getAttr("align");
  25094. html = creatInsertStr(
  25095. node.getAttr("src"),
  25096. node.getAttr("width"),
  25097. node.getAttr("height"),
  25098. align,
  25099. cssfloat,
  25100. false
  25101. );
  25102. var img = UE.uNode.createElement(html);
  25103. node.parentNode.replaceChild(img, node);
  25104. }
  25105. });
  25106. },
  25107. commands: {
  25108. /**
  25109. * 插入音乐
  25110. * @command music
  25111. * @method execCommand
  25112. * @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
  25113. * width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
  25114. * @example
  25115. * ```javascript
  25116. * //editor是编辑器实例
  25117. * //在编辑器里插入一个“植物大战僵尸”的APP
  25118. * editor.execCommand( 'music' , {
  25119. * width: 400,
  25120. * height: 95,
  25121. * align: "center",
  25122. * url: "音乐地址"
  25123. * } );
  25124. * ```
  25125. */
  25126. music: {
  25127. execCommand: function(cmd, musicObj) {
  25128. var me = this,
  25129. str = creatInsertStr(
  25130. musicObj.url,
  25131. musicObj.width || 400,
  25132. musicObj.height || 95,
  25133. "none",
  25134. false
  25135. );
  25136. me.execCommand("inserthtml", str);
  25137. },
  25138. queryCommandState: function() {
  25139. var me = this,
  25140. img = me.selection.getRange().getClosedNode(),
  25141. flag = img && img.className == "edui-faked-music";
  25142. return flag ? 1 : 0;
  25143. }
  25144. }
  25145. }
  25146. };
  25147. });
  25148. // plugins/autoupload.js
  25149. /**
  25150. * @description
  25151. * 1.拖放文件到编辑区域,自动上传并插入到选区
  25152. * 2.插入粘贴板的图片,自动上传并插入到选区
  25153. * @author Jinqn
  25154. * @date 2013-10-14
  25155. */
  25156. UE.plugin.register("autoupload", function() {
  25157. function sendAndInsertFile(file, editor) {
  25158. var me = editor;
  25159. //模拟数据
  25160. var fieldName,
  25161. urlPrefix,
  25162. maxSize,
  25163. allowFiles,
  25164. actionUrl,
  25165. loadingHtml,
  25166. errorHandler,
  25167. successHandler,
  25168. filetype = /image\/\w+/i.test(file.type) ? "image" : "file",
  25169. loadingId = "loading_" + (+new Date()).toString(36);
  25170. fieldName = me.getOpt(filetype + "FieldName");
  25171. urlPrefix = me.getOpt(filetype + "UrlPrefix");
  25172. maxSize = me.getOpt(filetype + "MaxSize");
  25173. allowFiles = me.getOpt(filetype + "AllowFiles");
  25174. actionUrl = me.getActionUrl(me.getOpt(filetype + "ActionName"));
  25175. errorHandler = function(title) {
  25176. var loader = me.document.getElementById(loadingId);
  25177. loader && domUtils.remove(loader);
  25178. me.fireEvent("showmessage", {
  25179. id: loadingId,
  25180. content: title,
  25181. type: "error",
  25182. timeout: 4000
  25183. });
  25184. };
  25185. if (filetype == "image") {
  25186. loadingHtml =
  25187. '<img class="loadingclass" id="' +
  25188. loadingId +
  25189. '" src="' +
  25190. me.options.themePath +
  25191. me.options.theme +
  25192. '/images/spacer.gif">';
  25193. successHandler = function(data) {
  25194. var link = urlPrefix + data.url,
  25195. loader = me.document.getElementById(loadingId);
  25196. if (loader) {
  25197. domUtils.removeClasses(loader, "loadingclass");
  25198. loader.setAttribute("src", link);
  25199. loader.setAttribute("_src", link);
  25200. loader.setAttribute("alt", data.original || "");
  25201. loader.removeAttribute("id");
  25202. me.trigger("contentchange", loader);
  25203. }
  25204. };
  25205. } else {
  25206. loadingHtml =
  25207. "<p>" +
  25208. '<img class="loadingclass" id="' +
  25209. loadingId +
  25210. '" src="' +
  25211. me.options.themePath +
  25212. me.options.theme +
  25213. '/images/spacer.gif">' +
  25214. "</p>";
  25215. successHandler = function(data) {
  25216. var link = urlPrefix + data.url,
  25217. loader = me.document.getElementById(loadingId);
  25218. var rng = me.selection.getRange(),
  25219. bk = rng.createBookmark();
  25220. rng.selectNode(loader).select();
  25221. me.execCommand("insertfile", { url: link });
  25222. rng.moveToBookmark(bk).select();
  25223. };
  25224. }
  25225. /* 插入loading的占位符 */
  25226. me.execCommand("inserthtml", loadingHtml);
  25227. /* 判断后端配置是否没有加载成功 */
  25228. if (!me.getOpt(filetype + "ActionName")) {
  25229. errorHandler(me.getLang("autoupload.errorLoadConfig"));
  25230. return;
  25231. }
  25232. /* 判断文件大小是否超出限制 */
  25233. if (file.size > maxSize) {
  25234. errorHandler(me.getLang("autoupload.exceedSizeError"));
  25235. return;
  25236. }
  25237. /* 判断文件格式是否超出允许 */
  25238. var fileext = file.name ? file.name.substr(file.name.lastIndexOf(".")) : "";
  25239. if (
  25240. (fileext && filetype != "image") ||
  25241. (allowFiles &&
  25242. (allowFiles.join("") + ".").indexOf(fileext.toLowerCase() + ".") == -1)
  25243. ) {
  25244. errorHandler(me.getLang("autoupload.exceedTypeError"));
  25245. return;
  25246. }
  25247. /* 创建Ajax并提交 */
  25248. var xhr = new XMLHttpRequest(),
  25249. fd = new FormData(),
  25250. params = utils.serializeParam(me.queryCommandValue("serverparam")) || "",
  25251. url = utils.formatUrl(
  25252. actionUrl + (actionUrl.indexOf("?") == -1 ? "?" : "&") + params
  25253. );
  25254. fd.append(
  25255. fieldName,
  25256. file,
  25257. file.name || "blob." + file.type.substr("image/".length)
  25258. );
  25259. fd.append("type", "ajax");
  25260. xhr.open("post", url, true);
  25261. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  25262. xhr.addEventListener("load", function(e) {
  25263. try {
  25264. var json = new Function("return " + utils.trim(e.target.response))();
  25265. if (json.state == "SUCCESS" && json.url) {
  25266. successHandler(json);
  25267. } else {
  25268. errorHandler(json.state);
  25269. }
  25270. } catch (er) {
  25271. errorHandler(me.getLang("autoupload.loadError"));
  25272. }
  25273. });
  25274. xhr.send(fd);
  25275. }
  25276. function getPasteImage(e) {
  25277. return e.clipboardData &&
  25278. e.clipboardData.items &&
  25279. e.clipboardData.items.length == 1 &&
  25280. /^image\//.test(e.clipboardData.items[0].type)
  25281. ? e.clipboardData.items
  25282. : null;
  25283. }
  25284. function getDropImage(e) {
  25285. return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files : null;
  25286. }
  25287. return {
  25288. outputRule: function(root) {
  25289. utils.each(root.getNodesByTagName("img"), function(n) {
  25290. if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr("class"))) {
  25291. n.parentNode.removeChild(n);
  25292. }
  25293. });
  25294. utils.each(root.getNodesByTagName("p"), function(n) {
  25295. if (/\bloadpara\b/.test(n.getAttr("class"))) {
  25296. n.parentNode.removeChild(n);
  25297. }
  25298. });
  25299. },
  25300. bindEvents: {
  25301. defaultOptions: {
  25302. //默认间隔时间
  25303. enableDragUpload: true,
  25304. enablePasteUpload: true
  25305. },
  25306. //插入粘贴板的图片,拖放插入图片
  25307. ready: function(e) {
  25308. var me = this;
  25309. if (window.FormData && window.FileReader) {
  25310. var handler = function(e) {
  25311. var hasImg = false,
  25312. items;
  25313. //获取粘贴板文件列表或者拖放文件列表
  25314. items = e.type == "paste" ? getPasteImage(e) : getDropImage(e);
  25315. if (items) {
  25316. var len = items.length,
  25317. file;
  25318. while (len--) {
  25319. file = items[len];
  25320. if (file.getAsFile) file = file.getAsFile();
  25321. if (file && file.size > 0) {
  25322. sendAndInsertFile(file, me);
  25323. hasImg = true;
  25324. }
  25325. }
  25326. hasImg && e.preventDefault();
  25327. }
  25328. };
  25329. if (me.getOpt("enablePasteUpload") !== false) {
  25330. domUtils.on(me.body, "paste ", handler);
  25331. }
  25332. if (me.getOpt("enableDragUpload") !== false) {
  25333. domUtils.on(me.body, "drop", handler);
  25334. //取消拖放图片时出现的文字光标位置提示
  25335. domUtils.on(me.body, "dragover", function(e) {
  25336. if (e.dataTransfer.types[0] == "Files") {
  25337. e.preventDefault();
  25338. }
  25339. });
  25340. } else {
  25341. if (browser.gecko) {
  25342. domUtils.on(me.body, "drop", function(e) {
  25343. if (getDropImage(e)) {
  25344. e.preventDefault();
  25345. }
  25346. });
  25347. }
  25348. }
  25349. //设置loading的样式
  25350. utils.cssRule(
  25351. "loading",
  25352. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  25353. this.options.themePath +
  25354. this.options.theme +
  25355. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n" +
  25356. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  25357. this.options.themePath +
  25358. this.options.theme +
  25359. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  25360. "}",
  25361. this.document
  25362. );
  25363. }
  25364. }
  25365. }
  25366. };
  25367. });
  25368. // plugins/autosave.js
  25369. UE.plugin.register("autosave", function() {
  25370. var me = this,
  25371. //无限循环保护
  25372. lastSaveTime = new Date(),
  25373. //最小保存间隔时间
  25374. MIN_TIME = 20,
  25375. //auto save key
  25376. saveKey = null;
  25377. function save(editor) {
  25378. var saveData;
  25379. if (new Date() - lastSaveTime < MIN_TIME) {
  25380. return;
  25381. }
  25382. if (!editor.hasContents()) {
  25383. //这里不能调用命令来删除, 会造成事件死循环
  25384. saveKey && me.removePreferences(saveKey);
  25385. return;
  25386. }
  25387. lastSaveTime = new Date();
  25388. editor._saveFlag = null;
  25389. saveData = me.body.innerHTML;
  25390. if (
  25391. editor.fireEvent("beforeautosave", {
  25392. content: saveData
  25393. }) === false
  25394. ) {
  25395. return;
  25396. }
  25397. me.setPreferences(saveKey, saveData);
  25398. editor.fireEvent("afterautosave", {
  25399. content: saveData
  25400. });
  25401. }
  25402. return {
  25403. defaultOptions: {
  25404. //默认间隔时间
  25405. saveInterval: 500,
  25406. enableAutoSave: true
  25407. },
  25408. bindEvents: {
  25409. ready: function() {
  25410. var _suffix = "-drafts-data",
  25411. key = null;
  25412. if (me.key) {
  25413. key = me.key + _suffix;
  25414. } else {
  25415. key = (me.container.parentNode.id || "ue-common") + _suffix;
  25416. }
  25417. //页面地址+编辑器ID 保持唯一
  25418. saveKey =
  25419. (location.protocol + location.host + location.pathname).replace(
  25420. /[.:\/]/g,
  25421. "_"
  25422. ) + key;
  25423. },
  25424. contentchange: function() {
  25425. if (!me.getOpt("enableAutoSave")) {
  25426. return;
  25427. }
  25428. if (!saveKey) {
  25429. return;
  25430. }
  25431. if (me._saveFlag) {
  25432. window.clearTimeout(me._saveFlag);
  25433. }
  25434. if (me.options.saveInterval > 0) {
  25435. me._saveFlag = window.setTimeout(function() {
  25436. save(me);
  25437. }, me.options.saveInterval);
  25438. } else {
  25439. save(me);
  25440. }
  25441. }
  25442. },
  25443. commands: {
  25444. clearlocaldata: {
  25445. execCommand: function(cmd, name) {
  25446. if (saveKey && me.getPreferences(saveKey)) {
  25447. me.removePreferences(saveKey);
  25448. }
  25449. },
  25450. notNeedUndo: true,
  25451. ignoreContentChange: true
  25452. },
  25453. getlocaldata: {
  25454. execCommand: function(cmd, name) {
  25455. return saveKey ? me.getPreferences(saveKey) || "" : "";
  25456. },
  25457. notNeedUndo: true,
  25458. ignoreContentChange: true
  25459. },
  25460. drafts: {
  25461. execCommand: function(cmd, name) {
  25462. if (saveKey) {
  25463. me.body.innerHTML =
  25464. me.getPreferences(saveKey) || "<p>" + domUtils.fillHtml + "</p>";
  25465. me.focus(true);
  25466. }
  25467. },
  25468. queryCommandState: function() {
  25469. return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1;
  25470. },
  25471. notNeedUndo: true,
  25472. ignoreContentChange: true
  25473. }
  25474. }
  25475. };
  25476. });
  25477. // plugins/charts.js
  25478. UE.plugin.register("charts", function() {
  25479. var me = this;
  25480. return {
  25481. bindEvents: {
  25482. chartserror: function() {}
  25483. },
  25484. commands: {
  25485. charts: {
  25486. execCommand: function(cmd, data) {
  25487. var tableNode = domUtils.findParentByTagName(
  25488. this.selection.getRange().startContainer,
  25489. "table",
  25490. true
  25491. ),
  25492. flagText = [],
  25493. config = {};
  25494. if (!tableNode) {
  25495. return false;
  25496. }
  25497. if (!validData(tableNode)) {
  25498. me.fireEvent("chartserror");
  25499. return false;
  25500. }
  25501. config.title = data.title || "";
  25502. config.subTitle = data.subTitle || "";
  25503. config.xTitle = data.xTitle || "";
  25504. config.yTitle = data.yTitle || "";
  25505. config.suffix = data.suffix || "";
  25506. config.tip = data.tip || "";
  25507. //数据对齐方式
  25508. config.dataFormat = data.tableDataFormat || "";
  25509. //图表类型
  25510. config.chartType = data.chartType || 0;
  25511. for (var key in config) {
  25512. if (!config.hasOwnProperty(key)) {
  25513. continue;
  25514. }
  25515. flagText.push(key + ":" + config[key]);
  25516. }
  25517. tableNode.setAttribute("data-chart", flagText.join(";"));
  25518. domUtils.addClass(tableNode, "edui-charts-table");
  25519. },
  25520. queryCommandState: function(cmd, name) {
  25521. var tableNode = domUtils.findParentByTagName(
  25522. this.selection.getRange().startContainer,
  25523. "table",
  25524. true
  25525. );
  25526. return tableNode && validData(tableNode) ? 0 : -1;
  25527. }
  25528. }
  25529. },
  25530. inputRule: function(root) {
  25531. utils.each(root.getNodesByTagName("table"), function(tableNode) {
  25532. if (tableNode.getAttr("data-chart") !== undefined) {
  25533. tableNode.setAttr("style");
  25534. }
  25535. });
  25536. },
  25537. outputRule: function(root) {
  25538. utils.each(root.getNodesByTagName("table"), function(tableNode) {
  25539. if (tableNode.getAttr("data-chart") !== undefined) {
  25540. tableNode.setAttr("style", "display: none;");
  25541. }
  25542. });
  25543. }
  25544. };
  25545. function validData(table) {
  25546. var firstRows = null,
  25547. cellCount = 0;
  25548. //行数不够
  25549. if (table.rows.length < 2) {
  25550. return false;
  25551. }
  25552. //列数不够
  25553. if (table.rows[0].cells.length < 2) {
  25554. return false;
  25555. }
  25556. //第一行所有cell必须是th
  25557. firstRows = table.rows[0].cells;
  25558. cellCount = firstRows.length;
  25559. for (var i = 0, cell; (cell = firstRows[i]); i++) {
  25560. if (cell.tagName.toLowerCase() !== "th") {
  25561. return false;
  25562. }
  25563. }
  25564. for (var i = 1, row; (row = table.rows[i]); i++) {
  25565. //每行单元格数不匹配, 返回false
  25566. if (row.cells.length != cellCount) {
  25567. return false;
  25568. }
  25569. //第一列不是th也返回false
  25570. if (row.cells[0].tagName.toLowerCase() !== "th") {
  25571. return false;
  25572. }
  25573. for (var j = 1, cell; (cell = row.cells[j]); j++) {
  25574. var value = utils.trim(cell.innerText || cell.textContent || "");
  25575. value = value
  25576. .replace(new RegExp(UE.dom.domUtils.fillChar, "g"), "")
  25577. .replace(/^\s+|\s+$/g, "");
  25578. //必须是数字
  25579. if (!/^\d*\.?\d+$/.test(value)) {
  25580. return false;
  25581. }
  25582. }
  25583. }
  25584. return true;
  25585. }
  25586. });
  25587. // plugins/section.js
  25588. /**
  25589. * 目录大纲支持插件
  25590. * @file
  25591. * @since 1.3.0
  25592. */
  25593. UE.plugin.register("section", function() {
  25594. /* 目录节点对象 */
  25595. function Section(option) {
  25596. this.tag = "";
  25597. (this.level = -1), (this.dom = null);
  25598. this.nextSection = null;
  25599. this.previousSection = null;
  25600. this.parentSection = null;
  25601. this.startAddress = [];
  25602. this.endAddress = [];
  25603. this.children = [];
  25604. }
  25605. function getSection(option) {
  25606. var section = new Section();
  25607. return utils.extend(section, option);
  25608. }
  25609. function getNodeFromAddress(startAddress, root) {
  25610. var current = root;
  25611. for (var i = 0; i < startAddress.length; i++) {
  25612. if (!current.childNodes) return null;
  25613. current = current.childNodes[startAddress[i]];
  25614. }
  25615. return current;
  25616. }
  25617. var me = this;
  25618. return {
  25619. bindMultiEvents: {
  25620. type: "aftersetcontent afterscencerestore",
  25621. handler: function() {
  25622. me.fireEvent("updateSections");
  25623. }
  25624. },
  25625. bindEvents: {
  25626. /* 初始化、拖拽、粘贴、执行setcontent之后 */
  25627. ready: function() {
  25628. me.fireEvent("updateSections");
  25629. domUtils.on(me.body, "drop paste", function() {
  25630. me.fireEvent("updateSections");
  25631. });
  25632. },
  25633. /* 执行paragraph命令之后 */
  25634. afterexeccommand: function(type, cmd) {
  25635. if (cmd == "paragraph") {
  25636. me.fireEvent("updateSections");
  25637. }
  25638. },
  25639. /* 部分键盘操作,触发updateSections事件 */
  25640. keyup: function(type, e) {
  25641. var me = this,
  25642. range = me.selection.getRange();
  25643. if (range.collapsed != true) {
  25644. me.fireEvent("updateSections");
  25645. } else {
  25646. var keyCode = e.keyCode || e.which;
  25647. if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
  25648. me.fireEvent("updateSections");
  25649. }
  25650. }
  25651. }
  25652. },
  25653. commands: {
  25654. getsections: {
  25655. execCommand: function(cmd, levels) {
  25656. var levelFn = levels || ["h1", "h2", "h3", "h4", "h5", "h6"];
  25657. for (var i = 0; i < levelFn.length; i++) {
  25658. if (typeof levelFn[i] == "string") {
  25659. levelFn[i] = (function(fn) {
  25660. return function(node) {
  25661. return node.tagName == fn.toUpperCase();
  25662. };
  25663. })(levelFn[i]);
  25664. } else if (typeof levelFn[i] != "function") {
  25665. levelFn[i] = function(node) {
  25666. return null;
  25667. };
  25668. }
  25669. }
  25670. function getSectionLevel(node) {
  25671. for (var i = 0; i < levelFn.length; i++) {
  25672. if (levelFn[i](node)) return i;
  25673. }
  25674. return -1;
  25675. }
  25676. var me = this,
  25677. Directory = getSection({ level: -1, title: "root" }),
  25678. previous = Directory;
  25679. function traversal(node, Directory) {
  25680. var level,
  25681. tmpSection = null,
  25682. parent,
  25683. child,
  25684. children = node.childNodes;
  25685. for (var i = 0, len = children.length; i < len; i++) {
  25686. child = children[i];
  25687. level = getSectionLevel(child);
  25688. if (level >= 0) {
  25689. var address = me.selection
  25690. .getRange()
  25691. .selectNode(child)
  25692. .createAddress(true).startAddress,
  25693. current = getSection({
  25694. tag: child.tagName,
  25695. title: child.innerText || child.textContent || "",
  25696. level: level,
  25697. dom: child,
  25698. startAddress: utils.clone(address, []),
  25699. endAddress: utils.clone(address, []),
  25700. children: []
  25701. });
  25702. previous.nextSection = current;
  25703. current.previousSection = previous;
  25704. parent = previous;
  25705. while (level <= parent.level) {
  25706. parent = parent.parentSection;
  25707. }
  25708. current.parentSection = parent;
  25709. parent.children.push(current);
  25710. tmpSection = previous = current;
  25711. } else {
  25712. child.nodeType === 1 && traversal(child, Directory);
  25713. tmpSection &&
  25714. tmpSection.endAddress[tmpSection.endAddress.length - 1]++;
  25715. }
  25716. }
  25717. }
  25718. traversal(me.body, Directory);
  25719. return Directory;
  25720. },
  25721. notNeedUndo: true
  25722. },
  25723. movesection: {
  25724. execCommand: function(cmd, sourceSection, targetSection, isAfter) {
  25725. var me = this,
  25726. targetAddress,
  25727. target;
  25728. if (!sourceSection || !targetSection || targetSection.level == -1)
  25729. return;
  25730. targetAddress = isAfter
  25731. ? targetSection.endAddress
  25732. : targetSection.startAddress;
  25733. target = getNodeFromAddress(targetAddress, me.body);
  25734. /* 判断目标地址是否被源章节包含 */
  25735. if (
  25736. !targetAddress ||
  25737. !target ||
  25738. isContainsAddress(
  25739. sourceSection.startAddress,
  25740. sourceSection.endAddress,
  25741. targetAddress
  25742. )
  25743. )
  25744. return;
  25745. var startNode = getNodeFromAddress(
  25746. sourceSection.startAddress,
  25747. me.body
  25748. ),
  25749. endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
  25750. current,
  25751. nextNode;
  25752. if (isAfter) {
  25753. current = endNode;
  25754. while (
  25755. current &&
  25756. !(
  25757. domUtils.getPosition(startNode, current) &
  25758. domUtils.POSITION_FOLLOWING
  25759. )
  25760. ) {
  25761. nextNode = current.previousSibling;
  25762. domUtils.insertAfter(target, current);
  25763. if (current == startNode) break;
  25764. current = nextNode;
  25765. }
  25766. } else {
  25767. current = startNode;
  25768. while (
  25769. current &&
  25770. !(
  25771. domUtils.getPosition(current, endNode) &
  25772. domUtils.POSITION_FOLLOWING
  25773. )
  25774. ) {
  25775. nextNode = current.nextSibling;
  25776. target.parentNode.insertBefore(current, target);
  25777. if (current == endNode) break;
  25778. current = nextNode;
  25779. }
  25780. }
  25781. me.fireEvent("updateSections");
  25782. /* 获取地址的包含关系 */
  25783. function isContainsAddress(startAddress, endAddress, addressTarget) {
  25784. var isAfterStartAddress = false,
  25785. isBeforeEndAddress = false;
  25786. for (var i = 0; i < startAddress.length; i++) {
  25787. if (i >= addressTarget.length) break;
  25788. if (addressTarget[i] > startAddress[i]) {
  25789. isAfterStartAddress = true;
  25790. break;
  25791. } else if (addressTarget[i] < startAddress[i]) {
  25792. break;
  25793. }
  25794. }
  25795. for (var i = 0; i < endAddress.length; i++) {
  25796. if (i >= addressTarget.length) break;
  25797. if (addressTarget[i] < startAddress[i]) {
  25798. isBeforeEndAddress = true;
  25799. break;
  25800. } else if (addressTarget[i] > startAddress[i]) {
  25801. break;
  25802. }
  25803. }
  25804. return isAfterStartAddress && isBeforeEndAddress;
  25805. }
  25806. }
  25807. },
  25808. deletesection: {
  25809. execCommand: function(cmd, section, keepChildren) {
  25810. var me = this;
  25811. if (!section) return;
  25812. function getNodeFromAddress(startAddress) {
  25813. var current = me.body;
  25814. for (var i = 0; i < startAddress.length; i++) {
  25815. if (!current.childNodes) return null;
  25816. current = current.childNodes[startAddress[i]];
  25817. }
  25818. return current;
  25819. }
  25820. var startNode = getNodeFromAddress(section.startAddress),
  25821. endNode = getNodeFromAddress(section.endAddress),
  25822. current = startNode,
  25823. nextNode;
  25824. if (!keepChildren) {
  25825. while (
  25826. current &&
  25827. domUtils.inDoc(endNode, me.document) &&
  25828. !(
  25829. domUtils.getPosition(current, endNode) &
  25830. domUtils.POSITION_FOLLOWING
  25831. )
  25832. ) {
  25833. nextNode = current.nextSibling;
  25834. domUtils.remove(current);
  25835. current = nextNode;
  25836. }
  25837. } else {
  25838. domUtils.remove(current);
  25839. }
  25840. me.fireEvent("updateSections");
  25841. }
  25842. },
  25843. selectsection: {
  25844. execCommand: function(cmd, section) {
  25845. if (!section && !section.dom) return false;
  25846. var me = this,
  25847. range = me.selection.getRange(),
  25848. address = {
  25849. startAddress: utils.clone(section.startAddress, []),
  25850. endAddress: utils.clone(section.endAddress, [])
  25851. };
  25852. address.endAddress[address.endAddress.length - 1]++;
  25853. range.moveToAddress(address).select().scrollToView();
  25854. return true;
  25855. },
  25856. notNeedUndo: true
  25857. },
  25858. scrolltosection: {
  25859. execCommand: function(cmd, section) {
  25860. if (!section && !section.dom) return false;
  25861. var me = this,
  25862. range = me.selection.getRange(),
  25863. address = {
  25864. startAddress: section.startAddress,
  25865. endAddress: section.endAddress
  25866. };
  25867. address.endAddress[address.endAddress.length - 1]++;
  25868. range.moveToAddress(address).scrollToView();
  25869. return true;
  25870. },
  25871. notNeedUndo: true
  25872. }
  25873. }
  25874. };
  25875. });
  25876. // plugins/simpleupload.js
  25877. /**
  25878. * @description
  25879. * 简单上传:点击按钮,直接选择文件上传
  25880. * @author Jinqn
  25881. * @date 2014-03-31
  25882. */
  25883. UE.plugin.register("simpleupload", function() {
  25884. var me = this,
  25885. isLoaded = false,
  25886. containerBtn;
  25887. function initUploadBtn() {
  25888. var w = containerBtn.offsetWidth || 20,
  25889. h = containerBtn.offsetHeight || 20,
  25890. btnIframe = document.createElement("iframe"),
  25891. btnStyle =
  25892. "display:block;width:" +
  25893. w +
  25894. "px;height:" +
  25895. h +
  25896. "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;";
  25897. domUtils.on(btnIframe, "load", function() {
  25898. var timestrap = (+new Date()).toString(36),
  25899. wrapper,
  25900. btnIframeDoc,
  25901. btnIframeBody;
  25902. btnIframeDoc =
  25903. btnIframe.contentDocument || btnIframe.contentWindow.document;
  25904. btnIframeBody = btnIframeDoc.body;
  25905. wrapper = btnIframeDoc.createElement("div");
  25906. wrapper.innerHTML =
  25907. '<form id="edui_form_' +
  25908. timestrap +
  25909. '" target="edui_iframe_' +
  25910. timestrap +
  25911. '" method="POST" enctype="multipart/form-data" action="' +
  25912. me.getOpt("serverUrl") +
  25913. '" ' +
  25914. 'style="' +
  25915. btnStyle +
  25916. '">' +
  25917. '<input id="edui_input_' +
  25918. timestrap +
  25919. '" type="file" accept="image/*" name="' +
  25920. me.options.imageFieldName +
  25921. '" ' +
  25922. 'style="' +
  25923. btnStyle +
  25924. '">' +
  25925. "</form>" +
  25926. '<iframe id="edui_iframe_' +
  25927. timestrap +
  25928. '" name="edui_iframe_' +
  25929. timestrap +
  25930. '" style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>';
  25931. wrapper.className = "edui-" + me.options.theme;
  25932. wrapper.id = me.ui.id + "_iframeupload";
  25933. btnIframeBody.style.cssText = btnStyle;
  25934. btnIframeBody.style.width = w + "px";
  25935. btnIframeBody.style.height = h + "px";
  25936. btnIframeBody.appendChild(wrapper);
  25937. if (btnIframeBody.parentNode) {
  25938. btnIframeBody.parentNode.style.width = w + "px";
  25939. btnIframeBody.parentNode.style.height = w + "px";
  25940. }
  25941. var form = btnIframeDoc.getElementById("edui_form_" + timestrap);
  25942. var input = btnIframeDoc.getElementById("edui_input_" + timestrap);
  25943. var iframe = btnIframeDoc.getElementById("edui_iframe_" + timestrap);
  25944. domUtils.on(input, "change", function() {
  25945. if (!input.value) return;
  25946. var loadingId = "loading_" + (+new Date()).toString(36);
  25947. var params =
  25948. utils.serializeParam(me.queryCommandValue("serverparam")) || "";
  25949. var imageActionUrl = me.getActionUrl(me.getOpt("imageActionName"));
  25950. var allowFiles = me.getOpt("imageAllowFiles");
  25951. me.focus();
  25952. me.execCommand(
  25953. "inserthtml",
  25954. '<img class="loadingclass" id="' +
  25955. loadingId +
  25956. '" src="' +
  25957. me.options.themePath +
  25958. me.options.theme +
  25959. '/images/spacer.gif">'
  25960. );
  25961. function callback() {
  25962. try {
  25963. var link,
  25964. json,
  25965. loader,
  25966. body = (iframe.contentDocument || iframe.contentWindow.document)
  25967. .body,
  25968. result = body.innerText || body.textContent || "";
  25969. json = new Function("return " + result)();
  25970. link = me.options.imageUrlPrefix + json.url;
  25971. if (json.state == "SUCCESS" && json.url) {
  25972. loader = me.document.getElementById(loadingId);
  25973. domUtils.removeClasses(loader, "loadingclass");
  25974. domUtils.on(loader,'load',function(){
  25975. me.fireEvent('contentchange');
  25976. });
  25977. loader.setAttribute("src", link);
  25978. loader.setAttribute("_src", link);
  25979. loader.setAttribute("alt", json.original || "");
  25980. loader.removeAttribute("id");
  25981. } else {
  25982. showErrorLoader && showErrorLoader(json.state);
  25983. }
  25984. } catch (er) {
  25985. showErrorLoader &&
  25986. showErrorLoader(me.getLang("simpleupload.loadError"));
  25987. }
  25988. form.reset();
  25989. domUtils.un(iframe, "load", callback);
  25990. }
  25991. function showErrorLoader(title) {
  25992. if (loadingId) {
  25993. var loader = me.document.getElementById(loadingId);
  25994. loader && domUtils.remove(loader);
  25995. me.fireEvent("showmessage", {
  25996. id: loadingId,
  25997. content: title,
  25998. type: "error",
  25999. timeout: 4000
  26000. });
  26001. }
  26002. }
  26003. /* 判断后端配置是否没有加载成功 */
  26004. if (!me.getOpt("imageActionName")) {
  26005. errorHandler(me.getLang("autoupload.errorLoadConfig"));
  26006. return;
  26007. }
  26008. // 判断文件格式是否错误
  26009. var filename = input.value,
  26010. fileext = filename ? filename.substr(filename.lastIndexOf(".")) : "";
  26011. if (
  26012. !fileext ||
  26013. (allowFiles &&
  26014. (allowFiles.join("") + ".").indexOf(fileext.toLowerCase() + ".") ==
  26015. -1)
  26016. ) {
  26017. showErrorLoader(me.getLang("simpleupload.exceedTypeError"));
  26018. return;
  26019. }
  26020. domUtils.on(iframe, "load", callback);
  26021. form.action = utils.formatUrl(
  26022. imageActionUrl +
  26023. (imageActionUrl.indexOf("?") == -1 ? "?" : "&") +
  26024. params
  26025. );
  26026. form.submit();
  26027. });
  26028. var stateTimer;
  26029. me.addListener("selectionchange", function() {
  26030. clearTimeout(stateTimer);
  26031. stateTimer = setTimeout(function() {
  26032. var state = me.queryCommandState("simpleupload");
  26033. if (state == -1) {
  26034. input.disabled = "disabled";
  26035. } else {
  26036. input.disabled = false;
  26037. }
  26038. }, 400);
  26039. });
  26040. isLoaded = true;
  26041. });
  26042. btnIframe.style.cssText = btnStyle;
  26043. containerBtn.appendChild(btnIframe);
  26044. }
  26045. return {
  26046. bindEvents: {
  26047. ready: function() {
  26048. //设置loading的样式
  26049. utils.cssRule(
  26050. "loading",
  26051. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  26052. this.options.themePath +
  26053. this.options.theme +
  26054. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n" +
  26055. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  26056. this.options.themePath +
  26057. this.options.theme +
  26058. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  26059. "}",
  26060. this.document
  26061. );
  26062. },
  26063. /* 初始化简单上传按钮 */
  26064. simpleuploadbtnready: function(type, container) {
  26065. containerBtn = container;
  26066. me.afterConfigReady(initUploadBtn);
  26067. }
  26068. },
  26069. outputRule: function(root) {
  26070. utils.each(root.getNodesByTagName("img"), function(n) {
  26071. if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr("class"))) {
  26072. n.parentNode.removeChild(n);
  26073. }
  26074. });
  26075. },
  26076. commands: {
  26077. simpleupload: {
  26078. queryCommandState: function() {
  26079. return isLoaded ? 0 : -1;
  26080. }
  26081. }
  26082. }
  26083. };
  26084. });
  26085. // plugins/serverparam.js
  26086. /**
  26087. * 服务器提交的额外参数列表设置插件
  26088. * @file
  26089. * @since 1.2.6.1
  26090. */
  26091. UE.plugin.register("serverparam", function() {
  26092. var me = this,
  26093. serverParam = {};
  26094. return {
  26095. commands: {
  26096. /**
  26097. * 修改服务器提交的额外参数列表,清除所有项
  26098. * @command serverparam
  26099. * @method execCommand
  26100. * @param { String } cmd 命令字符串
  26101. * @example
  26102. * ```javascript
  26103. * editor.execCommand('serverparam');
  26104. * editor.queryCommandValue('serverparam'); //返回空
  26105. * ```
  26106. */
  26107. /**
  26108. * 修改服务器提交的额外参数列表,删除指定项
  26109. * @command serverparam
  26110. * @method execCommand
  26111. * @param { String } cmd 命令字符串
  26112. * @param { String } key 要清除的属性
  26113. * @example
  26114. * ```javascript
  26115. * editor.execCommand('serverparam', 'name'); //删除属性name
  26116. * ```
  26117. */
  26118. /**
  26119. * 修改服务器提交的额外参数列表,使用键值添加项
  26120. * @command serverparam
  26121. * @method execCommand
  26122. * @param { String } cmd 命令字符串
  26123. * @param { String } key 要添加的属性
  26124. * @param { String } value 要添加属性的值
  26125. * @example
  26126. * ```javascript
  26127. * editor.execCommand('serverparam', 'name', 'hello');
  26128. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  26129. * ```
  26130. */
  26131. /**
  26132. * 修改服务器提交的额外参数列表,传入键值对对象添加多项
  26133. * @command serverparam
  26134. * @method execCommand
  26135. * @param { String } cmd 命令字符串
  26136. * @param { Object } key 传入的键值对对象
  26137. * @example
  26138. * ```javascript
  26139. * editor.execCommand('serverparam', {'name': 'hello'});
  26140. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  26141. * ```
  26142. */
  26143. /**
  26144. * 修改服务器提交的额外参数列表,使用自定义函数添加多项
  26145. * @command serverparam
  26146. * @method execCommand
  26147. * @param { String } cmd 命令字符串
  26148. * @param { Function } key 自定义获取参数的函数
  26149. * @example
  26150. * ```javascript
  26151. * editor.execCommand('serverparam', function(editor){
  26152. * return {'key': 'value'};
  26153. * });
  26154. * editor.queryCommandValue('serverparam'); //返回对象 {'key': 'value'}
  26155. * ```
  26156. */
  26157. /**
  26158. * 获取服务器提交的额外参数列表
  26159. * @command serverparam
  26160. * @method queryCommandValue
  26161. * @param { String } cmd 命令字符串
  26162. * @example
  26163. * ```javascript
  26164. * editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'}
  26165. * ```
  26166. */
  26167. serverparam: {
  26168. execCommand: function(cmd, key, value) {
  26169. if (key === undefined || key === null) {
  26170. //不传参数,清空列表
  26171. serverParam = {};
  26172. } else if (utils.isString(key)) {
  26173. //传入键值
  26174. if (value === undefined || value === null) {
  26175. delete serverParam[key];
  26176. } else {
  26177. serverParam[key] = value;
  26178. }
  26179. } else if (utils.isObject(key)) {
  26180. //传入对象,覆盖列表项
  26181. utils.extend(serverParam, key, false);
  26182. } else if (utils.isFunction(key)) {
  26183. //传入函数,添加列表项
  26184. utils.extend(serverParam, key(), false);
  26185. }
  26186. },
  26187. queryCommandValue: function() {
  26188. return serverParam || {};
  26189. }
  26190. }
  26191. }
  26192. };
  26193. });
  26194. // plugins/insertfile.js
  26195. /**
  26196. * 插入附件
  26197. */
  26198. UE.plugin.register("insertfile", function() {
  26199. var me = this;
  26200. function getFileIcon(url) {
  26201. var ext = url.substr(url.lastIndexOf(".") + 1).toLowerCase(),
  26202. maps = {
  26203. rar: "icon_rar.gif",
  26204. zip: "icon_rar.gif",
  26205. tar: "icon_rar.gif",
  26206. gz: "icon_rar.gif",
  26207. bz2: "icon_rar.gif",
  26208. doc: "icon_doc.gif",
  26209. docx: "icon_doc.gif",
  26210. pdf: "icon_pdf.gif",
  26211. mp3: "icon_mp3.gif",
  26212. xls: "icon_xls.gif",
  26213. chm: "icon_chm.gif",
  26214. ppt: "icon_ppt.gif",
  26215. pptx: "icon_ppt.gif",
  26216. avi: "icon_mv.gif",
  26217. rmvb: "icon_mv.gif",
  26218. wmv: "icon_mv.gif",
  26219. flv: "icon_mv.gif",
  26220. swf: "icon_mv.gif",
  26221. rm: "icon_mv.gif",
  26222. exe: "icon_exe.gif",
  26223. psd: "icon_psd.gif",
  26224. txt: "icon_txt.gif",
  26225. jpg: "icon_jpg.gif",
  26226. png: "icon_jpg.gif",
  26227. jpeg: "icon_jpg.gif",
  26228. gif: "icon_jpg.gif",
  26229. ico: "icon_jpg.gif",
  26230. bmp: "icon_jpg.gif"
  26231. };
  26232. return maps[ext] ? maps[ext] : maps["txt"];
  26233. }
  26234. return {
  26235. commands: {
  26236. insertfile: {
  26237. execCommand: function(command, filelist) {
  26238. filelist = utils.isArray(filelist) ? filelist : [filelist];
  26239. if (me.fireEvent("beforeinsertfile", filelist) === true) {
  26240. return;
  26241. }
  26242. var i,
  26243. item,
  26244. icon,
  26245. title,
  26246. html = "",
  26247. URL = me.getOpt("UEDITOR_HOME_URL"),
  26248. iconDir =
  26249. URL +
  26250. (URL.substr(URL.length - 1) == "/" ? "" : "/") +
  26251. "dialogs/attachment/fileTypeImages/";
  26252. for (i = 0; i < filelist.length; i++) {
  26253. item = filelist[i];
  26254. icon = iconDir + getFileIcon(item.url);
  26255. title =
  26256. item.title || item.url.substr(item.url.lastIndexOf("/") + 1);
  26257. html +=
  26258. '<p style="line-height: 16px;">' +
  26259. '<img style="vertical-align: middle; margin-right: 2px;" src="' +
  26260. icon +
  26261. '" _src="' +
  26262. icon +
  26263. '" />' +
  26264. '<a style="font-size:12px; color:#0066cc;" href="' +
  26265. item.url +
  26266. '" title="' +
  26267. title +
  26268. '">' +
  26269. title +
  26270. "</a>" +
  26271. "</p>";
  26272. }
  26273. me.execCommand("insertHtml", html);
  26274. me.fireEvent("afterinsertfile", filelist);
  26275. }
  26276. }
  26277. }
  26278. };
  26279. });
  26280. // plugins/xssFilter.js
  26281. /**
  26282. * @file xssFilter.js
  26283. * @desc xss过滤器
  26284. * @author robbenmu
  26285. */
  26286. UE.plugins.xssFilter = function() {
  26287. var config = UEDITOR_CONFIG;
  26288. var whitList = config.whitList;
  26289. function filter(node) {
  26290. var tagName = node.tagName;
  26291. var attrs = node.attrs;
  26292. if (!whitList.hasOwnProperty(tagName)) {
  26293. node.parentNode.removeChild(node);
  26294. return false;
  26295. }
  26296. UE.utils.each(attrs, function (val, key) {
  26297. if (whitList[tagName].indexOf(key) === -1) {
  26298. node.setAttr(key);
  26299. }
  26300. });
  26301. }
  26302. // 添加inserthtml\paste等操作用的过滤规则
  26303. if (whitList && config.xssFilterRules) {
  26304. this.options.filterRules = function () {
  26305. var result = {};
  26306. UE.utils.each(whitList, function(val, key) {
  26307. result[key] = function (node) {
  26308. return filter(node);
  26309. };
  26310. });
  26311. return result;
  26312. }();
  26313. }
  26314. var tagList = [];
  26315. UE.utils.each(whitList, function (val, key) {
  26316. tagList.push(key);
  26317. });
  26318. // 添加input过滤规则
  26319. //
  26320. if (whitList && config.inputXssFilter) {
  26321. this.addInputRule(function (root) {
  26322. root.traversal(function(node) {
  26323. if (node.type !== 'element') {
  26324. return false;
  26325. }
  26326. filter(node);
  26327. });
  26328. });
  26329. }
  26330. // 添加output过滤规则
  26331. //
  26332. if (whitList && config.outputXssFilter) {
  26333. this.addOutputRule(function (root) {
  26334. root.traversal(function(node) {
  26335. if (node.type !== 'element') {
  26336. return false;
  26337. }
  26338. filter(node);
  26339. });
  26340. });
  26341. }
  26342. };
  26343. // ui/ui.js
  26344. var baidu = baidu || {};
  26345. baidu.editor = baidu.editor || {};
  26346. UE.ui = baidu.editor.ui = {};
  26347. // ui/uiutils.js
  26348. ;(function() {
  26349. var browser = baidu.editor.browser,
  26350. domUtils = baidu.editor.dom.domUtils;
  26351. var magic = "$EDITORUI";
  26352. var root = (window[magic] = {});
  26353. var uidMagic = "ID" + magic;
  26354. var uidCount = 0;
  26355. var uiUtils = (baidu.editor.ui.uiUtils = {
  26356. uid: function(obj) {
  26357. return obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount;
  26358. },
  26359. hook: function(fn, callback) {
  26360. var dg;
  26361. if (fn && fn._callbacks) {
  26362. dg = fn;
  26363. } else {
  26364. dg = function() {
  26365. var q;
  26366. if (fn) {
  26367. q = fn.apply(this, arguments);
  26368. }
  26369. var callbacks = dg._callbacks;
  26370. var k = callbacks.length;
  26371. while (k--) {
  26372. var r = callbacks[k].apply(this, arguments);
  26373. if (q === undefined) {
  26374. q = r;
  26375. }
  26376. }
  26377. return q;
  26378. };
  26379. dg._callbacks = [];
  26380. }
  26381. dg._callbacks.push(callback);
  26382. return dg;
  26383. },
  26384. createElementByHtml: function(html) {
  26385. var el = document.createElement("div");
  26386. el.innerHTML = html;
  26387. el = el.firstChild;
  26388. el.parentNode.removeChild(el);
  26389. return el;
  26390. },
  26391. getViewportElement: function() {
  26392. return browser.ie && browser.quirks
  26393. ? document.body
  26394. : document.documentElement;
  26395. },
  26396. getClientRect: function(element) {
  26397. var bcr;
  26398. //trace IE6下在控制编辑器显隐时可能会报错,catch一下
  26399. try {
  26400. bcr = element.getBoundingClientRect();
  26401. } catch (e) {
  26402. bcr = { left: 0, top: 0, height: 0, width: 0 };
  26403. }
  26404. var rect = {
  26405. left: Math.round(bcr.left),
  26406. top: Math.round(bcr.top),
  26407. height: Math.round(bcr.bottom - bcr.top),
  26408. width: Math.round(bcr.right - bcr.left)
  26409. };
  26410. var doc;
  26411. while (
  26412. (doc = element.ownerDocument) !== document &&
  26413. (element = domUtils.getWindow(doc).frameElement)
  26414. ) {
  26415. bcr = element.getBoundingClientRect();
  26416. rect.left += bcr.left;
  26417. rect.top += bcr.top;
  26418. }
  26419. rect.bottom = rect.top + rect.height;
  26420. rect.right = rect.left + rect.width;
  26421. return rect;
  26422. },
  26423. getViewportRect: function() {
  26424. var viewportEl = uiUtils.getViewportElement();
  26425. var width = (window.innerWidth || viewportEl.clientWidth) | 0;
  26426. var height = (window.innerHeight || viewportEl.clientHeight) | 0;
  26427. return {
  26428. left: 0,
  26429. top: 0,
  26430. height: height,
  26431. width: width,
  26432. bottom: height,
  26433. right: width
  26434. };
  26435. },
  26436. setViewportOffset: function(element, offset) {
  26437. var rect;
  26438. var fixedLayer = uiUtils.getFixedLayer();
  26439. if (element.parentNode === fixedLayer) {
  26440. element.style.left = offset.left + "px";
  26441. element.style.top = offset.top + "px";
  26442. } else {
  26443. domUtils.setViewportOffset(element, offset);
  26444. }
  26445. },
  26446. getEventOffset: function(evt) {
  26447. var el = evt.target || evt.srcElement;
  26448. var rect = uiUtils.getClientRect(el);
  26449. var offset = uiUtils.getViewportOffsetByEvent(evt);
  26450. return {
  26451. left: offset.left - rect.left,
  26452. top: offset.top - rect.top
  26453. };
  26454. },
  26455. getViewportOffsetByEvent: function(evt) {
  26456. var el = evt.target || evt.srcElement;
  26457. var frameEl = domUtils.getWindow(el).frameElement;
  26458. var offset = {
  26459. left: evt.clientX,
  26460. top: evt.clientY
  26461. };
  26462. if (frameEl && el.ownerDocument !== document) {
  26463. var rect = uiUtils.getClientRect(frameEl);
  26464. offset.left += rect.left;
  26465. offset.top += rect.top;
  26466. }
  26467. return offset;
  26468. },
  26469. setGlobal: function(id, obj) {
  26470. root[id] = obj;
  26471. return magic + '["' + id + '"]';
  26472. },
  26473. unsetGlobal: function(id) {
  26474. delete root[id];
  26475. },
  26476. copyAttributes: function(tgt, src) {
  26477. var attributes = src.attributes;
  26478. var k = attributes.length;
  26479. while (k--) {
  26480. var attrNode = attributes[k];
  26481. if (
  26482. attrNode.nodeName != "style" &&
  26483. attrNode.nodeName != "class" &&
  26484. (!browser.ie || attrNode.specified)
  26485. ) {
  26486. tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue);
  26487. }
  26488. }
  26489. if (src.className) {
  26490. domUtils.addClass(tgt, src.className);
  26491. }
  26492. if (src.style.cssText) {
  26493. tgt.style.cssText += ";" + src.style.cssText;
  26494. }
  26495. },
  26496. removeStyle: function(el, styleName) {
  26497. if (el.style.removeProperty) {
  26498. el.style.removeProperty(styleName);
  26499. } else if (el.style.removeAttribute) {
  26500. el.style.removeAttribute(styleName);
  26501. } else throw "";
  26502. },
  26503. contains: function(elA, elB) {
  26504. return (
  26505. elA &&
  26506. elB &&
  26507. (elA === elB
  26508. ? false
  26509. : elA.contains
  26510. ? elA.contains(elB)
  26511. : elA.compareDocumentPosition(elB) & 16)
  26512. );
  26513. },
  26514. startDrag: function(evt, callbacks, doc) {
  26515. var doc = doc || document;
  26516. var startX = evt.clientX;
  26517. var startY = evt.clientY;
  26518. function handleMouseMove(evt) {
  26519. var x = evt.clientX - startX;
  26520. var y = evt.clientY - startY;
  26521. callbacks.ondragmove(x, y, evt);
  26522. if (evt.stopPropagation) {
  26523. evt.stopPropagation();
  26524. } else {
  26525. evt.cancelBubble = true;
  26526. }
  26527. }
  26528. if (doc.addEventListener) {
  26529. function handleMouseUp(evt) {
  26530. doc.removeEventListener("mousemove", handleMouseMove, true);
  26531. doc.removeEventListener("mouseup", handleMouseUp, true);
  26532. window.removeEventListener("mouseup", handleMouseUp, true);
  26533. callbacks.ondragstop();
  26534. }
  26535. doc.addEventListener("mousemove", handleMouseMove, true);
  26536. doc.addEventListener("mouseup", handleMouseUp, true);
  26537. window.addEventListener("mouseup", handleMouseUp, true);
  26538. evt.preventDefault();
  26539. } else {
  26540. var elm = evt.srcElement;
  26541. elm.setCapture();
  26542. function releaseCaptrue() {
  26543. elm.releaseCapture();
  26544. elm.detachEvent("onmousemove", handleMouseMove);
  26545. elm.detachEvent("onmouseup", releaseCaptrue);
  26546. elm.detachEvent("onlosecaptrue", releaseCaptrue);
  26547. callbacks.ondragstop();
  26548. }
  26549. elm.attachEvent("onmousemove", handleMouseMove);
  26550. elm.attachEvent("onmouseup", releaseCaptrue);
  26551. elm.attachEvent("onlosecaptrue", releaseCaptrue);
  26552. evt.returnValue = false;
  26553. }
  26554. callbacks.ondragstart();
  26555. },
  26556. getFixedLayer: function() {
  26557. var layer = document.getElementById("edui_fixedlayer");
  26558. if (layer == null) {
  26559. layer = document.createElement("div");
  26560. layer.id = "edui_fixedlayer";
  26561. document.body.appendChild(layer);
  26562. if (browser.ie && browser.version <= 8) {
  26563. layer.style.position = "absolute";
  26564. bindFixedLayer();
  26565. setTimeout(updateFixedOffset);
  26566. } else {
  26567. layer.style.position = "fixed";
  26568. }
  26569. layer.style.left = "0";
  26570. layer.style.top = "0";
  26571. layer.style.width = "0";
  26572. layer.style.height = "0";
  26573. }
  26574. return layer;
  26575. },
  26576. makeUnselectable: function(element) {
  26577. if (browser.opera || (browser.ie && browser.version < 9)) {
  26578. element.unselectable = "on";
  26579. if (element.hasChildNodes()) {
  26580. for (var i = 0; i < element.childNodes.length; i++) {
  26581. if (element.childNodes[i].nodeType == 1) {
  26582. uiUtils.makeUnselectable(element.childNodes[i]);
  26583. }
  26584. }
  26585. }
  26586. } else {
  26587. if (element.style.MozUserSelect !== undefined) {
  26588. element.style.MozUserSelect = "none";
  26589. } else if (element.style.WebkitUserSelect !== undefined) {
  26590. element.style.WebkitUserSelect = "none";
  26591. } else if (element.style.KhtmlUserSelect !== undefined) {
  26592. element.style.KhtmlUserSelect = "none";
  26593. }
  26594. }
  26595. }
  26596. });
  26597. function updateFixedOffset() {
  26598. var layer = document.getElementById("edui_fixedlayer");
  26599. uiUtils.setViewportOffset(layer, {
  26600. left: 0,
  26601. top: 0
  26602. });
  26603. // layer.style.display = 'none';
  26604. // layer.style.display = 'block';
  26605. //#trace: 1354
  26606. // setTimeout(updateFixedOffset);
  26607. }
  26608. function bindFixedLayer(adjOffset) {
  26609. domUtils.on(window, "scroll", updateFixedOffset);
  26610. domUtils.on(
  26611. window,
  26612. "resize",
  26613. baidu.editor.utils.defer(updateFixedOffset, 0, true)
  26614. );
  26615. }
  26616. })();
  26617. // ui/uibase.js
  26618. ;(function() {
  26619. var utils = baidu.editor.utils,
  26620. uiUtils = baidu.editor.ui.uiUtils,
  26621. EventBase = baidu.editor.EventBase,
  26622. UIBase = (baidu.editor.ui.UIBase = function() {});
  26623. UIBase.prototype = {
  26624. className: "",
  26625. uiName: "",
  26626. initOptions: function(options) {
  26627. var me = this;
  26628. for (var k in options) {
  26629. me[k] = options[k];
  26630. }
  26631. this.id = this.id || "edui" + uiUtils.uid();
  26632. },
  26633. initUIBase: function() {
  26634. this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this));
  26635. },
  26636. render: function(holder) {
  26637. var html = this.renderHtml();
  26638. var el = uiUtils.createElementByHtml(html);
  26639. //by xuheng 给每个node添加class
  26640. var list = domUtils.getElementsByTagName(el, "*");
  26641. var theme = "edui-" + (this.theme || this.editor.options.theme);
  26642. var layer = document.getElementById("edui_fixedlayer");
  26643. for (var i = 0, node; (node = list[i++]); ) {
  26644. domUtils.addClass(node, theme);
  26645. }
  26646. domUtils.addClass(el, theme);
  26647. if (layer) {
  26648. layer.className = "";
  26649. domUtils.addClass(layer, theme);
  26650. }
  26651. var seatEl = this.getDom();
  26652. if (seatEl != null) {
  26653. seatEl.parentNode.replaceChild(el, seatEl);
  26654. uiUtils.copyAttributes(el, seatEl);
  26655. } else {
  26656. if (typeof holder == "string") {
  26657. holder = document.getElementById(holder);
  26658. }
  26659. holder = holder || uiUtils.getFixedLayer();
  26660. domUtils.addClass(holder, theme);
  26661. holder.appendChild(el);
  26662. }
  26663. this.postRender();
  26664. },
  26665. getDom: function(name) {
  26666. if (!name) {
  26667. return document.getElementById(this.id);
  26668. } else {
  26669. return document.getElementById(this.id + "_" + name);
  26670. }
  26671. },
  26672. postRender: function() {
  26673. this.fireEvent("postrender");
  26674. },
  26675. getHtmlTpl: function() {
  26676. return "";
  26677. },
  26678. formatHtml: function(tpl) {
  26679. var prefix = "edui-" + this.uiName;
  26680. return tpl
  26681. .replace(/##/g, this.id)
  26682. .replace(/%%-/g, this.uiName ? prefix + "-" : "")
  26683. .replace(/%%/g, (this.uiName ? prefix : "") + " " + this.className)
  26684. .replace(/\$\$/g, this._globalKey);
  26685. },
  26686. renderHtml: function() {
  26687. return this.formatHtml(this.getHtmlTpl());
  26688. },
  26689. dispose: function() {
  26690. var box = this.getDom();
  26691. if (box) baidu.editor.dom.domUtils.remove(box);
  26692. uiUtils.unsetGlobal(this.id);
  26693. }
  26694. };
  26695. utils.inherits(UIBase, EventBase);
  26696. })();
  26697. // ui/separator.js
  26698. ;(function() {
  26699. var utils = baidu.editor.utils,
  26700. UIBase = baidu.editor.ui.UIBase,
  26701. Separator = (baidu.editor.ui.Separator = function(options) {
  26702. this.initOptions(options);
  26703. this.initSeparator();
  26704. });
  26705. Separator.prototype = {
  26706. uiName: "separator",
  26707. initSeparator: function() {
  26708. this.initUIBase();
  26709. },
  26710. getHtmlTpl: function() {
  26711. return '<div id="##" class="edui-box %%"></div>';
  26712. }
  26713. };
  26714. utils.inherits(Separator, UIBase);
  26715. })();
  26716. // ui/mask.js
  26717. ///import core
  26718. ///import uicore
  26719. ;(function() {
  26720. var utils = baidu.editor.utils,
  26721. domUtils = baidu.editor.dom.domUtils,
  26722. UIBase = baidu.editor.ui.UIBase,
  26723. uiUtils = baidu.editor.ui.uiUtils;
  26724. var Mask = (baidu.editor.ui.Mask = function(options) {
  26725. this.initOptions(options);
  26726. this.initUIBase();
  26727. });
  26728. Mask.prototype = {
  26729. getHtmlTpl: function() {
  26730. return '<div id="##" class="edui-mask %%" onclick="return $$._onClick(event, this);" onmousedown="return $$._onMouseDown(event, this);"></div>';
  26731. },
  26732. postRender: function() {
  26733. var me = this;
  26734. domUtils.on(window, "resize", function() {
  26735. setTimeout(function() {
  26736. if (!me.isHidden()) {
  26737. me._fill();
  26738. }
  26739. });
  26740. });
  26741. },
  26742. show: function(zIndex) {
  26743. this._fill();
  26744. this.getDom().style.display = "";
  26745. this.getDom().style.zIndex = zIndex;
  26746. },
  26747. hide: function() {
  26748. this.getDom().style.display = "none";
  26749. this.getDom().style.zIndex = "";
  26750. },
  26751. isHidden: function() {
  26752. return this.getDom().style.display == "none";
  26753. },
  26754. _onMouseDown: function() {
  26755. return false;
  26756. },
  26757. _onClick: function(e, target) {
  26758. this.fireEvent("click", e, target);
  26759. },
  26760. _fill: function() {
  26761. var el = this.getDom();
  26762. var vpRect = uiUtils.getViewportRect();
  26763. el.style.width = vpRect.width + "px";
  26764. el.style.height = vpRect.height + "px";
  26765. }
  26766. };
  26767. utils.inherits(Mask, UIBase);
  26768. })();
  26769. // ui/popup.js
  26770. ///import core
  26771. ///import uicore
  26772. ;(function() {
  26773. var utils = baidu.editor.utils,
  26774. uiUtils = baidu.editor.ui.uiUtils,
  26775. domUtils = baidu.editor.dom.domUtils,
  26776. UIBase = baidu.editor.ui.UIBase,
  26777. Popup = (baidu.editor.ui.Popup = function(options) {
  26778. this.initOptions(options);
  26779. this.initPopup();
  26780. });
  26781. var allPopups = [];
  26782. function closeAllPopup(evt, el) {
  26783. for (var i = 0; i < allPopups.length; i++) {
  26784. var pop = allPopups[i];
  26785. if (!pop.isHidden()) {
  26786. if (pop.queryAutoHide(el) !== false) {
  26787. if (
  26788. evt &&
  26789. /scroll/gi.test(evt.type) &&
  26790. pop.className == "edui-wordpastepop"
  26791. )
  26792. return;
  26793. pop.hide();
  26794. }
  26795. }
  26796. }
  26797. if (allPopups.length) pop.editor.fireEvent("afterhidepop");
  26798. }
  26799. Popup.postHide = closeAllPopup;
  26800. var ANCHOR_CLASSES = [
  26801. "edui-anchor-topleft",
  26802. "edui-anchor-topright",
  26803. "edui-anchor-bottomleft",
  26804. "edui-anchor-bottomright"
  26805. ];
  26806. Popup.prototype = {
  26807. SHADOW_RADIUS: 5,
  26808. content: null,
  26809. _hidden: false,
  26810. autoRender: true,
  26811. canSideLeft: true,
  26812. canSideUp: true,
  26813. initPopup: function() {
  26814. this.initUIBase();
  26815. allPopups.push(this);
  26816. },
  26817. getHtmlTpl: function() {
  26818. return (
  26819. '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
  26820. ' <div id="##_body" class="edui-popup-body">' +
  26821. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  26822. ' <div class="edui-shadow"></div>' +
  26823. ' <div id="##_content" class="edui-popup-content">' +
  26824. this.getContentHtmlTpl() +
  26825. " </div>" +
  26826. " </div>" +
  26827. "</div>"
  26828. );
  26829. },
  26830. getContentHtmlTpl: function() {
  26831. if (this.content) {
  26832. if (typeof this.content == "string") {
  26833. return this.content;
  26834. }
  26835. return this.content.renderHtml();
  26836. } else {
  26837. return "";
  26838. }
  26839. },
  26840. _UIBase_postRender: UIBase.prototype.postRender,
  26841. postRender: function() {
  26842. if (this.content instanceof UIBase) {
  26843. this.content.postRender();
  26844. }
  26845. //捕获鼠标滚轮
  26846. if (this.captureWheel && !this.captured) {
  26847. this.captured = true;
  26848. var winHeight =
  26849. (document.documentElement.clientHeight ||
  26850. document.body.clientHeight) - 80,
  26851. _height = this.getDom().offsetHeight,
  26852. _top = uiUtils.getClientRect(this.combox.getDom()).top,
  26853. content = this.getDom("content"),
  26854. ifr = this.getDom("body").getElementsByTagName("iframe"),
  26855. me = this;
  26856. ifr.length && (ifr = ifr[0]);
  26857. while (_top + _height > winHeight) {
  26858. _height -= 30;
  26859. }
  26860. content.style.height = _height + "px";
  26861. //同步更改iframe高度
  26862. ifr && (ifr.style.height = _height + "px");
  26863. //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
  26864. if (window.XMLHttpRequest) {
  26865. domUtils.on(
  26866. content,
  26867. "onmousewheel" in document.body ? "mousewheel" : "DOMMouseScroll",
  26868. function(e) {
  26869. if (e.preventDefault) {
  26870. e.preventDefault();
  26871. } else {
  26872. e.returnValue = false;
  26873. }
  26874. if (e.wheelDelta) {
  26875. content.scrollTop -= e.wheelDelta / 120 * 60;
  26876. } else {
  26877. content.scrollTop -= e.detail / -3 * 60;
  26878. }
  26879. }
  26880. );
  26881. } else {
  26882. //ie6
  26883. domUtils.on(this.getDom(), "mousewheel", function(e) {
  26884. e.returnValue = false;
  26885. me.getDom("content").scrollTop -= e.wheelDelta / 120 * 60;
  26886. });
  26887. }
  26888. }
  26889. this.fireEvent("postRenderAfter");
  26890. this.hide(true);
  26891. this._UIBase_postRender();
  26892. },
  26893. _doAutoRender: function() {
  26894. if (!this.getDom() && this.autoRender) {
  26895. this.render();
  26896. }
  26897. },
  26898. mesureSize: function() {
  26899. var box = this.getDom("content");
  26900. return uiUtils.getClientRect(box);
  26901. },
  26902. fitSize: function() {
  26903. if (this.captureWheel && this.sized) {
  26904. return this.__size;
  26905. }
  26906. this.sized = true;
  26907. var popBodyEl = this.getDom("body");
  26908. popBodyEl.style.width = "";
  26909. popBodyEl.style.height = "";
  26910. var size = this.mesureSize();
  26911. if (this.captureWheel) {
  26912. popBodyEl.style.width = -(-20 - size.width) + "px";
  26913. var height = parseInt(this.getDom("content").style.height, 10);
  26914. !window.isNaN(height) && (size.height = height);
  26915. } else {
  26916. popBodyEl.style.width = size.width + "px";
  26917. }
  26918. popBodyEl.style.height = size.height + "px";
  26919. this.__size = size;
  26920. this.captureWheel && (this.getDom("content").style.overflow = "auto");
  26921. return size;
  26922. },
  26923. showAnchor: function(element, hoz) {
  26924. this.showAnchorRect(uiUtils.getClientRect(element), hoz);
  26925. },
  26926. showAnchorRect: function(rect, hoz, adj) {
  26927. this._doAutoRender();
  26928. var vpRect = uiUtils.getViewportRect();
  26929. this.getDom().style.visibility = "hidden";
  26930. this._show();
  26931. var popSize = this.fitSize();
  26932. var sideLeft, sideUp, left, top;
  26933. if (hoz) {
  26934. sideLeft =
  26935. this.canSideLeft &&
  26936. (rect.right + popSize.width > vpRect.right &&
  26937. rect.left > popSize.width);
  26938. sideUp =
  26939. this.canSideUp &&
  26940. (rect.top + popSize.height > vpRect.bottom &&
  26941. rect.bottom > popSize.height);
  26942. left = sideLeft ? rect.left - popSize.width : rect.right;
  26943. top = sideUp ? rect.bottom - popSize.height : rect.top;
  26944. } else {
  26945. sideLeft =
  26946. this.canSideLeft &&
  26947. (rect.right + popSize.width > vpRect.right &&
  26948. rect.left > popSize.width);
  26949. sideUp =
  26950. this.canSideUp &&
  26951. (rect.top + popSize.height > vpRect.bottom &&
  26952. rect.bottom > popSize.height);
  26953. left = sideLeft ? rect.right - popSize.width : rect.left;
  26954. top = sideUp ? rect.top - popSize.height : rect.bottom;
  26955. }
  26956. var popEl = this.getDom();
  26957. uiUtils.setViewportOffset(popEl, {
  26958. left: left,
  26959. top: top
  26960. });
  26961. domUtils.removeClasses(popEl, ANCHOR_CLASSES);
  26962. popEl.className +=
  26963. " " + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
  26964. if (this.editor) {
  26965. popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
  26966. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
  26967. popEl.style.zIndex - 1;
  26968. }
  26969. this.getDom().style.visibility = "visible";
  26970. },
  26971. showAt: function(offset) {
  26972. var left = offset.left;
  26973. var top = offset.top;
  26974. var rect = {
  26975. left: left,
  26976. top: top,
  26977. right: left,
  26978. bottom: top,
  26979. height: 0,
  26980. width: 0
  26981. };
  26982. this.showAnchorRect(rect, false, true);
  26983. },
  26984. _show: function() {
  26985. if (this._hidden) {
  26986. var box = this.getDom();
  26987. box.style.display = "";
  26988. this._hidden = false;
  26989. // if (box.setActive) {
  26990. // box.setActive();
  26991. // }
  26992. this.fireEvent("show");
  26993. }
  26994. },
  26995. isHidden: function() {
  26996. return this._hidden;
  26997. },
  26998. show: function() {
  26999. this._doAutoRender();
  27000. this._show();
  27001. },
  27002. hide: function(notNofity) {
  27003. if (!this._hidden && this.getDom()) {
  27004. this.getDom().style.display = "none";
  27005. this._hidden = true;
  27006. if (!notNofity) {
  27007. this.fireEvent("hide");
  27008. }
  27009. }
  27010. },
  27011. queryAutoHide: function(el) {
  27012. return !el || !uiUtils.contains(this.getDom(), el);
  27013. }
  27014. };
  27015. utils.inherits(Popup, UIBase);
  27016. domUtils.on(document, "mousedown", function(evt) {
  27017. var el = evt.target || evt.srcElement;
  27018. closeAllPopup(evt, el);
  27019. });
  27020. domUtils.on(window, "scroll", function(evt, el) {
  27021. closeAllPopup(evt, el);
  27022. });
  27023. })();
  27024. // ui/colorpicker.js
  27025. ///import core
  27026. ///import uicore
  27027. ;(function() {
  27028. var utils = baidu.editor.utils,
  27029. UIBase = baidu.editor.ui.UIBase,
  27030. ColorPicker = (baidu.editor.ui.ColorPicker = function(options) {
  27031. this.initOptions(options);
  27032. this.noColorText = this.noColorText || this.editor.getLang("clearColor");
  27033. this.initUIBase();
  27034. });
  27035. ColorPicker.prototype = {
  27036. getHtmlTpl: function() {
  27037. return genColorPicker(this.noColorText, this.editor);
  27038. },
  27039. _onTableClick: function(evt) {
  27040. var tgt = evt.target || evt.srcElement;
  27041. var color = tgt.getAttribute("data-color");
  27042. if (color) {
  27043. this.fireEvent("pickcolor", color);
  27044. }
  27045. },
  27046. _onTableOver: function(evt) {
  27047. var tgt = evt.target || evt.srcElement;
  27048. var color = tgt.getAttribute("data-color");
  27049. if (color) {
  27050. this.getDom("preview").style.backgroundColor = color;
  27051. }
  27052. },
  27053. _onTableOut: function() {
  27054. this.getDom("preview").style.backgroundColor = "";
  27055. },
  27056. _onPickNoColor: function() {
  27057. this.fireEvent("picknocolor");
  27058. }
  27059. };
  27060. utils.inherits(ColorPicker, UIBase);
  27061. var COLORS = ("ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646," +
  27062. "f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada," +
  27063. "d8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5," +
  27064. "bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f," +
  27065. "a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09," +
  27066. "7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806," +
  27067. "c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,").split(
  27068. ","
  27069. );
  27070. function genColorPicker(noColorText, editor) {
  27071. var html =
  27072. '<div id="##" class="edui-colorpicker %%">' +
  27073. '<div class="edui-colorpicker-topbar edui-clearfix">' +
  27074. '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
  27075. '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">' +
  27076. noColorText +
  27077. "</div>" +
  27078. "</div>" +
  27079. '<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">' +
  27080. '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;padding-top: 2px"><td colspan="10">' +
  27081. editor.getLang("themeColor") +
  27082. "</td> </tr>" +
  27083. '<tr class="edui-colorpicker-tablefirstrow" >';
  27084. for (var i = 0; i < COLORS.length; i++) {
  27085. if (i && i % 10 === 0) {
  27086. html +=
  27087. "</tr>" +
  27088. (i == 60
  27089. ? '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;"><td colspan="10">' +
  27090. editor.getLang("standardColor") +
  27091. "</td></tr>"
  27092. : "") +
  27093. "<tr" +
  27094. (i == 60 ? ' class="edui-colorpicker-tablefirstrow"' : "") +
  27095. ">";
  27096. }
  27097. html += i < 70
  27098. ? '<td style="padding: 0 2px;"><a hidefocus title="' +
  27099. COLORS[i] +
  27100. '" onclick="return false;" href="javascript:" unselectable="on" class="edui-box edui-colorpicker-colorcell"' +
  27101. ' data-color="#' +
  27102. COLORS[i] +
  27103. '"' +
  27104. ' style="background-color:#' +
  27105. COLORS[i] +
  27106. ";border:solid #ccc;" +
  27107. (i < 10 || i >= 60
  27108. ? "border-width:1px;"
  27109. : i >= 10 && i < 20
  27110. ? "border-width:1px 1px 0 1px;"
  27111. : "border-width:0 1px 0 1px;") +
  27112. '"' +
  27113. "></a></td>"
  27114. : "";
  27115. }
  27116. html += "</tr></table></div>";
  27117. return html;
  27118. }
  27119. })();
  27120. // ui/tablepicker.js
  27121. ///import core
  27122. ///import uicore
  27123. ;(function() {
  27124. var utils = baidu.editor.utils,
  27125. uiUtils = baidu.editor.ui.uiUtils,
  27126. UIBase = baidu.editor.ui.UIBase;
  27127. var TablePicker = (baidu.editor.ui.TablePicker = function(options) {
  27128. this.initOptions(options);
  27129. this.initTablePicker();
  27130. });
  27131. TablePicker.prototype = {
  27132. defaultNumRows: 10,
  27133. defaultNumCols: 10,
  27134. maxNumRows: 20,
  27135. maxNumCols: 20,
  27136. numRows: 10,
  27137. numCols: 10,
  27138. lengthOfCellSide: 22,
  27139. initTablePicker: function() {
  27140. this.initUIBase();
  27141. },
  27142. getHtmlTpl: function() {
  27143. var me = this;
  27144. return (
  27145. '<div id="##" class="edui-tablepicker %%">' +
  27146. '<div class="edui-tablepicker-body">' +
  27147. '<div class="edui-infoarea">' +
  27148. '<span id="##_label" class="edui-label"></span>' +
  27149. "</div>" +
  27150. '<div class="edui-pickarea"' +
  27151. ' onmousemove="$$._onMouseMove(event, this);"' +
  27152. ' onmouseover="$$._onMouseOver(event, this);"' +
  27153. ' onmouseout="$$._onMouseOut(event, this);"' +
  27154. ' onclick="$$._onClick(event, this);"' +
  27155. ">" +
  27156. '<div id="##_overlay" class="edui-overlay"></div>' +
  27157. "</div>" +
  27158. "</div>" +
  27159. "</div>"
  27160. );
  27161. },
  27162. _UIBase_render: UIBase.prototype.render,
  27163. render: function(holder) {
  27164. this._UIBase_render(holder);
  27165. this.getDom("label").innerHTML =
  27166. "0" +
  27167. this.editor.getLang("t_row") +
  27168. " x 0" +
  27169. this.editor.getLang("t_col");
  27170. },
  27171. _track: function(numCols, numRows) {
  27172. var style = this.getDom("overlay").style;
  27173. var sideLen = this.lengthOfCellSide;
  27174. style.width = numCols * sideLen + "px";
  27175. style.height = numRows * sideLen + "px";
  27176. var label = this.getDom("label");
  27177. label.innerHTML =
  27178. numCols +
  27179. this.editor.getLang("t_col") +
  27180. " x " +
  27181. numRows +
  27182. this.editor.getLang("t_row");
  27183. this.numCols = numCols;
  27184. this.numRows = numRows;
  27185. },
  27186. _onMouseOver: function(evt, el) {
  27187. var rel = evt.relatedTarget || evt.fromElement;
  27188. if (!uiUtils.contains(el, rel) && el !== rel) {
  27189. this.getDom("label").innerHTML =
  27190. "0" +
  27191. this.editor.getLang("t_col") +
  27192. " x 0" +
  27193. this.editor.getLang("t_row");
  27194. this.getDom("overlay").style.visibility = "";
  27195. }
  27196. },
  27197. _onMouseOut: function(evt, el) {
  27198. var rel = evt.relatedTarget || evt.toElement;
  27199. if (!uiUtils.contains(el, rel) && el !== rel) {
  27200. this.getDom("label").innerHTML =
  27201. "0" +
  27202. this.editor.getLang("t_col") +
  27203. " x 0" +
  27204. this.editor.getLang("t_row");
  27205. this.getDom("overlay").style.visibility = "hidden";
  27206. }
  27207. },
  27208. _onMouseMove: function(evt, el) {
  27209. var style = this.getDom("overlay").style;
  27210. var offset = uiUtils.getEventOffset(evt);
  27211. var sideLen = this.lengthOfCellSide;
  27212. var numCols = Math.ceil(offset.left / sideLen);
  27213. var numRows = Math.ceil(offset.top / sideLen);
  27214. this._track(numCols, numRows);
  27215. },
  27216. _onClick: function() {
  27217. this.fireEvent("picktable", this.numCols, this.numRows);
  27218. }
  27219. };
  27220. utils.inherits(TablePicker, UIBase);
  27221. })();
  27222. // ui/stateful.js
  27223. ;(function() {
  27224. var browser = baidu.editor.browser,
  27225. domUtils = baidu.editor.dom.domUtils,
  27226. uiUtils = baidu.editor.ui.uiUtils;
  27227. var TPL_STATEFUL =
  27228. 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
  27229. ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
  27230. (browser.ie
  27231. ? ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
  27232. ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"'
  27233. : ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
  27234. ' onmouseout="$$.Stateful_onMouseOut(event, this);"');
  27235. baidu.editor.ui.Stateful = {
  27236. alwalysHoverable: false,
  27237. target: null, //目标元素和this指向dom不一样
  27238. Stateful_init: function() {
  27239. this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
  27240. this.getHtmlTpl = this.Stateful_getHtmlTpl;
  27241. },
  27242. Stateful_getHtmlTpl: function() {
  27243. var tpl = this._Stateful_dGetHtmlTpl();
  27244. // 使用function避免$转义
  27245. return tpl.replace(/stateful/g, function() {
  27246. return TPL_STATEFUL;
  27247. });
  27248. },
  27249. Stateful_onMouseEnter: function(evt, el) {
  27250. this.target = el;
  27251. if (!this.isDisabled() || this.alwalysHoverable) {
  27252. this.addState("hover");
  27253. this.fireEvent("over");
  27254. }
  27255. },
  27256. Stateful_onMouseLeave: function(evt, el) {
  27257. if (!this.isDisabled() || this.alwalysHoverable) {
  27258. this.removeState("hover");
  27259. this.removeState("active");
  27260. this.fireEvent("out");
  27261. }
  27262. },
  27263. Stateful_onMouseOver: function(evt, el) {
  27264. var rel = evt.relatedTarget;
  27265. if (!uiUtils.contains(el, rel) && el !== rel) {
  27266. this.Stateful_onMouseEnter(evt, el);
  27267. }
  27268. },
  27269. Stateful_onMouseOut: function(evt, el) {
  27270. var rel = evt.relatedTarget;
  27271. if (!uiUtils.contains(el, rel) && el !== rel) {
  27272. this.Stateful_onMouseLeave(evt, el);
  27273. }
  27274. },
  27275. Stateful_onMouseDown: function(evt, el) {
  27276. if (!this.isDisabled()) {
  27277. this.addState("active");
  27278. }
  27279. },
  27280. Stateful_onMouseUp: function(evt, el) {
  27281. if (!this.isDisabled()) {
  27282. this.removeState("active");
  27283. }
  27284. },
  27285. Stateful_postRender: function() {
  27286. if (this.disabled && !this.hasState("disabled")) {
  27287. this.addState("disabled");
  27288. }
  27289. },
  27290. hasState: function(state) {
  27291. return domUtils.hasClass(this.getStateDom(), "edui-state-" + state);
  27292. },
  27293. addState: function(state) {
  27294. if (!this.hasState(state)) {
  27295. this.getStateDom().className += " edui-state-" + state;
  27296. }
  27297. },
  27298. removeState: function(state) {
  27299. if (this.hasState(state)) {
  27300. domUtils.removeClasses(this.getStateDom(), ["edui-state-" + state]);
  27301. }
  27302. },
  27303. getStateDom: function() {
  27304. return this.getDom("state");
  27305. },
  27306. isChecked: function() {
  27307. return this.hasState("checked");
  27308. },
  27309. setChecked: function(checked) {
  27310. if (!this.isDisabled() && checked) {
  27311. this.addState("checked");
  27312. } else {
  27313. this.removeState("checked");
  27314. }
  27315. },
  27316. isDisabled: function() {
  27317. return this.hasState("disabled");
  27318. },
  27319. setDisabled: function(disabled) {
  27320. if (disabled) {
  27321. this.removeState("hover");
  27322. this.removeState("checked");
  27323. this.removeState("active");
  27324. this.addState("disabled");
  27325. } else {
  27326. this.removeState("disabled");
  27327. }
  27328. }
  27329. };
  27330. })();
  27331. // ui/button.js
  27332. ///import core
  27333. ///import uicore
  27334. ///import ui/stateful.js
  27335. ;(function() {
  27336. var utils = baidu.editor.utils,
  27337. UIBase = baidu.editor.ui.UIBase,
  27338. Stateful = baidu.editor.ui.Stateful,
  27339. Button = (baidu.editor.ui.Button = function(options) {
  27340. if (options.name) {
  27341. var btnName = options.name;
  27342. var cssRules = options.cssRules;
  27343. if (!options.className) {
  27344. options.className = "edui-for-" + btnName;
  27345. }
  27346. options.cssRules =
  27347. ".edui-" +
  27348. (options.theme || "default") +
  27349. " .edui-toolbar .edui-button.edui-for-" +
  27350. btnName +
  27351. " .edui-icon {" +
  27352. cssRules +
  27353. "}";
  27354. }
  27355. this.initOptions(options);
  27356. this.initButton();
  27357. });
  27358. Button.prototype = {
  27359. uiName: "button",
  27360. label: "",
  27361. title: "",
  27362. showIcon: true,
  27363. showText: true,
  27364. cssRules: "",
  27365. initButton: function() {
  27366. this.initUIBase();
  27367. this.Stateful_init();
  27368. if (this.cssRules) {
  27369. utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules);
  27370. }
  27371. },
  27372. getHtmlTpl: function() {
  27373. return (
  27374. '<div id="##" class="edui-box %%">' +
  27375. '<div id="##_state" stateful>' +
  27376. '<div class="%%-wrap"><div id="##_body" unselectable="on" ' +
  27377. (this.title ? 'title="' + this.title + '"' : "") +
  27378. ' class="%%-body" onmousedown="return $$._onMouseDown(event, this);" onclick="return $$._onClick(event, this);">' +
  27379. (this.showIcon ? '<div class="edui-box edui-icon"><svg class="edui-iconfont"><use xlink:href="#' + this.className + '"></use></svg></div>' : "") +
  27380. (this.showText
  27381. ? '<div class="edui-box edui-label">' + this.label + "</div>"
  27382. : "") +
  27383. "</div>" +
  27384. "</div>" +
  27385. "</div></div>"
  27386. );
  27387. },
  27388. postRender: function() {
  27389. this.Stateful_postRender();
  27390. this.setDisabled(this.disabled);
  27391. },
  27392. _onMouseDown: function(e) {
  27393. var target = e.target || e.srcElement,
  27394. tagName = target && target.tagName && target.tagName.toLowerCase();
  27395. if (tagName == "input" || tagName == "object" || tagName == "object") {
  27396. return false;
  27397. }
  27398. },
  27399. _onClick: function() {
  27400. if (!this.isDisabled()) {
  27401. this.fireEvent("click");
  27402. }
  27403. },
  27404. setTitle: function(text) {
  27405. var label = this.getDom("label");
  27406. label.innerHTML = text;
  27407. }
  27408. };
  27409. utils.inherits(Button, UIBase);
  27410. utils.extend(Button.prototype, Stateful);
  27411. })();
  27412. // ui/splitbutton.js
  27413. ///import core
  27414. ///import uicore
  27415. ///import ui/stateful.js
  27416. ;(function() {
  27417. var utils = baidu.editor.utils,
  27418. uiUtils = baidu.editor.ui.uiUtils,
  27419. domUtils = baidu.editor.dom.domUtils,
  27420. UIBase = baidu.editor.ui.UIBase,
  27421. Stateful = baidu.editor.ui.Stateful,
  27422. SplitButton = (baidu.editor.ui.SplitButton = function(options) {
  27423. this.initOptions(options);
  27424. this.initSplitButton();
  27425. });
  27426. SplitButton.prototype = {
  27427. popup: null,
  27428. uiName: "splitbutton",
  27429. title: "",
  27430. initSplitButton: function() {
  27431. this.initUIBase();
  27432. this.Stateful_init();
  27433. var me = this;
  27434. if (this.popup != null) {
  27435. var popup = this.popup;
  27436. this.popup = null;
  27437. this.setPopup(popup);
  27438. }
  27439. },
  27440. _UIBase_postRender: UIBase.prototype.postRender,
  27441. postRender: function() {
  27442. this.Stateful_postRender();
  27443. this._UIBase_postRender();
  27444. },
  27445. setPopup: function(popup) {
  27446. if (this.popup === popup) return;
  27447. if (this.popup != null) {
  27448. this.popup.dispose();
  27449. }
  27450. popup.addListener("show", utils.bind(this._onPopupShow, this));
  27451. popup.addListener("hide", utils.bind(this._onPopupHide, this));
  27452. popup.addListener(
  27453. "postrender",
  27454. utils.bind(function() {
  27455. popup
  27456. .getDom("body")
  27457. .appendChild(
  27458. uiUtils.createElementByHtml(
  27459. '<div id="' +
  27460. this.popup.id +
  27461. '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
  27462. (uiUtils.getClientRect(this.getDom()).width + 20) +
  27463. 'px"></div>'
  27464. )
  27465. );
  27466. popup.getDom().className += " " + this.className;
  27467. }, this)
  27468. );
  27469. this.popup = popup;
  27470. },
  27471. _onPopupShow: function() {
  27472. this.addState("opened");
  27473. },
  27474. _onPopupHide: function() {
  27475. this.removeState("opened");
  27476. },
  27477. getHtmlTpl: function() {
  27478. return (
  27479. '<div id="##" class="edui-box %%">' +
  27480. "<div " +
  27481. (this.title ? 'title="' + this.title + '"' : "") +
  27482. ' id="##_state" stateful><div class="%%-body">' +
  27483. '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
  27484. '<div class="edui-box edui-icon"><svg class="edui-iconfont"><use xlink:href="#' + this.className + '"></use></svg></div>' +
  27485. "</div>" +
  27486. '<div class="edui-box edui-splitborder"></div>' +
  27487. '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
  27488. "</div></div></div>"
  27489. );
  27490. },
  27491. showPopup: function() {
  27492. // 当popup往上弹出的时候,做特殊处理
  27493. var rect = uiUtils.getClientRect(this.getDom());
  27494. rect.top -= this.popup.SHADOW_RADIUS;
  27495. rect.height += this.popup.SHADOW_RADIUS;
  27496. this.popup.showAnchorRect(rect);
  27497. },
  27498. _onArrowClick: function(event, el) {
  27499. if (!this.isDisabled()) {
  27500. this.showPopup();
  27501. }
  27502. },
  27503. _onButtonClick: function() {
  27504. if (!this.isDisabled()) {
  27505. this.fireEvent("buttonclick");
  27506. }
  27507. }
  27508. };
  27509. utils.inherits(SplitButton, UIBase);
  27510. utils.extend(SplitButton.prototype, Stateful, true);
  27511. })();
  27512. // ui/colorbutton.js
  27513. ///import core
  27514. ///import uicore
  27515. ///import ui/colorpicker.js
  27516. ///import ui/popup.js
  27517. ///import ui/splitbutton.js
  27518. ;(function() {
  27519. var utils = baidu.editor.utils,
  27520. uiUtils = baidu.editor.ui.uiUtils,
  27521. ColorPicker = baidu.editor.ui.ColorPicker,
  27522. Popup = baidu.editor.ui.Popup,
  27523. SplitButton = baidu.editor.ui.SplitButton,
  27524. ColorButton = (baidu.editor.ui.ColorButton = function(options) {
  27525. this.initOptions(options);
  27526. this.initColorButton();
  27527. });
  27528. ColorButton.prototype = {
  27529. initColorButton: function() {
  27530. var me = this;
  27531. this.popup = new Popup({
  27532. content: new ColorPicker({
  27533. noColorText: me.editor.getLang("clearColor"),
  27534. editor: me.editor,
  27535. onpickcolor: function(t, color) {
  27536. me._onPickColor(color);
  27537. },
  27538. onpicknocolor: function(t, color) {
  27539. me._onPickNoColor(color);
  27540. }
  27541. }),
  27542. editor: me.editor
  27543. });
  27544. this.initSplitButton();
  27545. },
  27546. _SplitButton_postRender: SplitButton.prototype.postRender,
  27547. postRender: function() {
  27548. this._SplitButton_postRender();
  27549. this.getDom("button_body").appendChild(
  27550. uiUtils.createElementByHtml(
  27551. '<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>'
  27552. )
  27553. );
  27554. this.getDom().className += " edui-colorbutton";
  27555. },
  27556. setColor: function(color) {
  27557. this.getDom("colorlump").style.backgroundColor = color;
  27558. this.color = color;
  27559. },
  27560. _onPickColor: function(color) {
  27561. if (this.fireEvent("pickcolor", color) !== false) {
  27562. this.setColor(color);
  27563. this.popup.hide();
  27564. }
  27565. },
  27566. _onPickNoColor: function(color) {
  27567. if (this.fireEvent("picknocolor") !== false) {
  27568. this.popup.hide();
  27569. }
  27570. }
  27571. };
  27572. utils.inherits(ColorButton, SplitButton);
  27573. })();
  27574. // ui/tablebutton.js
  27575. ///import core
  27576. ///import uicore
  27577. ///import ui/popup.js
  27578. ///import ui/tablepicker.js
  27579. ///import ui/splitbutton.js
  27580. ;(function() {
  27581. var utils = baidu.editor.utils,
  27582. Popup = baidu.editor.ui.Popup,
  27583. TablePicker = baidu.editor.ui.TablePicker,
  27584. SplitButton = baidu.editor.ui.SplitButton,
  27585. TableButton = (baidu.editor.ui.TableButton = function(options) {
  27586. this.initOptions(options);
  27587. this.initTableButton();
  27588. });
  27589. TableButton.prototype = {
  27590. initTableButton: function() {
  27591. var me = this;
  27592. this.popup = new Popup({
  27593. content: new TablePicker({
  27594. editor: me.editor,
  27595. onpicktable: function(t, numCols, numRows) {
  27596. me._onPickTable(numCols, numRows);
  27597. }
  27598. }),
  27599. editor: me.editor
  27600. });
  27601. this.initSplitButton();
  27602. },
  27603. _onPickTable: function(numCols, numRows) {
  27604. if (this.fireEvent("picktable", numCols, numRows) !== false) {
  27605. this.popup.hide();
  27606. }
  27607. }
  27608. };
  27609. utils.inherits(TableButton, SplitButton);
  27610. })();
  27611. // ui/autotypesetpicker.js
  27612. ///import core
  27613. ///import uicore
  27614. ;(function() {
  27615. var utils = baidu.editor.utils,
  27616. UIBase = baidu.editor.ui.UIBase;
  27617. var AutoTypeSetPicker = (baidu.editor.ui.AutoTypeSetPicker = function(
  27618. options
  27619. ) {
  27620. this.initOptions(options);
  27621. this.initAutoTypeSetPicker();
  27622. });
  27623. AutoTypeSetPicker.prototype = {
  27624. initAutoTypeSetPicker: function() {
  27625. this.initUIBase();
  27626. },
  27627. getHtmlTpl: function() {
  27628. var me = this.editor,
  27629. opt = me.options.autotypeset,
  27630. lang = me.getLang("autoTypeSet");
  27631. var textAlignInputName = "textAlignValue" + me.uid,
  27632. imageBlockInputName = "imageBlockLineValue" + me.uid,
  27633. symbolConverInputName = "symbolConverValue" + me.uid;
  27634. return (
  27635. '<div id="##" class="edui-autotypesetpicker %%">' +
  27636. '<div class="edui-autotypesetpicker-body">' +
  27637. "<table >" +
  27638. '<tr><td nowrap><input type="checkbox" name="mergeEmptyline" ' +
  27639. (opt["mergeEmptyline"] ? "checked" : "") +
  27640. ">" +
  27641. lang.mergeLine +
  27642. '</td><td colspan="2"><input type="checkbox" name="removeEmptyline" ' +
  27643. (opt["removeEmptyline"] ? "checked" : "") +
  27644. ">" +
  27645. lang.delLine +
  27646. "</td></tr>" +
  27647. '<tr><td nowrap><input type="checkbox" name="removeClass" ' +
  27648. (opt["removeClass"] ? "checked" : "") +
  27649. ">" +
  27650. lang.removeFormat +
  27651. '</td><td colspan="2"><input type="checkbox" name="indent" ' +
  27652. (opt["indent"] ? "checked" : "") +
  27653. ">" +
  27654. lang.indent +
  27655. "</td></tr>" +
  27656. "<tr>" +
  27657. '<td nowrap><input type="checkbox" name="textAlign" ' +
  27658. (opt["textAlign"] ? "checked" : "") +
  27659. ">" +
  27660. lang.alignment +
  27661. "</td>" +
  27662. '<td colspan="2" id="' +
  27663. textAlignInputName +
  27664. '">' +
  27665. '<input type="radio" name="' +
  27666. textAlignInputName +
  27667. '" value="left" ' +
  27668. (opt["textAlign"] && opt["textAlign"] == "left" ? "checked" : "") +
  27669. ">" +
  27670. me.getLang("justifyleft") +
  27671. '<input type="radio" name="' +
  27672. textAlignInputName +
  27673. '" value="center" ' +
  27674. (opt["textAlign"] && opt["textAlign"] == "center" ? "checked" : "") +
  27675. ">" +
  27676. me.getLang("justifycenter") +
  27677. '<input type="radio" name="' +
  27678. textAlignInputName +
  27679. '" value="right" ' +
  27680. (opt["textAlign"] && opt["textAlign"] == "right" ? "checked" : "") +
  27681. ">" +
  27682. me.getLang("justifyright") +
  27683. "</td>" +
  27684. "</tr>" +
  27685. "<tr>" +
  27686. '<td nowrap><input type="checkbox" name="imageBlockLine" ' +
  27687. (opt["imageBlockLine"] ? "checked" : "") +
  27688. ">" +
  27689. lang.imageFloat +
  27690. "</td>" +
  27691. '<td nowrap id="' +
  27692. imageBlockInputName +
  27693. '">' +
  27694. '<input type="radio" name="' +
  27695. imageBlockInputName +
  27696. '" value="none" ' +
  27697. (opt["imageBlockLine"] && opt["imageBlockLine"] == "none"
  27698. ? "checked"
  27699. : "") +
  27700. ">" +
  27701. me.getLang("default") +
  27702. '<input type="radio" name="' +
  27703. imageBlockInputName +
  27704. '" value="left" ' +
  27705. (opt["imageBlockLine"] && opt["imageBlockLine"] == "left"
  27706. ? "checked"
  27707. : "") +
  27708. ">" +
  27709. me.getLang("justifyleft") +
  27710. '<input type="radio" name="' +
  27711. imageBlockInputName +
  27712. '" value="center" ' +
  27713. (opt["imageBlockLine"] && opt["imageBlockLine"] == "center"
  27714. ? "checked"
  27715. : "") +
  27716. ">" +
  27717. me.getLang("justifycenter") +
  27718. '<input type="radio" name="' +
  27719. imageBlockInputName +
  27720. '" value="right" ' +
  27721. (opt["imageBlockLine"] && opt["imageBlockLine"] == "right"
  27722. ? "checked"
  27723. : "") +
  27724. ">" +
  27725. me.getLang("justifyright") +
  27726. "</td>" +
  27727. "</tr>" +
  27728. '<tr><td nowrap><input type="checkbox" name="clearFontSize" ' +
  27729. (opt["clearFontSize"] ? "checked" : "") +
  27730. ">" +
  27731. lang.removeFontsize +
  27732. '</td><td colspan="2"><input type="checkbox" name="clearFontFamily" ' +
  27733. (opt["clearFontFamily"] ? "checked" : "") +
  27734. ">" +
  27735. lang.removeFontFamily +
  27736. "</td></tr>" +
  27737. '<tr><td nowrap colspan="3"><input type="checkbox" name="removeEmptyNode" ' +
  27738. (opt["removeEmptyNode"] ? "checked" : "") +
  27739. ">" +
  27740. lang.removeHtml +
  27741. "</td></tr>" +
  27742. '<tr><td nowrap colspan="3"><input type="checkbox" name="pasteFilter" ' +
  27743. (opt["pasteFilter"] ? "checked" : "") +
  27744. ">" +
  27745. lang.pasteFilter +
  27746. "</td></tr>" +
  27747. "<tr>" +
  27748. '<td nowrap><input type="checkbox" name="symbolConver" ' +
  27749. (opt["bdc2sb"] || opt["tobdc"] ? "checked" : "") +
  27750. ">" +
  27751. lang.symbol +
  27752. "</td>" +
  27753. '<td id="' +
  27754. symbolConverInputName +
  27755. '">' +
  27756. '<input type="radio" name="bdc" value="bdc2sb" ' +
  27757. (opt["bdc2sb"] ? "checked" : "") +
  27758. ">" +
  27759. lang.bdc2sb +
  27760. '<input type="radio" name="bdc" value="tobdc" ' +
  27761. (opt["tobdc"] ? "checked" : "") +
  27762. ">" +
  27763. lang.tobdc +
  27764. "" +
  27765. "</td>" +
  27766. '<td nowrap align="right"><button >' +
  27767. lang.run +
  27768. "</button></td>" +
  27769. "</tr>" +
  27770. "</table>" +
  27771. "</div>" +
  27772. "</div>"
  27773. );
  27774. },
  27775. _UIBase_render: UIBase.prototype.render
  27776. };
  27777. utils.inherits(AutoTypeSetPicker, UIBase);
  27778. })();
  27779. // ui/autotypesetbutton.js
  27780. ///import core
  27781. ///import uicore
  27782. ///import ui/popup.js
  27783. ///import ui/autotypesetpicker.js
  27784. ///import ui/splitbutton.js
  27785. ;(function() {
  27786. var utils = baidu.editor.utils,
  27787. Popup = baidu.editor.ui.Popup,
  27788. AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
  27789. SplitButton = baidu.editor.ui.SplitButton,
  27790. AutoTypeSetButton = (baidu.editor.ui.AutoTypeSetButton = function(options) {
  27791. this.initOptions(options);
  27792. this.initAutoTypeSetButton();
  27793. });
  27794. function getPara(me) {
  27795. var opt = {},
  27796. cont = me.getDom(),
  27797. editorId = me.editor.uid,
  27798. inputType = null,
  27799. attrName = null,
  27800. ipts = domUtils.getElementsByTagName(cont, "input");
  27801. for (var i = ipts.length - 1, ipt; (ipt = ipts[i--]); ) {
  27802. inputType = ipt.getAttribute("type");
  27803. if (inputType == "checkbox") {
  27804. attrName = ipt.getAttribute("name");
  27805. opt[attrName] && delete opt[attrName];
  27806. if (ipt.checked) {
  27807. var attrValue = document.getElementById(
  27808. attrName + "Value" + editorId
  27809. );
  27810. if (attrValue) {
  27811. if (/input/gi.test(attrValue.tagName)) {
  27812. opt[attrName] = attrValue.value;
  27813. } else {
  27814. var iptChilds = attrValue.getElementsByTagName("input");
  27815. for (
  27816. var j = iptChilds.length - 1, iptchild;
  27817. (iptchild = iptChilds[j--]);
  27818. ) {
  27819. if (iptchild.checked) {
  27820. opt[attrName] = iptchild.value;
  27821. break;
  27822. }
  27823. }
  27824. }
  27825. } else {
  27826. opt[attrName] = true;
  27827. }
  27828. } else {
  27829. opt[attrName] = false;
  27830. }
  27831. } else {
  27832. opt[ipt.getAttribute("value")] = ipt.checked;
  27833. }
  27834. }
  27835. var selects = domUtils.getElementsByTagName(cont, "select");
  27836. for (var i = 0, si; (si = selects[i++]); ) {
  27837. var attr = si.getAttribute("name");
  27838. opt[attr] = opt[attr] ? si.value : "";
  27839. }
  27840. utils.extend(me.editor.options.autotypeset, opt);
  27841. me.editor.setPreferences("autotypeset", opt);
  27842. }
  27843. AutoTypeSetButton.prototype = {
  27844. initAutoTypeSetButton: function() {
  27845. var me = this;
  27846. this.popup = new Popup({
  27847. //传入配置参数
  27848. content: new AutoTypeSetPicker({ editor: me.editor }),
  27849. editor: me.editor,
  27850. hide: function() {
  27851. if (!this._hidden && this.getDom()) {
  27852. getPara(this);
  27853. this.getDom().style.display = "none";
  27854. this._hidden = true;
  27855. this.fireEvent("hide");
  27856. }
  27857. }
  27858. });
  27859. var flag = 0;
  27860. this.popup.addListener("postRenderAfter", function() {
  27861. var popupUI = this;
  27862. if (flag) return;
  27863. var cont = this.getDom(),
  27864. btn = cont.getElementsByTagName("button")[0];
  27865. btn.onclick = function() {
  27866. getPara(popupUI);
  27867. me.editor.execCommand("autotypeset");
  27868. popupUI.hide();
  27869. };
  27870. domUtils.on(cont, "click", function(e) {
  27871. var target = e.target || e.srcElement,
  27872. editorId = me.editor.uid;
  27873. if (target && target.tagName == "INPUT") {
  27874. // 点击图片浮动的checkbox,去除对应的radio
  27875. if (
  27876. target.name == "imageBlockLine" ||
  27877. target.name == "textAlign" ||
  27878. target.name == "symbolConver"
  27879. ) {
  27880. var checked = target.checked,
  27881. radioTd = document.getElementById(
  27882. target.name + "Value" + editorId
  27883. ),
  27884. radios = radioTd.getElementsByTagName("input"),
  27885. defalutSelect = {
  27886. imageBlockLine: "none",
  27887. textAlign: "left",
  27888. symbolConver: "tobdc"
  27889. };
  27890. for (var i = 0; i < radios.length; i++) {
  27891. if (checked) {
  27892. if (radios[i].value == defalutSelect[target.name]) {
  27893. radios[i].checked = "checked";
  27894. }
  27895. } else {
  27896. radios[i].checked = false;
  27897. }
  27898. }
  27899. }
  27900. // 点击radio,选中对应的checkbox
  27901. if (
  27902. target.name == "imageBlockLineValue" + editorId ||
  27903. target.name == "textAlignValue" + editorId ||
  27904. target.name == "bdc"
  27905. ) {
  27906. var checkboxs = target.parentNode.previousSibling.getElementsByTagName(
  27907. "input"
  27908. );
  27909. checkboxs && (checkboxs[0].checked = true);
  27910. }
  27911. getPara(popupUI);
  27912. }
  27913. });
  27914. flag = 1;
  27915. });
  27916. this.initSplitButton();
  27917. }
  27918. };
  27919. utils.inherits(AutoTypeSetButton, SplitButton);
  27920. })();
  27921. // ui/cellalignpicker.js
  27922. ///import core
  27923. ///import uicore
  27924. ;(function() {
  27925. var utils = baidu.editor.utils,
  27926. Popup = baidu.editor.ui.Popup,
  27927. Stateful = baidu.editor.ui.Stateful,
  27928. UIBase = baidu.editor.ui.UIBase;
  27929. /**
  27930. * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
  27931. * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
  27932. * @update 2013/4/2 hancong03@baidu.com
  27933. */
  27934. var CellAlignPicker = (baidu.editor.ui.CellAlignPicker = function(options) {
  27935. this.initOptions(options);
  27936. this.initSelected();
  27937. this.initCellAlignPicker();
  27938. });
  27939. CellAlignPicker.prototype = {
  27940. //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
  27941. initSelected: function() {
  27942. var status = {
  27943. valign: {
  27944. top: 0,
  27945. middle: 1,
  27946. bottom: 2
  27947. },
  27948. align: {
  27949. left: 0,
  27950. center: 1,
  27951. right: 2
  27952. },
  27953. count: 3
  27954. },
  27955. result = -1;
  27956. if (this.selected) {
  27957. this.selectedIndex =
  27958. status.valign[this.selected.valign] * status.count +
  27959. status.align[this.selected.align];
  27960. }
  27961. },
  27962. initCellAlignPicker: function() {
  27963. this.initUIBase();
  27964. this.Stateful_init();
  27965. },
  27966. getHtmlTpl: function() {
  27967. var alignType = ["left", "center", "right"],
  27968. COUNT = 9,
  27969. tempClassName = null,
  27970. tempIndex = -1,
  27971. tmpl = [];
  27972. for (var i = 0; i < COUNT; i++) {
  27973. tempClassName = this.selectedIndex === i
  27974. ? ' class="edui-cellalign-selected" '
  27975. : "";
  27976. tempIndex = i % 3;
  27977. tempIndex === 0 && tmpl.push("<tr>");
  27978. tmpl.push(
  27979. '<td index="' +
  27980. i +
  27981. '" ' +
  27982. tempClassName +
  27983. ' stateful><div class="edui-icon edui-' +
  27984. alignType[tempIndex] +
  27985. '"></div></td>'
  27986. );
  27987. tempIndex === 2 && tmpl.push("</tr>");
  27988. }
  27989. return (
  27990. '<div id="##" class="edui-cellalignpicker %%">' +
  27991. '<div class="edui-cellalignpicker-body">' +
  27992. '<table onclick="$$._onClick(event);">' +
  27993. tmpl.join("") +
  27994. "</table>" +
  27995. "</div>" +
  27996. "</div>"
  27997. );
  27998. },
  27999. getStateDom: function() {
  28000. return this.target;
  28001. },
  28002. _onClick: function(evt) {
  28003. var target = evt.target || evt.srcElement;
  28004. if (/icon/.test(target.className)) {
  28005. this.items[target.parentNode.getAttribute("index")].onclick();
  28006. Popup.postHide(evt);
  28007. }
  28008. },
  28009. _UIBase_render: UIBase.prototype.render
  28010. };
  28011. utils.inherits(CellAlignPicker, UIBase);
  28012. utils.extend(CellAlignPicker.prototype, Stateful, true);
  28013. })();
  28014. // ui/pastepicker.js
  28015. ///import core
  28016. ///import uicore
  28017. ;(function() {
  28018. var utils = baidu.editor.utils,
  28019. Stateful = baidu.editor.ui.Stateful,
  28020. uiUtils = baidu.editor.ui.uiUtils,
  28021. UIBase = baidu.editor.ui.UIBase;
  28022. var PastePicker = (baidu.editor.ui.PastePicker = function(options) {
  28023. this.initOptions(options);
  28024. this.initPastePicker();
  28025. });
  28026. PastePicker.prototype = {
  28027. initPastePicker: function() {
  28028. this.initUIBase();
  28029. this.Stateful_init();
  28030. },
  28031. getHtmlTpl: function() {
  28032. return (
  28033. '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
  28034. '<div class="edui-pastecontainer">' +
  28035. '<div class="edui-title">' +
  28036. this.editor.getLang("pasteOpt") +
  28037. "</div>" +
  28038. '<div class="edui-button">' +
  28039. '<div title="' +
  28040. this.editor.getLang("pasteSourceFormat") +
  28041. '" onclick="$$.format(false)" stateful>' +
  28042. '<div class="edui-richtxticon"></div></div>' +
  28043. '<div title="' +
  28044. this.editor.getLang("tagFormat") +
  28045. '" onclick="$$.format(2)" stateful>' +
  28046. '<div class="edui-tagicon"></div></div>' +
  28047. '<div title="' +
  28048. this.editor.getLang("pasteTextFormat") +
  28049. '" onclick="$$.format(true)" stateful>' +
  28050. '<div class="edui-plaintxticon"></div></div>' +
  28051. "</div>" +
  28052. "</div>" +
  28053. "</div>"
  28054. );
  28055. },
  28056. getStateDom: function() {
  28057. return this.target;
  28058. },
  28059. format: function(param) {
  28060. this.editor.ui._isTransfer = true;
  28061. this.editor.fireEvent("pasteTransfer", param);
  28062. },
  28063. _onClick: function(cur) {
  28064. var node = domUtils.getNextDomNode(cur),
  28065. screenHt = uiUtils.getViewportRect().height,
  28066. subPop = uiUtils.getClientRect(node);
  28067. if (subPop.top + subPop.height > screenHt)
  28068. node.style.top = -subPop.height - cur.offsetHeight + "px";
  28069. else node.style.top = "";
  28070. if (/hidden/gi.test(domUtils.getComputedStyle(node, "visibility"))) {
  28071. node.style.visibility = "visible";
  28072. domUtils.addClass(cur, "edui-state-opened");
  28073. } else {
  28074. node.style.visibility = "hidden";
  28075. domUtils.removeClasses(cur, "edui-state-opened");
  28076. }
  28077. },
  28078. _UIBase_render: UIBase.prototype.render
  28079. };
  28080. utils.inherits(PastePicker, UIBase);
  28081. utils.extend(PastePicker.prototype, Stateful, true);
  28082. })();
  28083. // ui/toolbar.js
  28084. ;(function() {
  28085. var utils = baidu.editor.utils,
  28086. uiUtils = baidu.editor.ui.uiUtils,
  28087. UIBase = baidu.editor.ui.UIBase,
  28088. Toolbar = (baidu.editor.ui.Toolbar = function(options) {
  28089. this.initOptions(options);
  28090. this.initToolbar();
  28091. });
  28092. Toolbar.prototype = {
  28093. items: null,
  28094. initToolbar: function() {
  28095. this.items = this.items || [];
  28096. this.initUIBase();
  28097. },
  28098. add: function(item, index) {
  28099. if (index === undefined) {
  28100. this.items.push(item);
  28101. } else {
  28102. this.items.splice(index, 0, item);
  28103. }
  28104. },
  28105. getHtmlTpl: function() {
  28106. var buff = [];
  28107. for (var i = 0; i < this.items.length; i++) {
  28108. buff[i] = this.items[i].renderHtml();
  28109. }
  28110. return (
  28111. '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
  28112. buff.join("") +
  28113. "</div>"
  28114. );
  28115. },
  28116. postRender: function() {
  28117. var box = this.getDom();
  28118. for (var i = 0; i < this.items.length; i++) {
  28119. this.items[i].postRender();
  28120. }
  28121. uiUtils.makeUnselectable(box);
  28122. },
  28123. _onMouseDown: function(e) {
  28124. var target = e.target || e.srcElement,
  28125. tagName = target && target.tagName && target.tagName.toLowerCase();
  28126. if (tagName == "input" || tagName == "object" || tagName == "object") {
  28127. return false;
  28128. }
  28129. }
  28130. };
  28131. utils.inherits(Toolbar, UIBase);
  28132. })();
  28133. // ui/menu.js
  28134. ///import core
  28135. ///import uicore
  28136. ///import ui\popup.js
  28137. ///import ui\stateful.js
  28138. ;(function() {
  28139. var utils = baidu.editor.utils,
  28140. domUtils = baidu.editor.dom.domUtils,
  28141. uiUtils = baidu.editor.ui.uiUtils,
  28142. UIBase = baidu.editor.ui.UIBase,
  28143. Popup = baidu.editor.ui.Popup,
  28144. Stateful = baidu.editor.ui.Stateful,
  28145. CellAlignPicker = baidu.editor.ui.CellAlignPicker,
  28146. Menu = (baidu.editor.ui.Menu = function(options) {
  28147. this.initOptions(options);
  28148. this.initMenu();
  28149. });
  28150. var menuSeparator = {
  28151. renderHtml: function() {
  28152. return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>';
  28153. },
  28154. postRender: function() {},
  28155. queryAutoHide: function() {
  28156. return true;
  28157. }
  28158. };
  28159. Menu.prototype = {
  28160. items: null,
  28161. uiName: "menu",
  28162. initMenu: function() {
  28163. this.items = this.items || [];
  28164. this.initPopup();
  28165. this.initItems();
  28166. },
  28167. initItems: function() {
  28168. for (var i = 0; i < this.items.length; i++) {
  28169. var item = this.items[i];
  28170. if (item == "-") {
  28171. this.items[i] = this.getSeparator();
  28172. } else if (!(item instanceof MenuItem)) {
  28173. item.editor = this.editor;
  28174. item.theme = this.editor.options.theme;
  28175. this.items[i] = this.createItem(item);
  28176. }
  28177. }
  28178. },
  28179. getSeparator: function() {
  28180. return menuSeparator;
  28181. },
  28182. createItem: function(item) {
  28183. //新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  28184. item.menu = this;
  28185. return new MenuItem(item);
  28186. },
  28187. _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
  28188. getContentHtmlTpl: function() {
  28189. if (this.items.length == 0) {
  28190. return this._Popup_getContentHtmlTpl();
  28191. }
  28192. var buff = [];
  28193. for (var i = 0; i < this.items.length; i++) {
  28194. var item = this.items[i];
  28195. buff[i] = item.renderHtml();
  28196. }
  28197. return '<div class="%%-body">' + buff.join("") + "</div>";
  28198. },
  28199. _Popup_postRender: Popup.prototype.postRender,
  28200. postRender: function() {
  28201. var me = this;
  28202. for (var i = 0; i < this.items.length; i++) {
  28203. var item = this.items[i];
  28204. item.ownerMenu = this;
  28205. item.postRender();
  28206. }
  28207. domUtils.on(this.getDom(), "mouseover", function(evt) {
  28208. evt = evt || event;
  28209. var rel = evt.relatedTarget || evt.fromElement;
  28210. var el = me.getDom();
  28211. if (!uiUtils.contains(el, rel) && el !== rel) {
  28212. me.fireEvent("over");
  28213. }
  28214. });
  28215. this._Popup_postRender();
  28216. },
  28217. queryAutoHide: function(el) {
  28218. if (el) {
  28219. if (uiUtils.contains(this.getDom(), el)) {
  28220. return false;
  28221. }
  28222. for (var i = 0; i < this.items.length; i++) {
  28223. var item = this.items[i];
  28224. if (item.queryAutoHide(el) === false) {
  28225. return false;
  28226. }
  28227. }
  28228. }
  28229. },
  28230. clearItems: function() {
  28231. for (var i = 0; i < this.items.length; i++) {
  28232. var item = this.items[i];
  28233. clearTimeout(item._showingTimer);
  28234. clearTimeout(item._closingTimer);
  28235. if (item.subMenu) {
  28236. item.subMenu.destroy();
  28237. }
  28238. }
  28239. this.items = [];
  28240. },
  28241. destroy: function() {
  28242. if (this.getDom()) {
  28243. domUtils.remove(this.getDom());
  28244. }
  28245. this.clearItems();
  28246. },
  28247. dispose: function() {
  28248. this.destroy();
  28249. }
  28250. };
  28251. utils.inherits(Menu, Popup);
  28252. /**
  28253. * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  28254. * @type {Function}
  28255. */
  28256. var MenuItem = (baidu.editor.ui.MenuItem = function(options) {
  28257. this.initOptions(options);
  28258. this.initUIBase();
  28259. this.Stateful_init();
  28260. if (this.subMenu && !(this.subMenu instanceof Menu)) {
  28261. if (options.className && options.className.indexOf("aligntd") != -1) {
  28262. var me = this;
  28263. //获取单元格对齐初始状态
  28264. this.subMenu.selected = this.editor.queryCommandValue("cellalignment");
  28265. this.subMenu = new Popup({
  28266. content: new CellAlignPicker(this.subMenu),
  28267. parentMenu: me,
  28268. editor: me.editor,
  28269. destroy: function() {
  28270. if (this.getDom()) {
  28271. domUtils.remove(this.getDom());
  28272. }
  28273. }
  28274. });
  28275. this.subMenu.addListener("postRenderAfter", function() {
  28276. domUtils.on(this.getDom(), "mouseover", function() {
  28277. me.addState("opened");
  28278. });
  28279. });
  28280. } else {
  28281. this.subMenu = new Menu(this.subMenu);
  28282. }
  28283. }
  28284. });
  28285. MenuItem.prototype = {
  28286. label: "",
  28287. subMenu: null,
  28288. ownerMenu: null,
  28289. uiName: "menuitem",
  28290. alwalysHoverable: true,
  28291. getHtmlTpl: function() {
  28292. return (
  28293. '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
  28294. '<div class="%%-body">' +
  28295. this.renderLabelHtml() +
  28296. "</div>" +
  28297. "</div>"
  28298. );
  28299. },
  28300. postRender: function() {
  28301. var me = this;
  28302. this.addListener("over", function() {
  28303. me.ownerMenu.fireEvent("submenuover", me);
  28304. if (me.subMenu) {
  28305. me.delayShowSubMenu();
  28306. }
  28307. });
  28308. if (this.subMenu) {
  28309. this.getDom().className += " edui-hassubmenu";
  28310. this.subMenu.render();
  28311. this.addListener("out", function() {
  28312. me.delayHideSubMenu();
  28313. });
  28314. this.subMenu.addListener("over", function() {
  28315. clearTimeout(me._closingTimer);
  28316. me._closingTimer = null;
  28317. me.addState("opened");
  28318. });
  28319. this.ownerMenu.addListener("hide", function() {
  28320. me.hideSubMenu();
  28321. });
  28322. this.ownerMenu.addListener("submenuover", function(t, subMenu) {
  28323. if (subMenu !== me) {
  28324. me.delayHideSubMenu();
  28325. }
  28326. });
  28327. this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
  28328. this.subMenu.queryAutoHide = function(el) {
  28329. if (el && uiUtils.contains(me.getDom(), el)) {
  28330. return false;
  28331. }
  28332. return this._bakQueryAutoHide(el);
  28333. };
  28334. }
  28335. this.getDom().style.tabIndex = "-1";
  28336. uiUtils.makeUnselectable(this.getDom());
  28337. this.Stateful_postRender();
  28338. },
  28339. delayShowSubMenu: function() {
  28340. var me = this;
  28341. if (!me.isDisabled()) {
  28342. me.addState("opened");
  28343. clearTimeout(me._showingTimer);
  28344. clearTimeout(me._closingTimer);
  28345. me._closingTimer = null;
  28346. me._showingTimer = setTimeout(function() {
  28347. me.showSubMenu();
  28348. }, 250);
  28349. }
  28350. },
  28351. delayHideSubMenu: function() {
  28352. var me = this;
  28353. if (!me.isDisabled()) {
  28354. me.removeState("opened");
  28355. clearTimeout(me._showingTimer);
  28356. if (!me._closingTimer) {
  28357. me._closingTimer = setTimeout(function() {
  28358. if (!me.hasState("opened")) {
  28359. me.hideSubMenu();
  28360. }
  28361. me._closingTimer = null;
  28362. }, 400);
  28363. }
  28364. }
  28365. },
  28366. renderLabelHtml: function() {
  28367. return (
  28368. '<div class="edui-arrow"></div>' +
  28369. '<div class="edui-box edui-icon"></div>' +
  28370. '<div class="edui-box edui-label %%-label">' +
  28371. (this.label || "") +
  28372. "</div>"
  28373. );
  28374. },
  28375. getStateDom: function() {
  28376. return this.getDom();
  28377. },
  28378. queryAutoHide: function(el) {
  28379. if (this.subMenu && this.hasState("opened")) {
  28380. return this.subMenu.queryAutoHide(el);
  28381. }
  28382. },
  28383. _onClick: function(event, this_) {
  28384. if (this.hasState("disabled")) return;
  28385. if (this.fireEvent("click", event, this_) !== false) {
  28386. if (this.subMenu) {
  28387. this.showSubMenu();
  28388. } else {
  28389. Popup.postHide(event);
  28390. }
  28391. }
  28392. },
  28393. showSubMenu: function() {
  28394. var rect = uiUtils.getClientRect(this.getDom());
  28395. rect.right -= 5;
  28396. rect.left += 2;
  28397. rect.width -= 7;
  28398. rect.top -= 4;
  28399. rect.bottom += 4;
  28400. rect.height += 8;
  28401. this.subMenu.showAnchorRect(rect, true, true);
  28402. },
  28403. hideSubMenu: function() {
  28404. this.subMenu.hide();
  28405. }
  28406. };
  28407. utils.inherits(MenuItem, UIBase);
  28408. utils.extend(MenuItem.prototype, Stateful, true);
  28409. })();
  28410. // ui/combox.js
  28411. ///import core
  28412. ///import uicore
  28413. ///import ui/menu.js
  28414. ///import ui/splitbutton.js
  28415. ;(function() {
  28416. // todo: menu和item提成通用list
  28417. var utils = baidu.editor.utils,
  28418. uiUtils = baidu.editor.ui.uiUtils,
  28419. Menu = baidu.editor.ui.Menu,
  28420. SplitButton = baidu.editor.ui.SplitButton,
  28421. Combox = (baidu.editor.ui.Combox = function(options) {
  28422. this.initOptions(options);
  28423. this.initCombox();
  28424. });
  28425. Combox.prototype = {
  28426. uiName: "combox",
  28427. onbuttonclick: function() {
  28428. this.showPopup();
  28429. },
  28430. initCombox: function() {
  28431. var me = this;
  28432. this.items = this.items || [];
  28433. for (var i = 0; i < this.items.length; i++) {
  28434. var item = this.items[i];
  28435. item.uiName = "listitem";
  28436. item.index = i;
  28437. item.onclick = function() {
  28438. me.selectByIndex(this.index);
  28439. };
  28440. }
  28441. this.popup = new Menu({
  28442. items: this.items,
  28443. uiName: "list",
  28444. editor: this.editor,
  28445. captureWheel: true,
  28446. combox: this
  28447. });
  28448. this.initSplitButton();
  28449. },
  28450. _SplitButton_postRender: SplitButton.prototype.postRender,
  28451. postRender: function() {
  28452. this._SplitButton_postRender();
  28453. this.setLabel(this.label || "");
  28454. this.setValue(this.initValue || "");
  28455. },
  28456. showPopup: function() {
  28457. var rect = uiUtils.getClientRect(this.getDom());
  28458. rect.top += 1;
  28459. rect.bottom -= 1;
  28460. rect.height -= 2;
  28461. this.popup.showAnchorRect(rect);
  28462. },
  28463. getValue: function() {
  28464. return this.value;
  28465. },
  28466. setValue: function(value) {
  28467. var index = this.indexByValue(value);
  28468. if (index != -1) {
  28469. this.selectedIndex = index;
  28470. this.setLabel(this.items[index].label);
  28471. this.value = this.items[index].value;
  28472. } else {
  28473. this.selectedIndex = -1;
  28474. this.setLabel(this.getLabelForUnknowValue(value));
  28475. this.value = value;
  28476. }
  28477. },
  28478. setLabel: function(label) {
  28479. this.getDom("button_body").innerHTML = label;
  28480. this.label = label;
  28481. },
  28482. getLabelForUnknowValue: function(value) {
  28483. return value;
  28484. },
  28485. indexByValue: function(value) {
  28486. for (var i = 0; i < this.items.length; i++) {
  28487. if (value == this.items[i].value) {
  28488. return i;
  28489. }
  28490. }
  28491. return -1;
  28492. },
  28493. getItem: function(index) {
  28494. return this.items[index];
  28495. },
  28496. selectByIndex: function(index) {
  28497. if (
  28498. index < this.items.length &&
  28499. this.fireEvent("select", index) !== false
  28500. ) {
  28501. this.selectedIndex = index;
  28502. this.value = this.items[index].value;
  28503. this.setLabel(this.items[index].label);
  28504. }
  28505. }
  28506. };
  28507. utils.inherits(Combox, SplitButton);
  28508. })();
  28509. // ui/dialog.js
  28510. ///import core
  28511. ///import uicore
  28512. ///import ui/mask.js
  28513. ///import ui/button.js
  28514. ;(function() {
  28515. var utils = baidu.editor.utils,
  28516. domUtils = baidu.editor.dom.domUtils,
  28517. uiUtils = baidu.editor.ui.uiUtils,
  28518. Mask = baidu.editor.ui.Mask,
  28519. UIBase = baidu.editor.ui.UIBase,
  28520. Button = baidu.editor.ui.Button,
  28521. Dialog = (baidu.editor.ui.Dialog = function(options) {
  28522. if (options.name) {
  28523. var name = options.name;
  28524. var cssRules = options.cssRules;
  28525. if (!options.className) {
  28526. options.className = "edui-for-" + name;
  28527. }
  28528. if (cssRules) {
  28529. options.cssRules =
  28530. ".edui-for-" + name + " .edui-dialog-content {" + cssRules + "}";
  28531. }
  28532. }
  28533. this.initOptions(
  28534. utils.extend(
  28535. {
  28536. autoReset: true,
  28537. draggable: true,
  28538. onok: function() {},
  28539. oncancel: function() {},
  28540. onclose: function(t, ok) {
  28541. return ok ? this.onok() : this.oncancel();
  28542. },
  28543. //是否控制dialog中的scroll事件, 默认为不阻止
  28544. holdScroll: false
  28545. },
  28546. options
  28547. )
  28548. );
  28549. this.initDialog();
  28550. });
  28551. var modalMask;
  28552. var dragMask;
  28553. var activeDialog;
  28554. Dialog.prototype = {
  28555. draggable: false,
  28556. uiName: "dialog",
  28557. initDialog: function() {
  28558. var me = this,
  28559. theme = this.editor.options.theme;
  28560. if (this.cssRules) {
  28561. this.cssRules = ".edui-" + theme + " " + this.cssRules;
  28562. utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules);
  28563. }
  28564. this.initUIBase();
  28565. this.modalMask =
  28566. modalMask ||
  28567. (modalMask = new Mask({
  28568. className: "edui-dialog-modalmask",
  28569. theme: theme,
  28570. onclick: function() {
  28571. activeDialog && activeDialog.close(false);
  28572. }
  28573. }));
  28574. this.dragMask =
  28575. dragMask ||
  28576. (dragMask = new Mask({
  28577. className: "edui-dialog-dragmask",
  28578. theme: theme
  28579. }));
  28580. this.closeButton = new Button({
  28581. className: "edui-dialog-closebutton",
  28582. title: me.closeDialog,
  28583. theme: theme,
  28584. onclick: function() {
  28585. me.close(false);
  28586. }
  28587. });
  28588. this.fullscreen && this.initResizeEvent();
  28589. if (this.buttons) {
  28590. for (var i = 0; i < this.buttons.length; i++) {
  28591. if (!(this.buttons[i] instanceof Button)) {
  28592. this.buttons[i] = new Button(
  28593. utils.extend(
  28594. this.buttons[i],
  28595. {
  28596. editor: this.editor
  28597. },
  28598. true
  28599. )
  28600. );
  28601. }
  28602. }
  28603. }
  28604. },
  28605. initResizeEvent: function() {
  28606. var me = this;
  28607. domUtils.on(window, "resize", function() {
  28608. if (me._hidden || me._hidden === undefined) {
  28609. return;
  28610. }
  28611. if (me.__resizeTimer) {
  28612. window.clearTimeout(me.__resizeTimer);
  28613. }
  28614. me.__resizeTimer = window.setTimeout(function() {
  28615. me.__resizeTimer = null;
  28616. var dialogWrapNode = me.getDom(),
  28617. contentNode = me.getDom("content"),
  28618. wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
  28619. contentRect = UE.ui.uiUtils.getClientRect(contentNode),
  28620. vpRect = uiUtils.getViewportRect();
  28621. contentNode.style.width =
  28622. vpRect.width - wrapRect.width + contentRect.width + "px";
  28623. contentNode.style.height =
  28624. vpRect.height - wrapRect.height + contentRect.height + "px";
  28625. dialogWrapNode.style.width = vpRect.width + "px";
  28626. dialogWrapNode.style.height = vpRect.height + "px";
  28627. me.fireEvent("resize");
  28628. }, 100);
  28629. });
  28630. },
  28631. fitSize: function() {
  28632. var popBodyEl = this.getDom("body");
  28633. // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
  28634. // uiUtils.removeStyle(popBodyEl, 'width');
  28635. // uiUtils.removeStyle(popBodyEl, 'height');
  28636. // }
  28637. var size = this.mesureSize();
  28638. popBodyEl.style.width = size.width + "px";
  28639. popBodyEl.style.height = size.height + "px";
  28640. return size;
  28641. },
  28642. safeSetOffset: function(offset) {
  28643. var me = this;
  28644. var el = me.getDom();
  28645. var vpRect = uiUtils.getViewportRect();
  28646. var rect = uiUtils.getClientRect(el);
  28647. var left = offset.left;
  28648. if (left + rect.width > vpRect.right) {
  28649. left = vpRect.right - rect.width;
  28650. }
  28651. var top = offset.top;
  28652. if (top + rect.height > vpRect.bottom) {
  28653. top = vpRect.bottom - rect.height;
  28654. }
  28655. el.style.left = Math.max(left, 0) + "px";
  28656. el.style.top = Math.max(top, 0) + "px";
  28657. },
  28658. showAtCenter: function() {
  28659. var vpRect = uiUtils.getViewportRect();
  28660. if (!this.fullscreen) {
  28661. this.getDom().style.display = "";
  28662. var popSize = this.fitSize();
  28663. var titleHeight = this.getDom("titlebar").offsetHeight | 0;
  28664. var left = vpRect.width / 2 - popSize.width / 2;
  28665. var top =
  28666. vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
  28667. var popEl = this.getDom();
  28668. this.safeSetOffset({
  28669. left: Math.max(left | 0, 0),
  28670. top: Math.max(top | 0, 0)
  28671. });
  28672. if (!domUtils.hasClass(popEl, "edui-state-centered")) {
  28673. popEl.className += " edui-state-centered";
  28674. }
  28675. } else {
  28676. var dialogWrapNode = this.getDom(),
  28677. contentNode = this.getDom("content");
  28678. dialogWrapNode.style.display = "block";
  28679. var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
  28680. contentRect = UE.ui.uiUtils.getClientRect(contentNode);
  28681. dialogWrapNode.style.left = "-100000px";
  28682. contentNode.style.width =
  28683. vpRect.width - wrapRect.width + contentRect.width + "px";
  28684. contentNode.style.height =
  28685. vpRect.height - wrapRect.height + contentRect.height + "px";
  28686. dialogWrapNode.style.width = vpRect.width + "px";
  28687. dialogWrapNode.style.height = vpRect.height + "px";
  28688. dialogWrapNode.style.left = 0;
  28689. //保存环境的overflow值
  28690. this._originalContext = {
  28691. html: {
  28692. overflowX: document.documentElement.style.overflowX,
  28693. overflowY: document.documentElement.style.overflowY
  28694. },
  28695. body: {
  28696. overflowX: document.body.style.overflowX,
  28697. overflowY: document.body.style.overflowY
  28698. }
  28699. };
  28700. document.documentElement.style.overflowX = "hidden";
  28701. document.documentElement.style.overflowY = "hidden";
  28702. document.body.style.overflowX = "hidden";
  28703. document.body.style.overflowY = "hidden";
  28704. }
  28705. this._show();
  28706. },
  28707. getContentHtml: function() {
  28708. var contentHtml = "";
  28709. if (typeof this.content == "string") {
  28710. contentHtml = this.content;
  28711. } else if (this.iframeUrl) {
  28712. contentHtml =
  28713. '<span id="' +
  28714. this.id +
  28715. '_contmask" class="dialogcontmask"></span><iframe id="' +
  28716. this.id +
  28717. '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="' +
  28718. this.iframeUrl +
  28719. '"></iframe>';
  28720. }
  28721. return contentHtml;
  28722. },
  28723. getHtmlTpl: function() {
  28724. var footHtml = "";
  28725. if (this.buttons) {
  28726. var buff = [];
  28727. for (var i = 0; i < this.buttons.length; i++) {
  28728. buff[i] = this.buttons[i].renderHtml();
  28729. }
  28730. footHtml =
  28731. '<div class="%%-foot">' +
  28732. '<div id="##_buttons" class="%%-buttons">' +
  28733. buff.join("") +
  28734. "</div>" +
  28735. "</div>";
  28736. }
  28737. return (
  28738. '<div id="##" class="%%"><div ' +
  28739. (!this.fullscreen
  28740. ? 'class="%%"'
  28741. : 'class="%%-wrap edui-dialog-fullscreen-flag"') +
  28742. '><div id="##_body" class="%%-body">' +
  28743. '<div class="%%-shadow"></div>' +
  28744. '<div id="##_titlebar" class="%%-titlebar">' +
  28745. '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
  28746. '<span class="%%-caption">' +
  28747. (this.title || "") +
  28748. "</span>" +
  28749. "</div>" +
  28750. this.closeButton.renderHtml() +
  28751. "</div>" +
  28752. '<div id="##_content" class="%%-content">' +
  28753. (this.autoReset ? "" : this.getContentHtml()) +
  28754. "</div>" +
  28755. footHtml +
  28756. "</div></div></div>"
  28757. );
  28758. },
  28759. postRender: function() {
  28760. // todo: 保持居中/记住上次关闭位置选项
  28761. if (!this.modalMask.getDom()) {
  28762. this.modalMask.render();
  28763. this.modalMask.hide();
  28764. }
  28765. if (!this.dragMask.getDom()) {
  28766. this.dragMask.render();
  28767. this.dragMask.hide();
  28768. }
  28769. var me = this;
  28770. this.addListener("show", function() {
  28771. me.modalMask.show(this.getDom().style.zIndex - 2);
  28772. });
  28773. this.addListener("hide", function() {
  28774. me.modalMask.hide();
  28775. });
  28776. if (this.buttons) {
  28777. for (var i = 0; i < this.buttons.length; i++) {
  28778. this.buttons[i].postRender();
  28779. }
  28780. }
  28781. domUtils.on(window, "resize", function() {
  28782. setTimeout(function() {
  28783. if (!me.isHidden()) {
  28784. me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
  28785. }
  28786. });
  28787. });
  28788. //hold住scroll事件,防止dialog的滚动影响页面
  28789. // if( this.holdScroll ) {
  28790. //
  28791. // if( !me.iframeUrl ) {
  28792. // domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  28793. // domUtils.preventDefault(e);
  28794. // } );
  28795. // } else {
  28796. // me.addListener('dialogafterreset', function(){
  28797. // window.setTimeout(function(){
  28798. // var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
  28799. //
  28800. // if( browser.ie ) {
  28801. //
  28802. // var timer = window.setInterval(function(){
  28803. //
  28804. // if( iframeWindow.document && iframeWindow.document.body ) {
  28805. // window.clearInterval( timer );
  28806. // timer = null;
  28807. // domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  28808. // domUtils.preventDefault(e);
  28809. // } );
  28810. // }
  28811. //
  28812. // }, 100);
  28813. //
  28814. // } else {
  28815. // domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  28816. // domUtils.preventDefault(e);
  28817. // } );
  28818. // }
  28819. //
  28820. // }, 1);
  28821. // });
  28822. // }
  28823. //
  28824. // }
  28825. this._hide();
  28826. },
  28827. mesureSize: function() {
  28828. var body = this.getDom("body");
  28829. var width = uiUtils.getClientRect(this.getDom("content")).width;
  28830. var dialogBodyStyle = body.style;
  28831. dialogBodyStyle.width = width;
  28832. return uiUtils.getClientRect(body);
  28833. },
  28834. _onTitlebarMouseDown: function(evt, el) {
  28835. if (this.draggable) {
  28836. var rect;
  28837. var vpRect = uiUtils.getViewportRect();
  28838. var me = this;
  28839. uiUtils.startDrag(evt, {
  28840. ondragstart: function() {
  28841. rect = uiUtils.getClientRect(me.getDom());
  28842. me.getDom("contmask").style.visibility = "visible";
  28843. me.dragMask.show(me.getDom().style.zIndex - 1);
  28844. },
  28845. ondragmove: function(x, y) {
  28846. var left = rect.left + x;
  28847. var top = rect.top + y;
  28848. me.safeSetOffset({
  28849. left: left,
  28850. top: top
  28851. });
  28852. },
  28853. ondragstop: function() {
  28854. me.getDom("contmask").style.visibility = "hidden";
  28855. domUtils.removeClasses(me.getDom(), ["edui-state-centered"]);
  28856. me.dragMask.hide();
  28857. }
  28858. });
  28859. }
  28860. },
  28861. reset: function() {
  28862. this.getDom("content").innerHTML = this.getContentHtml();
  28863. this.fireEvent("dialogafterreset");
  28864. },
  28865. _show: function() {
  28866. if (this._hidden) {
  28867. this.getDom().style.display = "";
  28868. //要高过编辑器的zindxe
  28869. this.editor.container.style.zIndex &&
  28870. (this.getDom().style.zIndex =
  28871. this.editor.container.style.zIndex * 1 + 10);
  28872. this._hidden = false;
  28873. this.fireEvent("show");
  28874. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
  28875. this.getDom().style.zIndex - 4;
  28876. }
  28877. },
  28878. isHidden: function() {
  28879. return this._hidden;
  28880. },
  28881. _hide: function() {
  28882. if (!this._hidden) {
  28883. var wrapNode = this.getDom();
  28884. wrapNode.style.display = "none";
  28885. wrapNode.style.zIndex = "";
  28886. wrapNode.style.width = "";
  28887. wrapNode.style.height = "";
  28888. this._hidden = true;
  28889. this.fireEvent("hide");
  28890. }
  28891. },
  28892. open: function() {
  28893. if (this.autoReset) {
  28894. //有可能还没有渲染
  28895. try {
  28896. this.reset();
  28897. } catch (e) {
  28898. this.render();
  28899. this.open();
  28900. }
  28901. }
  28902. this.showAtCenter();
  28903. if (this.iframeUrl) {
  28904. try {
  28905. this.getDom("iframe").focus();
  28906. } catch (ex) {}
  28907. }
  28908. activeDialog = this;
  28909. },
  28910. _onCloseButtonClick: function(evt, el) {
  28911. this.close(false);
  28912. },
  28913. close: function(ok) {
  28914. if (this.fireEvent("close", ok) !== false) {
  28915. //还原环境
  28916. if (this.fullscreen) {
  28917. document.documentElement.style.overflowX = this._originalContext.html.overflowX;
  28918. document.documentElement.style.overflowY = this._originalContext.html.overflowY;
  28919. document.body.style.overflowX = this._originalContext.body.overflowX;
  28920. document.body.style.overflowY = this._originalContext.body.overflowY;
  28921. delete this._originalContext;
  28922. }
  28923. this._hide();
  28924. //销毁content
  28925. var content = this.getDom("content");
  28926. var iframe = this.getDom("iframe");
  28927. if (content && iframe) {
  28928. var doc = iframe.contentDocument || iframe.contentWindow.document;
  28929. doc && (doc.body.innerHTML = "");
  28930. domUtils.remove(content);
  28931. }
  28932. }
  28933. }
  28934. };
  28935. utils.inherits(Dialog, UIBase);
  28936. })();
  28937. // ui/menubutton.js
  28938. ///import core
  28939. ///import uicore
  28940. ///import ui/menu.js
  28941. ///import ui/splitbutton.js
  28942. ;(function() {
  28943. var utils = baidu.editor.utils,
  28944. Menu = baidu.editor.ui.Menu,
  28945. SplitButton = baidu.editor.ui.SplitButton,
  28946. MenuButton = (baidu.editor.ui.MenuButton = function(options) {
  28947. this.initOptions(options);
  28948. this.initMenuButton();
  28949. });
  28950. MenuButton.prototype = {
  28951. initMenuButton: function() {
  28952. var me = this;
  28953. this.uiName = "menubutton";
  28954. this.popup = new Menu({
  28955. items: me.items,
  28956. className: me.className,
  28957. editor: me.editor
  28958. });
  28959. this.popup.addListener("show", function() {
  28960. var list = this;
  28961. for (var i = 0; i < list.items.length; i++) {
  28962. list.items[i].removeState("checked");
  28963. if (list.items[i].value == me._value) {
  28964. list.items[i].addState("checked");
  28965. this.value = me._value;
  28966. }
  28967. }
  28968. });
  28969. this.initSplitButton();
  28970. },
  28971. setValue: function(value) {
  28972. this._value = value;
  28973. }
  28974. };
  28975. utils.inherits(MenuButton, SplitButton);
  28976. })();
  28977. // ui/multiMenu.js
  28978. ///import core
  28979. ///import uicore
  28980. ///commands 表情
  28981. ;(function() {
  28982. var utils = baidu.editor.utils,
  28983. Popup = baidu.editor.ui.Popup,
  28984. SplitButton = baidu.editor.ui.SplitButton,
  28985. MultiMenuPop = (baidu.editor.ui.MultiMenuPop = function(options) {
  28986. this.initOptions(options);
  28987. this.initMultiMenu();
  28988. });
  28989. MultiMenuPop.prototype = {
  28990. initMultiMenu: function() {
  28991. var me = this;
  28992. this.popup = new Popup({
  28993. content: "",
  28994. editor: me.editor,
  28995. iframe_rendered: false,
  28996. onshow: function() {
  28997. if (!this.iframe_rendered) {
  28998. this.iframe_rendered = true;
  28999. this.getDom("content").innerHTML =
  29000. '<iframe id="' +
  29001. me.id +
  29002. '_iframe" src="' +
  29003. me.iframeUrl +
  29004. '" frameborder="0"></iframe>';
  29005. me.editor.container.style.zIndex &&
  29006. (this.getDom().style.zIndex =
  29007. me.editor.container.style.zIndex * 1 + 1);
  29008. }
  29009. }
  29010. // canSideUp:false,
  29011. // canSideLeft:false
  29012. });
  29013. this.onbuttonclick = function() {
  29014. this.showPopup();
  29015. };
  29016. this.initSplitButton();
  29017. }
  29018. };
  29019. utils.inherits(MultiMenuPop, SplitButton);
  29020. })();
  29021. // ui/shortcutmenu.js
  29022. ;(function() {
  29023. var UI = baidu.editor.ui,
  29024. UIBase = UI.UIBase,
  29025. uiUtils = UI.uiUtils,
  29026. utils = baidu.editor.utils,
  29027. domUtils = baidu.editor.dom.domUtils;
  29028. var allMenus = [], //存储所有快捷菜单
  29029. timeID,
  29030. isSubMenuShow = false; //是否有子pop显示
  29031. var ShortCutMenu = (UI.ShortCutMenu = function(options) {
  29032. this.initOptions(options);
  29033. this.initShortCutMenu();
  29034. });
  29035. ShortCutMenu.postHide = hideAllMenu;
  29036. ShortCutMenu.prototype = {
  29037. isHidden: true,
  29038. SPACE: 5,
  29039. initShortCutMenu: function() {
  29040. this.items = this.items || [];
  29041. this.initUIBase();
  29042. this.initItems();
  29043. this.initEvent();
  29044. allMenus.push(this);
  29045. },
  29046. initEvent: function() {
  29047. var me = this,
  29048. doc = me.editor.document;
  29049. domUtils.on(doc, "mousemove", function(e) {
  29050. if (me.isHidden === false) {
  29051. //有pop显示就不隐藏快捷菜单
  29052. if (me.getSubMenuMark() || me.eventType == "contextmenu") return;
  29053. var flag = true,
  29054. el = me.getDom(),
  29055. wt = el.offsetWidth,
  29056. ht = el.offsetHeight,
  29057. distanceX = wt / 2 + me.SPACE, //距离中心X标准
  29058. distanceY = ht / 2, //距离中心Y标准
  29059. x = Math.abs(e.screenX - me.left), //离中心距离横坐标
  29060. y = Math.abs(e.screenY - me.top); //离中心距离纵坐标
  29061. clearTimeout(timeID);
  29062. timeID = setTimeout(function() {
  29063. if (y > 0 && y < distanceY) {
  29064. me.setOpacity(el, "1");
  29065. } else if (y > distanceY && y < distanceY + 70) {
  29066. me.setOpacity(el, "0.5");
  29067. flag = false;
  29068. } else if (y > distanceY + 70 && y < distanceY + 140) {
  29069. me.hide();
  29070. }
  29071. if (flag && x > 0 && x < distanceX) {
  29072. me.setOpacity(el, "1");
  29073. } else if (x > distanceX && x < distanceX + 70) {
  29074. me.setOpacity(el, "0.5");
  29075. } else if (x > distanceX + 70 && x < distanceX + 140) {
  29076. me.hide();
  29077. }
  29078. });
  29079. }
  29080. });
  29081. //ie\ff下 mouseout不准
  29082. if (browser.chrome) {
  29083. domUtils.on(doc, "mouseout", function(e) {
  29084. var relatedTgt = e.relatedTarget || e.toElement;
  29085. if (relatedTgt == null || relatedTgt.tagName == "HTML") {
  29086. me.hide();
  29087. }
  29088. });
  29089. }
  29090. me.editor.addListener("afterhidepop", function() {
  29091. if (!me.isHidden) {
  29092. isSubMenuShow = true;
  29093. }
  29094. });
  29095. },
  29096. initItems: function() {
  29097. if (utils.isArray(this.items)) {
  29098. for (var i = 0, len = this.items.length; i < len; i++) {
  29099. var item = this.items[i].toLowerCase();
  29100. if (UI[item]) {
  29101. this.items[i] = new UI[item](this.editor);
  29102. this.items[i].className += " edui-shortcutsubmenu ";
  29103. }
  29104. }
  29105. }
  29106. },
  29107. setOpacity: function(el, value) {
  29108. if (browser.ie && browser.version < 9) {
  29109. el.style.filter = "alpha(opacity = " + parseFloat(value) * 100 + ");";
  29110. } else {
  29111. el.style.opacity = value;
  29112. }
  29113. },
  29114. getSubMenuMark: function() {
  29115. isSubMenuShow = false;
  29116. var layerEle = uiUtils.getFixedLayer();
  29117. var list = domUtils.getElementsByTagName(layerEle, "div", function(node) {
  29118. return domUtils.hasClass(node, "edui-shortcutsubmenu edui-popup");
  29119. });
  29120. for (var i = 0, node; (node = list[i++]); ) {
  29121. if (node.style.display != "none") {
  29122. isSubMenuShow = true;
  29123. }
  29124. }
  29125. return isSubMenuShow;
  29126. },
  29127. show: function(e, hasContextmenu) {
  29128. var me = this,
  29129. offset = {},
  29130. el = this.getDom(),
  29131. fixedlayer = uiUtils.getFixedLayer();
  29132. function setPos(offset) {
  29133. if (offset.left < 0) {
  29134. offset.left = 0;
  29135. }
  29136. if (offset.top < 0) {
  29137. offset.top = 0;
  29138. }
  29139. el.style.cssText =
  29140. "position:absolute;left:" +
  29141. offset.left +
  29142. "px;top:" +
  29143. offset.top +
  29144. "px;";
  29145. }
  29146. function setPosByCxtMenu(menu) {
  29147. if (!menu.tagName) {
  29148. menu = menu.getDom();
  29149. }
  29150. offset.left = parseInt(menu.style.left);
  29151. offset.top = parseInt(menu.style.top);
  29152. offset.top -= el.offsetHeight + 15;
  29153. setPos(offset);
  29154. }
  29155. me.eventType = e.type;
  29156. el.style.cssText = "display:block;left:-9999px";
  29157. if (e.type == "contextmenu" && hasContextmenu) {
  29158. var menu = domUtils.getElementsByTagName(
  29159. fixedlayer,
  29160. "div",
  29161. "edui-contextmenu"
  29162. )[0];
  29163. if (menu) {
  29164. setPosByCxtMenu(menu);
  29165. } else {
  29166. me.editor.addListener("aftershowcontextmenu", function(type, menu) {
  29167. setPosByCxtMenu(menu);
  29168. });
  29169. }
  29170. } else {
  29171. offset = uiUtils.getViewportOffsetByEvent(e);
  29172. offset.top -= el.offsetHeight + me.SPACE;
  29173. offset.left += me.SPACE + 20;
  29174. setPos(offset);
  29175. me.setOpacity(el, 0.2);
  29176. }
  29177. me.isHidden = false;
  29178. me.left = e.screenX + el.offsetWidth / 2 - me.SPACE;
  29179. me.top = e.screenY - el.offsetHeight / 2 - me.SPACE;
  29180. if (me.editor) {
  29181. el.style.zIndex = me.editor.container.style.zIndex * 1 + 10;
  29182. fixedlayer.style.zIndex = el.style.zIndex - 1;
  29183. }
  29184. },
  29185. hide: function() {
  29186. if (this.getDom()) {
  29187. this.getDom().style.display = "none";
  29188. }
  29189. this.isHidden = true;
  29190. },
  29191. postRender: function() {
  29192. if (utils.isArray(this.items)) {
  29193. for (var i = 0, item; (item = this.items[i++]); ) {
  29194. item.postRender();
  29195. }
  29196. }
  29197. },
  29198. getHtmlTpl: function() {
  29199. var buff;
  29200. if (utils.isArray(this.items)) {
  29201. buff = [];
  29202. for (var i = 0; i < this.items.length; i++) {
  29203. buff[i] = this.items[i].renderHtml();
  29204. }
  29205. buff = buff.join("");
  29206. } else {
  29207. buff = this.items;
  29208. }
  29209. return (
  29210. '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
  29211. buff +
  29212. "</div>"
  29213. );
  29214. }
  29215. };
  29216. utils.inherits(ShortCutMenu, UIBase);
  29217. function hideAllMenu(e) {
  29218. var tgt = e.target || e.srcElement,
  29219. cur = domUtils.findParent(
  29220. tgt,
  29221. function(node) {
  29222. return (
  29223. domUtils.hasClass(node, "edui-shortcutmenu") ||
  29224. domUtils.hasClass(node, "edui-popup")
  29225. );
  29226. },
  29227. true
  29228. );
  29229. if (!cur) {
  29230. for (var i = 0, menu; (menu = allMenus[i++]); ) {
  29231. menu.hide();
  29232. }
  29233. }
  29234. }
  29235. domUtils.on(document, "mousedown", function(e) {
  29236. hideAllMenu(e);
  29237. });
  29238. domUtils.on(window, "scroll", function(e) {
  29239. hideAllMenu(e);
  29240. });
  29241. })();
  29242. // ui/breakline.js
  29243. ;(function() {
  29244. var utils = baidu.editor.utils,
  29245. UIBase = baidu.editor.ui.UIBase,
  29246. Breakline = (baidu.editor.ui.Breakline = function(options) {
  29247. this.initOptions(options);
  29248. this.initSeparator();
  29249. });
  29250. Breakline.prototype = {
  29251. uiName: "Breakline",
  29252. initSeparator: function() {
  29253. this.initUIBase();
  29254. },
  29255. getHtmlTpl: function() {
  29256. return "<br/>";
  29257. }
  29258. };
  29259. utils.inherits(Breakline, UIBase);
  29260. })();
  29261. // ui/message.js
  29262. ///import core
  29263. ///import uicore
  29264. ;(function() {
  29265. var utils = baidu.editor.utils,
  29266. domUtils = baidu.editor.dom.domUtils,
  29267. UIBase = baidu.editor.ui.UIBase,
  29268. Message = (baidu.editor.ui.Message = function(options) {
  29269. this.initOptions(options);
  29270. this.initMessage();
  29271. });
  29272. Message.prototype = {
  29273. initMessage: function() {
  29274. this.initUIBase();
  29275. },
  29276. getHtmlTpl: function() {
  29277. return (
  29278. '<div id="##" class="edui-message %%">' +
  29279. ' <div id="##_closer" class="edui-message-closer">×</div>' +
  29280. ' <div id="##_body" class="edui-message-body edui-message-type-info">' +
  29281. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  29282. ' <div class="edui-shadow"></div>' +
  29283. ' <div id="##_content" class="edui-message-content">' +
  29284. " </div>" +
  29285. " </div>" +
  29286. "</div>"
  29287. );
  29288. },
  29289. reset: function(opt) {
  29290. var me = this;
  29291. if (!opt.keepshow) {
  29292. clearTimeout(this.timer);
  29293. me.timer = setTimeout(function() {
  29294. me.hide();
  29295. }, opt.timeout || 4000);
  29296. }
  29297. opt.content !== undefined && me.setContent(opt.content);
  29298. opt.type !== undefined && me.setType(opt.type);
  29299. me.show();
  29300. },
  29301. postRender: function() {
  29302. var me = this,
  29303. closer = this.getDom("closer");
  29304. closer &&
  29305. domUtils.on(closer, "click", function() {
  29306. me.hide();
  29307. });
  29308. },
  29309. setContent: function(content) {
  29310. this.getDom("content").innerHTML = content;
  29311. },
  29312. setType: function(type) {
  29313. type = type || "info";
  29314. var body = this.getDom("body");
  29315. body.className = body.className.replace(
  29316. /edui-message-type-[\w-]+/,
  29317. "edui-message-type-" + type
  29318. );
  29319. },
  29320. getContent: function() {
  29321. return this.getDom("content").innerHTML;
  29322. },
  29323. getType: function() {
  29324. var arr = this.getDom("body").match(/edui-message-type-([\w-]+)/);
  29325. return arr ? arr[1] : "";
  29326. },
  29327. show: function() {
  29328. this.getDom().style.display = "block";
  29329. },
  29330. hide: function() {
  29331. var dom = this.getDom();
  29332. if (dom) {
  29333. dom.style.display = "none";
  29334. dom.parentNode && dom.parentNode.removeChild(dom);
  29335. }
  29336. }
  29337. };
  29338. utils.inherits(Message, UIBase);
  29339. })();
  29340. // ui/iconfont.js
  29341. ;(function(window){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>';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window)
  29342. // adapter/editorui.js
  29343. //ui跟编辑器的适配層
  29344. //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
  29345. //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据neditor.config中的toolbars找到相应的进行实例化
  29346. ;(function() {
  29347. var utils = baidu.editor.utils;
  29348. var editorui = baidu.editor.ui;
  29349. var _Dialog = editorui.Dialog;
  29350. editorui.buttons = {};
  29351. editorui.Dialog = function(options) {
  29352. var dialog = new _Dialog(options);
  29353. dialog.addListener("hide", function() {
  29354. if (dialog.editor) {
  29355. var editor = dialog.editor;
  29356. try {
  29357. if (browser.gecko) {
  29358. var y = editor.window.scrollY,
  29359. x = editor.window.scrollX;
  29360. editor.body.focus();
  29361. editor.window.scrollTo(x, y);
  29362. } else {
  29363. editor.focus();
  29364. }
  29365. } catch (ex) {}
  29366. }
  29367. });
  29368. return dialog;
  29369. };
  29370. var iframeUrlMap = {
  29371. anchor: "~/dialogs/anchor/anchor.html",
  29372. insertimage: "/admin/Base/Photos/index",
  29373. link: "~/dialogs/link/link.html",
  29374. spechars: "~/dialogs/spechars/spechars.html",
  29375. searchreplace: "~/dialogs/searchreplace/searchreplace.html",
  29376. map: "~/dialogs/map/map.html",
  29377. gmap: "~/dialogs/gmap/gmap.html",
  29378. insertvideo: "~/dialogs/video/video.html",
  29379. help: "~/dialogs/help/help.html",
  29380. preview: "~/dialogs/preview/preview.html",
  29381. emotion: "~/dialogs/emotion/emotion.html",
  29382. wordimage: "~/dialogs/wordimage/wordimage.html",
  29383. attachment: "~/dialogs/attachment/attachment.html",
  29384. insertframe: "~/dialogs/insertframe/insertframe.html",
  29385. edittip: "~/dialogs/table/edittip.html",
  29386. edittable: "~/dialogs/table/edittable.html",
  29387. edittd: "~/dialogs/table/edittd.html",
  29388. webapp: "~/dialogs/webapp/webapp.html",
  29389. snapscreen: "~/dialogs/snapscreen/snapscreen.html",
  29390. scrawl: "~/dialogs/scrawl/scrawl.html",
  29391. music: "~/dialogs/music/music.html",
  29392. template: "~/dialogs/template/template.html",
  29393. background: "~/dialogs/background/background.html",
  29394. charts: "~/dialogs/charts/charts.html"
  29395. };
  29396. //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  29397. var btnCmds = [
  29398. "undo",
  29399. "redo",
  29400. "formatmatch",
  29401. "bold",
  29402. "italic",
  29403. "underline",
  29404. "fontborder",
  29405. "touppercase",
  29406. "tolowercase",
  29407. "strikethrough",
  29408. "subscript",
  29409. "superscript",
  29410. "source",
  29411. "indent",
  29412. "outdent",
  29413. "blockquote",
  29414. "pasteplain",
  29415. "pagebreak",
  29416. "selectall",
  29417. "print",
  29418. "horizontal",
  29419. "removeformat",
  29420. "time",
  29421. "date",
  29422. "unlink",
  29423. "insertparagraphbeforetable",
  29424. "insertrow",
  29425. "insertcol",
  29426. "mergeright",
  29427. "mergedown",
  29428. "deleterow",
  29429. "deletecol",
  29430. "splittorows",
  29431. "splittocols",
  29432. "splittocells",
  29433. "mergecells",
  29434. "deletetable",
  29435. "drafts"
  29436. ];
  29437. for (var i = 0, ci; (ci = btnCmds[i++]); ) {
  29438. ci = ci.toLowerCase();
  29439. editorui[ci] = (function(cmd) {
  29440. return function(editor) {
  29441. var ui = new editorui.Button({
  29442. className: "edui-for-" + cmd,
  29443. title:
  29444. editor.options.labelMap[cmd] ||
  29445. editor.getLang("labelMap." + cmd) ||
  29446. "",
  29447. onclick: function() {
  29448. editor.execCommand(cmd);
  29449. },
  29450. theme: editor.options.theme,
  29451. showText: false
  29452. });
  29453. editorui.buttons[cmd] = ui;
  29454. editor.addListener("selectionchange", function(
  29455. type,
  29456. causeByUi,
  29457. uiReady
  29458. ) {
  29459. var state = editor.queryCommandState(cmd);
  29460. if (state == -1) {
  29461. ui.setDisabled(true);
  29462. ui.setChecked(false);
  29463. } else {
  29464. if (!uiReady) {
  29465. ui.setDisabled(false);
  29466. ui.setChecked(state);
  29467. }
  29468. }
  29469. });
  29470. return ui;
  29471. };
  29472. })(ci);
  29473. }
  29474. //清除文档
  29475. editorui.cleardoc = function(editor) {
  29476. var ui = new editorui.Button({
  29477. className: "edui-for-cleardoc",
  29478. title:
  29479. editor.options.labelMap.cleardoc ||
  29480. editor.getLang("labelMap.cleardoc") ||
  29481. "",
  29482. theme: editor.options.theme,
  29483. onclick: function() {
  29484. if (confirm(editor.getLang("confirmClear"))) {
  29485. editor.execCommand("cleardoc");
  29486. }
  29487. }
  29488. });
  29489. editorui.buttons["cleardoc"] = ui;
  29490. editor.addListener("selectionchange", function() {
  29491. ui.setDisabled(editor.queryCommandState("cleardoc") == -1);
  29492. });
  29493. return ui;
  29494. };
  29495. //排版,图片排版,文字方向
  29496. var typeset = {
  29497. justify: ["left", "right", "center", "justify"],
  29498. imagefloat: ["none", "left", "center", "right"],
  29499. directionality: ["ltr", "rtl"]
  29500. };
  29501. for (var p in typeset) {
  29502. (function(cmd, val) {
  29503. for (var i = 0, ci; (ci = val[i++]); ) {
  29504. (function(cmd2) {
  29505. editorui[cmd.replace("float", "") + cmd2] = function(editor) {
  29506. var ui = new editorui.Button({
  29507. className: "edui-for-" + cmd.replace("float", "") + cmd2,
  29508. title:
  29509. editor.options.labelMap[cmd.replace("float", "") + cmd2] ||
  29510. editor.getLang(
  29511. "labelMap." + cmd.replace("float", "") + cmd2
  29512. ) ||
  29513. "",
  29514. theme: editor.options.theme,
  29515. onclick: function() {
  29516. editor.execCommand(cmd, cmd2);
  29517. }
  29518. });
  29519. editorui.buttons[cmd] = ui;
  29520. editor.addListener("selectionchange", function(
  29521. type,
  29522. causeByUi,
  29523. uiReady
  29524. ) {
  29525. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  29526. ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady);
  29527. });
  29528. return ui;
  29529. };
  29530. })(ci);
  29531. }
  29532. })(p, typeset[p]);
  29533. }
  29534. //字体颜色和背景颜色
  29535. for (var i = 0, ci; (ci = ["backcolor", "forecolor"][i++]); ) {
  29536. editorui[ci] = (function(cmd) {
  29537. return function(editor) {
  29538. var ui = new editorui.ColorButton({
  29539. className: "edui-for-" + cmd,
  29540. color: "default",
  29541. title:
  29542. editor.options.labelMap[cmd] ||
  29543. editor.getLang("labelMap." + cmd) ||
  29544. "",
  29545. editor: editor,
  29546. onpickcolor: function(t, color) {
  29547. editor.execCommand(cmd, color);
  29548. },
  29549. onpicknocolor: function() {
  29550. editor.execCommand(cmd, "default");
  29551. this.setColor("transparent");
  29552. this.color = "default";
  29553. },
  29554. onbuttonclick: function() {
  29555. editor.execCommand(cmd, this.color);
  29556. }
  29557. });
  29558. editorui.buttons[cmd] = ui;
  29559. editor.addListener("selectionchange", function() {
  29560. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  29561. });
  29562. return ui;
  29563. };
  29564. })(ci);
  29565. }
  29566. var dialogBtns = {
  29567. noOk: ["searchreplace", "help", "spechars", "webapp", "preview"],
  29568. ok: [
  29569. "attachment",
  29570. "anchor",
  29571. "link",
  29572. "insertimage",
  29573. "map",
  29574. "gmap",
  29575. "insertframe",
  29576. "wordimage",
  29577. "insertvideo",
  29578. "insertframe",
  29579. "edittip",
  29580. "edittable",
  29581. "edittd",
  29582. "scrawl",
  29583. "template",
  29584. "music",
  29585. "background",
  29586. "charts"
  29587. ]
  29588. };
  29589. for (var p in dialogBtns) {
  29590. (function(type, vals) {
  29591. for (var i = 0, ci; (ci = vals[i++]); ) {
  29592. //todo opera下存在问题
  29593. if (browser.opera && ci === "searchreplace") {
  29594. continue;
  29595. }
  29596. (function(cmd) {
  29597. editorui[cmd] = function(editor, iframeUrl, title) {
  29598. iframeUrl =
  29599. iframeUrl ||
  29600. (editor.options.iframeUrlMap || {})[cmd] ||
  29601. iframeUrlMap[cmd];
  29602. title =
  29603. editor.options.labelMap[cmd] ||
  29604. editor.getLang("labelMap." + cmd) ||
  29605. "";
  29606. var dialog;
  29607. //没有iframeUrl不创建dialog
  29608. if (iframeUrl) {
  29609. dialog = new editorui.Dialog(
  29610. utils.extend(
  29611. {
  29612. iframeUrl: editor.ui.mapUrl(iframeUrl),
  29613. editor: editor,
  29614. className: "edui-for-" + cmd,
  29615. title: title,
  29616. holdScroll: cmd === "insertimage",
  29617. fullscreen: /charts|preview/.test(cmd),
  29618. closeDialog: editor.getLang("closeDialog")
  29619. },
  29620. type == "ok"
  29621. ? {
  29622. buttons: [
  29623. {
  29624. className: "edui-okbutton",
  29625. label: editor.getLang("ok"),
  29626. editor: editor,
  29627. onclick: function() {
  29628. dialog.close(true);
  29629. }
  29630. },
  29631. {
  29632. className: "edui-cancelbutton",
  29633. label: editor.getLang("cancel"),
  29634. editor: editor,
  29635. onclick: function() {
  29636. dialog.close(false);
  29637. }
  29638. }
  29639. ]
  29640. }
  29641. : {}
  29642. )
  29643. );
  29644. editor.ui._dialogs[cmd + "Dialog"] = dialog;
  29645. }
  29646. var ui = new editorui.Button({
  29647. className: "edui-for-" + cmd,
  29648. title: title,
  29649. onclick: function() {
  29650. if (dialog) {
  29651. switch (cmd) {
  29652. case "wordimage":
  29653. var images = editor.execCommand("wordimage");
  29654. if (images && images.length) {
  29655. dialog.render();
  29656. dialog.open();
  29657. }
  29658. break;
  29659. case "scrawl":
  29660. if (editor.queryCommandState("scrawl") != -1) {
  29661. dialog.render();
  29662. dialog.open();
  29663. }
  29664. break;
  29665. default:
  29666. dialog.render();
  29667. dialog.open();
  29668. }
  29669. }
  29670. },
  29671. theme: editor.options.theme,
  29672. disabled:
  29673. (cmd == "scrawl" && editor.queryCommandState("scrawl") == -1) ||
  29674. cmd == "charts"
  29675. });
  29676. editorui.buttons[cmd] = ui;
  29677. editor.addListener("selectionchange", function() {
  29678. //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
  29679. var unNeedCheckState = { edittable: 1 };
  29680. if (cmd in unNeedCheckState) return;
  29681. var state = editor.queryCommandState(cmd);
  29682. if (ui.getDom()) {
  29683. ui.setDisabled(state == -1);
  29684. ui.setChecked(state);
  29685. }
  29686. });
  29687. return ui;
  29688. };
  29689. })(ci.toLowerCase());
  29690. }
  29691. })(p, dialogBtns[p]);
  29692. }
  29693. editorui.snapscreen = function(editor, iframeUrl, title) {
  29694. title =
  29695. editor.options.labelMap["snapscreen"] ||
  29696. editor.getLang("labelMap.snapscreen") ||
  29697. "";
  29698. var ui = new editorui.Button({
  29699. className: "edui-for-snapscreen",
  29700. title: title,
  29701. onclick: function() {
  29702. editor.execCommand("snapscreen");
  29703. },
  29704. theme: editor.options.theme
  29705. });
  29706. editorui.buttons["snapscreen"] = ui;
  29707. iframeUrl =
  29708. iframeUrl ||
  29709. (editor.options.iframeUrlMap || {})["snapscreen"] ||
  29710. iframeUrlMap["snapscreen"];
  29711. if (iframeUrl) {
  29712. var dialog = new editorui.Dialog({
  29713. iframeUrl: editor.ui.mapUrl(iframeUrl),
  29714. editor: editor,
  29715. className: "edui-for-snapscreen",
  29716. title: title,
  29717. buttons: [
  29718. {
  29719. className: "edui-okbutton",
  29720. label: editor.getLang("ok"),
  29721. editor: editor,
  29722. onclick: function() {
  29723. dialog.close(true);
  29724. }
  29725. },
  29726. {
  29727. className: "edui-cancelbutton",
  29728. label: editor.getLang("cancel"),
  29729. editor: editor,
  29730. onclick: function() {
  29731. dialog.close(false);
  29732. }
  29733. }
  29734. ]
  29735. });
  29736. dialog.render();
  29737. editor.ui._dialogs["snapscreenDialog"] = dialog;
  29738. }
  29739. editor.addListener("selectionchange", function() {
  29740. ui.setDisabled(editor.queryCommandState("snapscreen") == -1);
  29741. });
  29742. return ui;
  29743. };
  29744. editorui.insertcode = function(editor, list, title) {
  29745. list = editor.options["insertcode"] || [];
  29746. title =
  29747. editor.options.labelMap["insertcode"] ||
  29748. editor.getLang("labelMap.insertcode") ||
  29749. "";
  29750. // if (!list.length) return;
  29751. var items = [];
  29752. utils.each(list, function(key, val) {
  29753. items.push({
  29754. label: key,
  29755. value: val,
  29756. theme: editor.options.theme,
  29757. renderLabelHtml: function() {
  29758. return (
  29759. '<div class="edui-label %%-label" >' + (this.label || "") + "</div>"
  29760. );
  29761. }
  29762. });
  29763. });
  29764. var ui = new editorui.Combox({
  29765. editor: editor,
  29766. items: items,
  29767. onselect: function(t, index) {
  29768. editor.execCommand("insertcode", this.items[index].value);
  29769. },
  29770. onbuttonclick: function() {
  29771. this.showPopup();
  29772. },
  29773. title: title,
  29774. initValue: title,
  29775. className: "edui-for-insertcode",
  29776. indexByValue: function(value) {
  29777. if (value) {
  29778. for (var i = 0, ci; (ci = this.items[i]); i++) {
  29779. if (ci.value.indexOf(value) != -1) return i;
  29780. }
  29781. }
  29782. return -1;
  29783. }
  29784. });
  29785. editorui.buttons["insertcode"] = ui;
  29786. editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
  29787. if (!uiReady) {
  29788. var state = editor.queryCommandState("insertcode");
  29789. if (state == -1) {
  29790. ui.setDisabled(true);
  29791. } else {
  29792. ui.setDisabled(false);
  29793. var value = editor.queryCommandValue("insertcode");
  29794. if (!value) {
  29795. ui.setValue(title);
  29796. return;
  29797. }
  29798. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  29799. value && (value = value.replace(/['"]/g, "").split(",")[0]);
  29800. ui.setValue(value);
  29801. }
  29802. }
  29803. });
  29804. return ui;
  29805. };
  29806. editorui.fontfamily = function(editor, list, title) {
  29807. list = editor.options["fontfamily"] || [];
  29808. title =
  29809. editor.options.labelMap["fontfamily"] ||
  29810. editor.getLang("labelMap.fontfamily") ||
  29811. "";
  29812. if (!list.length) return;
  29813. for (var i = 0, ci, items = []; (ci = list[i]); i++) {
  29814. var langLabel = editor.getLang("fontfamily")[ci.name] || "";
  29815. (function(key, val) {
  29816. items.push({
  29817. label: key,
  29818. value: val,
  29819. theme: editor.options.theme,
  29820. renderLabelHtml: function() {
  29821. return (
  29822. '<div class="edui-label %%-label" style="font-family:' +
  29823. utils.unhtml(this.value) +
  29824. '">' +
  29825. (this.label || "") +
  29826. "</div>"
  29827. );
  29828. }
  29829. });
  29830. })(ci.label || langLabel, ci.val);
  29831. }
  29832. var ui = new editorui.Combox({
  29833. editor: editor,
  29834. items: items,
  29835. onselect: function(t, index) {
  29836. editor.execCommand("FontFamily", this.items[index].value);
  29837. },
  29838. onbuttonclick: function() {
  29839. this.showPopup();
  29840. },
  29841. title: title,
  29842. initValue: title,
  29843. className: "edui-for-fontfamily",
  29844. indexByValue: function(value) {
  29845. if (value) {
  29846. for (var i = 0, ci; (ci = this.items[i]); i++) {
  29847. if (ci.value.indexOf(value) != -1) return i;
  29848. }
  29849. }
  29850. return -1;
  29851. }
  29852. });
  29853. editorui.buttons["fontfamily"] = ui;
  29854. editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
  29855. if (!uiReady) {
  29856. var state = editor.queryCommandState("FontFamily");
  29857. if (state == -1) {
  29858. ui.setDisabled(true);
  29859. } else {
  29860. ui.setDisabled(false);
  29861. var value = editor.queryCommandValue("FontFamily");
  29862. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  29863. value && (value = value.replace(/['"]/g, "").split(",")[0]);
  29864. ui.setValue(value);
  29865. }
  29866. }
  29867. });
  29868. return ui;
  29869. };
  29870. editorui.fontsize = function(editor, list, title) {
  29871. title =
  29872. editor.options.labelMap["fontsize"] ||
  29873. editor.getLang("labelMap.fontsize") ||
  29874. "";
  29875. list = list || editor.options["fontsize"] || [];
  29876. if (!list.length) return;
  29877. var items = [];
  29878. for (var i = 0; i < list.length; i++) {
  29879. var size = list[i] + "px";
  29880. items.push({
  29881. label: size,
  29882. value: size,
  29883. theme: editor.options.theme,
  29884. renderLabelHtml: function() {
  29885. return (
  29886. '<div class="edui-label %%-label" style="line-height:1;font-size:' +
  29887. this.value +
  29888. '">' +
  29889. (this.label || "") +
  29890. "</div>"
  29891. );
  29892. }
  29893. });
  29894. }
  29895. var ui = new editorui.Combox({
  29896. editor: editor,
  29897. items: items,
  29898. title: title,
  29899. initValue: title,
  29900. onselect: function(t, index) {
  29901. editor.execCommand("FontSize", this.items[index].value);
  29902. },
  29903. onbuttonclick: function() {
  29904. this.showPopup();
  29905. },
  29906. className: "edui-for-fontsize"
  29907. });
  29908. editorui.buttons["fontsize"] = ui;
  29909. editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
  29910. if (!uiReady) {
  29911. var state = editor.queryCommandState("FontSize");
  29912. if (state == -1) {
  29913. ui.setDisabled(true);
  29914. } else {
  29915. ui.setDisabled(false);
  29916. ui.setValue(editor.queryCommandValue("FontSize"));
  29917. }
  29918. }
  29919. });
  29920. return ui;
  29921. };
  29922. editorui.paragraph = function(editor, list, title) {
  29923. title =
  29924. editor.options.labelMap["paragraph"] ||
  29925. editor.getLang("labelMap.paragraph") ||
  29926. "";
  29927. list = editor.options["paragraph"] || [];
  29928. if (utils.isEmptyObject(list)) return;
  29929. var items = [];
  29930. for (var i in list) {
  29931. items.push({
  29932. value: i,
  29933. label: list[i] || editor.getLang("paragraph")[i],
  29934. theme: editor.options.theme,
  29935. renderLabelHtml: function() {
  29936. return (
  29937. '<div class="edui-label %%-label"><span class="edui-for-' +
  29938. this.value +
  29939. '">' +
  29940. (this.label || "") +
  29941. "</span></div>"
  29942. );
  29943. }
  29944. });
  29945. }
  29946. var ui = new editorui.Combox({
  29947. editor: editor,
  29948. items: items,
  29949. title: title,
  29950. initValue: title,
  29951. className: "edui-for-paragraph",
  29952. onselect: function(t, index) {
  29953. editor.execCommand("Paragraph", this.items[index].value);
  29954. },
  29955. onbuttonclick: function() {
  29956. this.showPopup();
  29957. }
  29958. });
  29959. editorui.buttons["paragraph"] = ui;
  29960. editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
  29961. if (!uiReady) {
  29962. var state = editor.queryCommandState("Paragraph");
  29963. if (state == -1) {
  29964. ui.setDisabled(true);
  29965. } else {
  29966. ui.setDisabled(false);
  29967. var value = editor.queryCommandValue("Paragraph");
  29968. var index = ui.indexByValue(value);
  29969. if (index != -1) {
  29970. ui.setValue(value);
  29971. } else {
  29972. ui.setValue(ui.initValue);
  29973. }
  29974. }
  29975. }
  29976. });
  29977. return ui;
  29978. };
  29979. //自定义标题
  29980. editorui.customstyle = function(editor) {
  29981. var list = editor.options["customstyle"] || [],
  29982. title =
  29983. editor.options.labelMap["customstyle"] ||
  29984. editor.getLang("labelMap.customstyle") ||
  29985. "";
  29986. if (!list.length) return;
  29987. var langCs = editor.getLang("customstyle");
  29988. for (var i = 0, items = [], t; (t = list[i++]); ) {
  29989. (function(t) {
  29990. var ck = {};
  29991. ck.label = t.label ? t.label : langCs[t.name];
  29992. ck.style = t.style;
  29993. ck.className = t.className;
  29994. ck.tag = t.tag;
  29995. items.push({
  29996. label: ck.label,
  29997. value: ck,
  29998. theme: editor.options.theme,
  29999. renderLabelHtml: function() {
  30000. return (
  30001. '<div class="edui-label %%-label">' +
  30002. "<" +
  30003. ck.tag +
  30004. " " +
  30005. (ck.className ? ' class="' + ck.className + '"' : "") +
  30006. (ck.style ? ' style="' + ck.style + '"' : "") +
  30007. ">" +
  30008. ck.label +
  30009. "</" +
  30010. ck.tag +
  30011. ">" +
  30012. "</div>"
  30013. );
  30014. }
  30015. });
  30016. })(t);
  30017. }
  30018. var ui = new editorui.Combox({
  30019. editor: editor,
  30020. items: items,
  30021. title: title,
  30022. initValue: title,
  30023. className: "edui-for-customstyle",
  30024. onselect: function(t, index) {
  30025. editor.execCommand("customstyle", this.items[index].value);
  30026. },
  30027. onbuttonclick: function() {
  30028. this.showPopup();
  30029. },
  30030. indexByValue: function(value) {
  30031. for (var i = 0, ti; (ti = this.items[i++]); ) {
  30032. if (ti.label == value) {
  30033. return i - 1;
  30034. }
  30035. }
  30036. return -1;
  30037. }
  30038. });
  30039. editorui.buttons["customstyle"] = ui;
  30040. editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
  30041. if (!uiReady) {
  30042. var state = editor.queryCommandState("customstyle");
  30043. if (state == -1) {
  30044. ui.setDisabled(true);
  30045. } else {
  30046. ui.setDisabled(false);
  30047. var value = editor.queryCommandValue("customstyle");
  30048. var index = ui.indexByValue(value);
  30049. if (index != -1) {
  30050. ui.setValue(value);
  30051. } else {
  30052. ui.setValue(ui.initValue);
  30053. }
  30054. }
  30055. }
  30056. });
  30057. return ui;
  30058. };
  30059. editorui.inserttable = function(editor, iframeUrl, title) {
  30060. title =
  30061. editor.options.labelMap["inserttable"] ||
  30062. editor.getLang("labelMap.inserttable") ||
  30063. "";
  30064. var ui = new editorui.TableButton({
  30065. editor: editor,
  30066. title: title,
  30067. className: "edui-for-inserttable",
  30068. onpicktable: function(t, numCols, numRows) {
  30069. editor.execCommand("InsertTable", {
  30070. numRows: numRows,
  30071. numCols: numCols,
  30072. border: 1
  30073. });
  30074. },
  30075. onbuttonclick: function() {
  30076. this.showPopup();
  30077. }
  30078. });
  30079. editorui.buttons["inserttable"] = ui;
  30080. editor.addListener("selectionchange", function() {
  30081. ui.setDisabled(editor.queryCommandState("inserttable") == -1);
  30082. });
  30083. return ui;
  30084. };
  30085. editorui.lineheight = function(editor) {
  30086. var val = editor.options.lineheight || [];
  30087. if (!val.length) return;
  30088. for (var i = 0, ci, items = []; (ci = val[i++]); ) {
  30089. items.push({
  30090. //todo:写死了
  30091. label: ci,
  30092. value: ci,
  30093. theme: editor.options.theme,
  30094. onclick: function() {
  30095. editor.execCommand("lineheight", this.value);
  30096. }
  30097. });
  30098. }
  30099. var ui = new editorui.MenuButton({
  30100. editor: editor,
  30101. className: "edui-for-lineheight",
  30102. title:
  30103. editor.options.labelMap["lineheight"] ||
  30104. editor.getLang("labelMap.lineheight") ||
  30105. "",
  30106. items: items,
  30107. onbuttonclick: function() {
  30108. var value = editor.queryCommandValue("LineHeight") || this.value;
  30109. editor.execCommand("LineHeight", value);
  30110. }
  30111. });
  30112. editorui.buttons["lineheight"] = ui;
  30113. editor.addListener("selectionchange", function() {
  30114. var state = editor.queryCommandState("LineHeight");
  30115. if (state == -1) {
  30116. ui.setDisabled(true);
  30117. } else {
  30118. ui.setDisabled(false);
  30119. var value = editor.queryCommandValue("LineHeight");
  30120. value && ui.setValue((value + "").replace(/cm/, ""));
  30121. ui.setChecked(state);
  30122. }
  30123. });
  30124. return ui;
  30125. };
  30126. var rowspacings = ["top", "bottom"];
  30127. for (var r = 0, ri; (ri = rowspacings[r++]); ) {
  30128. (function(cmd) {
  30129. editorui["rowspacing" + cmd] = function(editor) {
  30130. var val = editor.options["rowspacing" + cmd] || [];
  30131. if (!val.length) return null;
  30132. for (var i = 0, ci, items = []; (ci = val[i++]); ) {
  30133. items.push({
  30134. label: ci,
  30135. value: ci,
  30136. theme: editor.options.theme,
  30137. onclick: function() {
  30138. editor.execCommand("rowspacing", this.value, cmd);
  30139. }
  30140. });
  30141. }
  30142. var ui = new editorui.MenuButton({
  30143. editor: editor,
  30144. className: "edui-for-rowspacing" + cmd,
  30145. title:
  30146. editor.options.labelMap["rowspacing" + cmd] ||
  30147. editor.getLang("labelMap.rowspacing" + cmd) ||
  30148. "",
  30149. items: items,
  30150. onbuttonclick: function() {
  30151. var value =
  30152. editor.queryCommandValue("rowspacing", cmd) || this.value;
  30153. editor.execCommand("rowspacing", value, cmd);
  30154. }
  30155. });
  30156. editorui.buttons[cmd] = ui;
  30157. editor.addListener("selectionchange", function() {
  30158. var state = editor.queryCommandState("rowspacing", cmd);
  30159. if (state == -1) {
  30160. ui.setDisabled(true);
  30161. } else {
  30162. ui.setDisabled(false);
  30163. var value = editor.queryCommandValue("rowspacing", cmd);
  30164. value && ui.setValue((value + "").replace(/%/, ""));
  30165. ui.setChecked(state);
  30166. }
  30167. });
  30168. return ui;
  30169. };
  30170. })(ri);
  30171. }
  30172. //有序,无序列表
  30173. var lists = ["insertorderedlist", "insertunorderedlist"];
  30174. for (var l = 0, cl; (cl = lists[l++]); ) {
  30175. (function(cmd) {
  30176. editorui[cmd] = function(editor) {
  30177. var vals = editor.options[cmd],
  30178. _onMenuClick = function() {
  30179. editor.execCommand(cmd, this.value);
  30180. },
  30181. items = [];
  30182. for (var i in vals) {
  30183. items.push({
  30184. label: vals[i] || editor.getLang()[cmd][i] || "",
  30185. value: i,
  30186. theme: editor.options.theme,
  30187. onclick: _onMenuClick
  30188. });
  30189. }
  30190. var ui = new editorui.MenuButton({
  30191. editor: editor,
  30192. className: "edui-for-" + cmd,
  30193. title: editor.getLang("labelMap." + cmd) || "",
  30194. items: items,
  30195. onbuttonclick: function() {
  30196. var value = editor.queryCommandValue(cmd) || this.value;
  30197. editor.execCommand(cmd, value);
  30198. }
  30199. });
  30200. editorui.buttons[cmd] = ui;
  30201. editor.addListener("selectionchange", function() {
  30202. var state = editor.queryCommandState(cmd);
  30203. if (state == -1) {
  30204. ui.setDisabled(true);
  30205. } else {
  30206. ui.setDisabled(false);
  30207. var value = editor.queryCommandValue(cmd);
  30208. ui.setValue(value);
  30209. ui.setChecked(state);
  30210. }
  30211. });
  30212. return ui;
  30213. };
  30214. })(cl);
  30215. }
  30216. editorui.fullscreen = function(editor, title) {
  30217. title =
  30218. editor.options.labelMap["fullscreen"] ||
  30219. editor.getLang("labelMap.fullscreen") ||
  30220. "";
  30221. var ui = new editorui.Button({
  30222. className: "edui-for-fullscreen",
  30223. title: title,
  30224. theme: editor.options.theme,
  30225. onclick: function() {
  30226. if (editor.ui) {
  30227. editor.ui.setFullScreen(!editor.ui.isFullScreen());
  30228. }
  30229. this.setChecked(editor.ui.isFullScreen());
  30230. }
  30231. });
  30232. editorui.buttons["fullscreen"] = ui;
  30233. editor.addListener("selectionchange", function() {
  30234. var state = editor.queryCommandState("fullscreen");
  30235. ui.setDisabled(state == -1);
  30236. ui.setChecked(editor.ui.isFullScreen());
  30237. });
  30238. return ui;
  30239. };
  30240. // 表情
  30241. editorui["emotion"] = function(editor, iframeUrl) {
  30242. var cmd = "emotion";
  30243. var ui = new editorui.MultiMenuPop({
  30244. title:
  30245. editor.options.labelMap[cmd] ||
  30246. editor.getLang("labelMap." + cmd + "") ||
  30247. "",
  30248. editor: editor,
  30249. className: "edui-for-" + cmd,
  30250. iframeUrl: editor.ui.mapUrl(
  30251. iframeUrl ||
  30252. (editor.options.iframeUrlMap || {})[cmd] ||
  30253. iframeUrlMap[cmd]
  30254. )
  30255. });
  30256. editorui.buttons[cmd] = ui;
  30257. editor.addListener("selectionchange", function() {
  30258. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  30259. });
  30260. return ui;
  30261. };
  30262. editorui.autotypeset = function(editor) {
  30263. var ui = new editorui.AutoTypeSetButton({
  30264. editor: editor,
  30265. title:
  30266. editor.options.labelMap["autotypeset"] ||
  30267. editor.getLang("labelMap.autotypeset") ||
  30268. "",
  30269. className: "edui-for-autotypeset",
  30270. onbuttonclick: function() {
  30271. editor.execCommand("autotypeset");
  30272. }
  30273. });
  30274. editorui.buttons["autotypeset"] = ui;
  30275. editor.addListener("selectionchange", function() {
  30276. ui.setDisabled(editor.queryCommandState("autotypeset") == -1);
  30277. });
  30278. return ui;
  30279. };
  30280. /* 简单上传插件 */
  30281. editorui["simpleupload"] = function(editor) {
  30282. var name = "simpleupload",
  30283. ui = new editorui.Button({
  30284. className: "edui-for-" + name,
  30285. title:
  30286. editor.options.labelMap[name] ||
  30287. editor.getLang("labelMap." + name) ||
  30288. "",
  30289. onclick: function() {},
  30290. theme: editor.options.theme,
  30291. showText: false
  30292. });
  30293. editorui.buttons[name] = ui;
  30294. editor.addListener("ready", function() {
  30295. var b = ui.getDom("body"),
  30296. iconSpan = b.children[0];
  30297. editor.fireEvent("simpleuploadbtnready", iconSpan);
  30298. });
  30299. editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
  30300. var state = editor.queryCommandState(name);
  30301. if (state == -1) {
  30302. ui.setDisabled(true);
  30303. ui.setChecked(false);
  30304. } else {
  30305. if (!uiReady) {
  30306. ui.setDisabled(false);
  30307. ui.setChecked(state);
  30308. }
  30309. }
  30310. });
  30311. return ui;
  30312. };
  30313. })();
  30314. // adapter/editor.js
  30315. ///import core
  30316. ///commands 全屏
  30317. ///commandsName FullScreen
  30318. ///commandsTitle 全屏
  30319. ;(function() {
  30320. var utils = baidu.editor.utils,
  30321. uiUtils = baidu.editor.ui.uiUtils,
  30322. UIBase = baidu.editor.ui.UIBase,
  30323. domUtils = baidu.editor.dom.domUtils;
  30324. var nodeStack = [];
  30325. function EditorUI(options) {
  30326. this.initOptions(options);
  30327. this.initEditorUI();
  30328. }
  30329. EditorUI.prototype = {
  30330. uiName: "editor",
  30331. initEditorUI: function() {
  30332. this.editor.ui = this;
  30333. this._dialogs = {};
  30334. this.initUIBase();
  30335. this._initToolbars();
  30336. var editor = this.editor,
  30337. me = this;
  30338. editor.addListener("ready", function() {
  30339. //提供getDialog方法
  30340. editor.getDialog = function(name) {
  30341. return editor.ui._dialogs[name + "Dialog"];
  30342. };
  30343. domUtils.on(editor.window, "scroll", function(evt) {
  30344. baidu.editor.ui.Popup.postHide(evt);
  30345. });
  30346. //提供编辑器实时宽高(全屏时宽高不变化)
  30347. editor.ui._actualFrameWidth = editor.options.initialFrameWidth;
  30348. UE.browser.ie &&
  30349. UE.browser.version === 6 &&
  30350. editor.container.ownerDocument.execCommand(
  30351. "BackgroundImageCache",
  30352. false,
  30353. true
  30354. );
  30355. //display bottom-bar label based on config
  30356. if (editor.options.elementPathEnabled) {
  30357. editor.ui.getDom("elementpath").innerHTML =
  30358. '<div class="edui-editor-breadcrumb">' +
  30359. editor.getLang("elementPathTip") +
  30360. ":</div>";
  30361. }
  30362. if (editor.options.wordCount) {
  30363. function countFn() {
  30364. setCount(editor, me);
  30365. domUtils.un(editor.document, "click", arguments.callee);
  30366. }
  30367. domUtils.on(editor.document, "click", countFn);
  30368. editor.ui.getDom("wordcount").innerHTML = editor.getLang(
  30369. "wordCountTip"
  30370. );
  30371. }
  30372. editor.ui._scale();
  30373. if (editor.options.scaleEnabled) {
  30374. if (editor.autoHeightEnabled) {
  30375. editor.disableAutoHeight();
  30376. }
  30377. me.enableScale();
  30378. } else {
  30379. me.disableScale();
  30380. }
  30381. if (
  30382. !editor.options.elementPathEnabled &&
  30383. !editor.options.wordCount &&
  30384. !editor.options.scaleEnabled
  30385. ) {
  30386. editor.ui.getDom("elementpath").style.display = "none";
  30387. editor.ui.getDom("wordcount").style.display = "none";
  30388. editor.ui.getDom("scale").style.display = "none";
  30389. }
  30390. if (!editor.selection.isFocus()) return;
  30391. editor.fireEvent("selectionchange", false, true);
  30392. });
  30393. editor.addListener("mousedown", function(t, evt) {
  30394. var el = evt.target || evt.srcElement;
  30395. baidu.editor.ui.Popup.postHide(evt, el);
  30396. baidu.editor.ui.ShortCutMenu.postHide(evt);
  30397. });
  30398. editor.addListener("delcells", function() {
  30399. if (UE.ui["edittip"]) {
  30400. new UE.ui["edittip"](editor);
  30401. }
  30402. editor.getDialog("edittip").open();
  30403. });
  30404. var pastePop,
  30405. isPaste = false,
  30406. timer;
  30407. editor.addListener("afterpaste", function() {
  30408. if (editor.queryCommandState("pasteplain")) return;
  30409. if (baidu.editor.ui.PastePicker) {
  30410. pastePop = new baidu.editor.ui.Popup({
  30411. content: new baidu.editor.ui.PastePicker({ editor: editor }),
  30412. editor: editor,
  30413. className: "edui-wordpastepop"
  30414. });
  30415. pastePop.render();
  30416. }
  30417. isPaste = true;
  30418. });
  30419. editor.addListener("afterinserthtml", function() {
  30420. clearTimeout(timer);
  30421. timer = setTimeout(function() {
  30422. if (pastePop && (isPaste || editor.ui._isTransfer)) {
  30423. if (pastePop.isHidden()) {
  30424. var span = domUtils.createElement(editor.document, "span", {
  30425. style: "line-height:0px;",
  30426. innerHTML: "\ufeff"
  30427. }),
  30428. range = editor.selection.getRange();
  30429. range.insertNode(span);
  30430. var tmp = getDomNode(span, "firstChild", "previousSibling");
  30431. tmp &&
  30432. pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp);
  30433. domUtils.remove(span);
  30434. } else {
  30435. pastePop.show();
  30436. }
  30437. delete editor.ui._isTransfer;
  30438. isPaste = false;
  30439. }
  30440. }, 200);
  30441. });
  30442. editor.addListener("contextmenu", function(t, evt) {
  30443. baidu.editor.ui.Popup.postHide(evt);
  30444. });
  30445. editor.addListener("keydown", function(t, evt) {
  30446. if (pastePop) pastePop.dispose(evt);
  30447. var keyCode = evt.keyCode || evt.which;
  30448. if (evt.altKey && keyCode == 90) {
  30449. UE.ui.buttons["fullscreen"].onclick();
  30450. }
  30451. });
  30452. editor.addListener("wordcount", function(type) {
  30453. setCount(this, me);
  30454. });
  30455. function setCount(editor, ui) {
  30456. editor.setOpt({
  30457. wordCount: true,
  30458. maximumWords: 10000,
  30459. wordCountMsg:
  30460. editor.options.wordCountMsg || editor.getLang("wordCountMsg"),
  30461. wordOverFlowMsg:
  30462. editor.options.wordOverFlowMsg || editor.getLang("wordOverFlowMsg")
  30463. });
  30464. var opt = editor.options,
  30465. max = opt.maximumWords,
  30466. msg = opt.wordCountMsg,
  30467. errMsg = opt.wordOverFlowMsg,
  30468. countDom = ui.getDom("wordcount");
  30469. if (!opt.wordCount) {
  30470. return;
  30471. }
  30472. var count = editor.getContentLength(true);
  30473. if (count > max) {
  30474. countDom.innerHTML = errMsg;
  30475. editor.fireEvent("wordcountoverflow");
  30476. } else {
  30477. countDom.innerHTML = msg
  30478. .replace("{#leave}", max - count)
  30479. .replace("{#count}", count);
  30480. }
  30481. }
  30482. editor.addListener("selectionchange", function() {
  30483. if (editor.options.elementPathEnabled) {
  30484. me[
  30485. (editor.queryCommandState("elementpath") == -1 ? "dis" : "en") +
  30486. "ableElementPath"
  30487. ]();
  30488. }
  30489. if (editor.options.scaleEnabled) {
  30490. me[
  30491. (editor.queryCommandState("scale") == -1 ? "dis" : "en") +
  30492. "ableScale"
  30493. ]();
  30494. }
  30495. });
  30496. var popup = new baidu.editor.ui.Popup({
  30497. editor: editor,
  30498. content: "",
  30499. className: "edui-bubble",
  30500. _onEditButtonClick: function() {
  30501. this.hide();
  30502. editor.ui._dialogs.linkDialog.open();
  30503. },
  30504. _onImgEditButtonClick: function(name) {
  30505. this.hide();
  30506. editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
  30507. },
  30508. _onImgSetFloat: function(value) {
  30509. this.hide();
  30510. editor.execCommand("imagefloat", value);
  30511. },
  30512. _setIframeAlign: function(value) {
  30513. var frame = popup.anchorEl;
  30514. var newFrame = frame.cloneNode(true);
  30515. switch (value) {
  30516. case -2:
  30517. newFrame.setAttribute("align", "");
  30518. break;
  30519. case -1:
  30520. newFrame.setAttribute("align", "left");
  30521. break;
  30522. case 1:
  30523. newFrame.setAttribute("align", "right");
  30524. break;
  30525. }
  30526. frame.parentNode.insertBefore(newFrame, frame);
  30527. domUtils.remove(frame);
  30528. popup.anchorEl = newFrame;
  30529. popup.showAnchor(popup.anchorEl);
  30530. },
  30531. _updateIframe: function() {
  30532. var frame = (editor._iframe = popup.anchorEl);
  30533. if (domUtils.hasClass(frame, "ueditor_baidumap")) {
  30534. editor.selection.getRange().selectNode(frame).select();
  30535. editor.ui._dialogs.mapDialog.open();
  30536. popup.hide();
  30537. } else {
  30538. editor.ui._dialogs.insertframeDialog.open();
  30539. popup.hide();
  30540. }
  30541. },
  30542. _onRemoveButtonClick: function(cmdName) {
  30543. editor.execCommand(cmdName);
  30544. this.hide();
  30545. },
  30546. queryAutoHide: function(el) {
  30547. if (el && el.ownerDocument == editor.document) {
  30548. if (
  30549. el.tagName.toLowerCase() == "img" ||
  30550. domUtils.findParentByTagName(el, "a", true)
  30551. ) {
  30552. return el !== popup.anchorEl;
  30553. }
  30554. }
  30555. return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el);
  30556. }
  30557. });
  30558. popup.render();
  30559. if (editor.options.imagePopup) {
  30560. editor.addListener("mouseover", function(t, evt) {
  30561. evt = evt || window.event;
  30562. var el = evt.target || evt.srcElement;
  30563. if (
  30564. editor.ui._dialogs.insertframeDialog &&
  30565. /iframe/gi.test(el.tagName)
  30566. ) {
  30567. var html = popup.formatHtml(
  30568. "<nobr>" +
  30569. editor.getLang("property") +
  30570. ': <span onclick=$$._setIframeAlign(-2) class="edui-clickable">' +
  30571. editor.getLang("default") +
  30572. '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(-1) class="edui-clickable">' +
  30573. editor.getLang("justifyleft") +
  30574. '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(1) class="edui-clickable">' +
  30575. editor.getLang("justifyright") +
  30576. "</span>&nbsp;&nbsp;" +
  30577. ' <span onclick="$$._updateIframe( this);" class="edui-clickable">' +
  30578. editor.getLang("modify") +
  30579. "</span></nobr>"
  30580. );
  30581. if (html) {
  30582. popup.getDom("content").innerHTML = html;
  30583. popup.anchorEl = el;
  30584. popup.showAnchor(popup.anchorEl);
  30585. } else {
  30586. popup.hide();
  30587. }
  30588. }
  30589. });
  30590. editor.addListener("selectionchange", function(t, causeByUi) {
  30591. if (!causeByUi) return;
  30592. var html = "",
  30593. str = "",
  30594. img = editor.selection.getRange().getClosedNode(),
  30595. dialogs = editor.ui._dialogs;
  30596. if (img && img.tagName == "IMG") {
  30597. var dialogName = "insertimageDialog";
  30598. if (
  30599. img.className.indexOf("edui-faked-video") != -1 ||
  30600. img.className.indexOf("edui-upload-video") != -1
  30601. ) {
  30602. dialogName = "insertvideoDialog";
  30603. }
  30604. if (img.className.indexOf("edui-faked-webapp") != -1) {
  30605. dialogName = "webappDialog";
  30606. }
  30607. if (img.src.indexOf("https://api.map.baidu.com") != -1) {
  30608. dialogName = "mapDialog";
  30609. }
  30610. if (img.className.indexOf("edui-faked-music") != -1) {
  30611. dialogName = "musicDialog";
  30612. }
  30613. if (
  30614. img.src.indexOf("http://maps.google.com/maps/api/staticmap") != -1
  30615. ) {
  30616. dialogName = "gmapDialog";
  30617. }
  30618. if (img.getAttribute("anchorname")) {
  30619. dialogName = "anchorDialog";
  30620. html = popup.formatHtml(
  30621. "<nobr>" +
  30622. editor.getLang("property") +
  30623. ': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' +
  30624. editor.getLang("modify") +
  30625. "</span>&nbsp;&nbsp;" +
  30626. "<span onclick=$$._onRemoveButtonClick('anchor') class=\"edui-clickable\">" +
  30627. editor.getLang("delete") +
  30628. "</span></nobr>"
  30629. );
  30630. }
  30631. if (img.getAttribute("word_img")) {
  30632. //todo 放到dialog去做查询
  30633. editor.word_img = [img.getAttribute("word_img")];
  30634. dialogName = "wordimageDialog";
  30635. }
  30636. if (
  30637. domUtils.hasClass(img, "loadingclass") ||
  30638. domUtils.hasClass(img, "loaderrorclass")
  30639. ) {
  30640. dialogName = "";
  30641. }
  30642. if (!dialogs[dialogName]) {
  30643. return;
  30644. }
  30645. str =
  30646. "<nobr>" +
  30647. editor.getLang("property") +
  30648. ": " +
  30649. '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' +
  30650. editor.getLang("default") +
  30651. "</span>&nbsp;&nbsp;" +
  30652. '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' +
  30653. editor.getLang("justifyleft") +
  30654. "</span>&nbsp;&nbsp;" +
  30655. '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' +
  30656. editor.getLang("justifyright") +
  30657. "</span>&nbsp;&nbsp;" +
  30658. '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' +
  30659. editor.getLang("justifycenter") +
  30660. "</span>&nbsp;&nbsp;" +
  30661. "<span onclick=\"$$._onImgEditButtonClick('" +
  30662. dialogName +
  30663. '\');" class="edui-clickable">' +
  30664. editor.getLang("modify") +
  30665. "</span></nobr>";
  30666. !html && (html = popup.formatHtml(str));
  30667. }
  30668. if (editor.ui._dialogs.linkDialog) {
  30669. var link = editor.queryCommandValue("link");
  30670. var url;
  30671. if (
  30672. link &&
  30673. (url = link.getAttribute("_href") || link.getAttribute("href", 2))
  30674. ) {
  30675. var txt = url;
  30676. if (url.length > 30) {
  30677. txt = url.substring(0, 20) + "...";
  30678. }
  30679. if (html) {
  30680. html += '<div style="height:5px;"></div>';
  30681. }
  30682. html += popup.formatHtml(
  30683. "<nobr>" +
  30684. editor.getLang("anthorMsg") +
  30685. ': <a target="_blank" href="' +
  30686. url +
  30687. '" title="' +
  30688. url +
  30689. '" >' +
  30690. txt +
  30691. "</a>" +
  30692. ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' +
  30693. editor.getLang("modify") +
  30694. "</span>" +
  30695. ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' +
  30696. editor.getLang("clear") +
  30697. "</span></nobr>"
  30698. );
  30699. popup.showAnchor(link);
  30700. }
  30701. }
  30702. if (html) {
  30703. popup.getDom("content").innerHTML = html;
  30704. popup.anchorEl = img || link;
  30705. popup.showAnchor(popup.anchorEl);
  30706. } else {
  30707. popup.hide();
  30708. }
  30709. });
  30710. }
  30711. },
  30712. _initToolbars: function() {
  30713. var editor = this.editor;
  30714. var toolbars = this.toolbars || [];
  30715. var toolbarUis = [];
  30716. var extraUIs = [];
  30717. for (var i = 0; i < toolbars.length; i++) {
  30718. var toolbar = toolbars[i];
  30719. var toolbarUi = new baidu.editor.ui.Toolbar({
  30720. theme: editor.options.theme
  30721. });
  30722. for (var j = 0; j < toolbar.length; j++) {
  30723. var toolbarItem = toolbar[j];
  30724. var toolbarItemUi = null;
  30725. if (typeof toolbarItem == "string") {
  30726. toolbarItem = toolbarItem.toLowerCase();
  30727. if (toolbarItem == "|") {
  30728. toolbarItem = "Separator";
  30729. }
  30730. if (toolbarItem == "||") {
  30731. toolbarItem = "Breakline";
  30732. }
  30733. var ui = baidu.editor.ui[toolbarItem];
  30734. if (ui) {
  30735. if (utils.isFunction(ui)) {
  30736. toolbarItemUi = new baidu.editor.ui[toolbarItem](editor);
  30737. } else {
  30738. if (ui.id && ui.id != editor.key) {
  30739. continue;
  30740. }
  30741. var itemUI = ui.execFn.call(editor, editor, toolbarItem);
  30742. if (itemUI) {
  30743. if (ui.index === undefined) {
  30744. toolbarUi.add(itemUI);
  30745. continue;
  30746. } else {
  30747. extraUIs.push({
  30748. index: ui.index,
  30749. itemUI: itemUI
  30750. });
  30751. }
  30752. }
  30753. }
  30754. }
  30755. //fullscreen这里单独处理一下,放到首行去
  30756. if (toolbarItem == "fullscreen") {
  30757. if (toolbarUis && toolbarUis[0]) {
  30758. toolbarUis[0].items.splice(0, 0, toolbarItemUi);
  30759. } else {
  30760. toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi);
  30761. }
  30762. continue;
  30763. }
  30764. } else {
  30765. toolbarItemUi = toolbarItem;
  30766. }
  30767. if (toolbarItemUi && toolbarItemUi.id) {
  30768. toolbarUi.add(toolbarItemUi);
  30769. }
  30770. }
  30771. toolbarUis[i] = toolbarUi;
  30772. }
  30773. //接受外部定制的UI
  30774. utils.each(extraUIs, function(obj) {
  30775. toolbarUi.add(obj.itemUI, obj.index);
  30776. });
  30777. this.toolbars = toolbarUis;
  30778. },
  30779. getHtmlTpl: function() {
  30780. return (
  30781. '<div id="##" class="%%">' +
  30782. '<div id="##_toolbarbox" class="%%-toolbarbox">' +
  30783. (this.toolbars.length
  30784. ? '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
  30785. this.renderToolbarBoxHtml() +
  30786. "</div></div>"
  30787. : "") +
  30788. '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
  30789. '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' +
  30790. this.editor.getLang("clickToUpload") +
  30791. "</div>" +
  30792. '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
  30793. '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
  30794. '<div style="height:0;overflow:hidden;clear:both;"></div>' +
  30795. "</div>" +
  30796. '<div id="##_message_holder" class="%%-messageholder"></div>' +
  30797. "</div>" +
  30798. '<div id="##_iframeholder" class="%%-iframeholder">' +
  30799. "</div>" +
  30800. //modify wdcount by matao
  30801. '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
  30802. '<td id="##_elementpath" class="%%-bottombar"></td>' +
  30803. '<td id="##_wordcount" class="%%-wordcount"></td>' +
  30804. '<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
  30805. "</tr></table></div>" +
  30806. '<div id="##_scalelayer"></div>' +
  30807. "</div>"
  30808. );
  30809. },
  30810. showWordImageDialog: function() {
  30811. this._dialogs["wordimageDialog"].open();
  30812. },
  30813. renderToolbarBoxHtml: function() {
  30814. var buff = [];
  30815. for (var i = 0; i < this.toolbars.length; i++) {
  30816. buff.push(this.toolbars[i].renderHtml());
  30817. }
  30818. return buff.join("");
  30819. },
  30820. setFullScreen: function(fullscreen) {
  30821. var editor = this.editor,
  30822. container = editor.container.parentNode.parentNode;
  30823. if (this._fullscreen != fullscreen) {
  30824. this._fullscreen = fullscreen;
  30825. this.editor.fireEvent("beforefullscreenchange", fullscreen);
  30826. if (baidu.editor.browser.gecko) {
  30827. var bk = editor.selection.getRange().createBookmark();
  30828. }
  30829. if (fullscreen) {
  30830. while (container.tagName != "BODY") {
  30831. var position = baidu.editor.dom.domUtils.getComputedStyle(
  30832. container,
  30833. "position"
  30834. );
  30835. nodeStack.push(position);
  30836. container.style.position = "static";
  30837. container = container.parentNode;
  30838. }
  30839. this._bakHtmlOverflow = document.documentElement.style.overflow;
  30840. this._bakBodyOverflow = document.body.style.overflow;
  30841. this._bakAutoHeight = this.editor.autoHeightEnabled;
  30842. this._bakScrollTop = Math.max(
  30843. document.documentElement.scrollTop,
  30844. document.body.scrollTop
  30845. );
  30846. this._bakEditorContaninerWidth = editor.iframe.parentNode.offsetWidth;
  30847. if (this._bakAutoHeight) {
  30848. //当全屏时不能执行自动长高
  30849. editor.autoHeightEnabled = false;
  30850. this.editor.disableAutoHeight();
  30851. }
  30852. document.documentElement.style.overflow = "hidden";
  30853. //修复,滚动条不收起的问题
  30854. window.scrollTo(0, window.scrollY);
  30855. this._bakCssText = this.getDom().style.cssText;
  30856. this._bakCssText1 = this.getDom("iframeholder").style.cssText;
  30857. editor.iframe.parentNode.style.width = "";
  30858. this._updateFullScreen();
  30859. } else {
  30860. while (container.tagName != "BODY") {
  30861. container.style.position = nodeStack.shift();
  30862. container = container.parentNode;
  30863. }
  30864. this.getDom().style.cssText = this._bakCssText;
  30865. this.getDom("iframeholder").style.cssText = this._bakCssText1;
  30866. if (this._bakAutoHeight) {
  30867. editor.autoHeightEnabled = true;
  30868. this.editor.enableAutoHeight();
  30869. }
  30870. document.documentElement.style.overflow = this._bakHtmlOverflow;
  30871. document.body.style.overflow = this._bakBodyOverflow;
  30872. editor.iframe.parentNode.style.width =
  30873. this._bakEditorContaninerWidth + "px";
  30874. window.scrollTo(0, this._bakScrollTop);
  30875. }
  30876. if (browser.gecko && editor.body.contentEditable === "true") {
  30877. var input = document.createElement("input");
  30878. document.body.appendChild(input);
  30879. editor.body.contentEditable = false;
  30880. setTimeout(function() {
  30881. input.focus();
  30882. setTimeout(function() {
  30883. editor.body.contentEditable = true;
  30884. editor.fireEvent("fullscreenchanged", fullscreen);
  30885. editor.selection.getRange().moveToBookmark(bk).select(true);
  30886. baidu.editor.dom.domUtils.remove(input);
  30887. fullscreen && window.scroll(0, 0);
  30888. }, 0);
  30889. }, 0);
  30890. }
  30891. if (editor.body.contentEditable === "true") {
  30892. this.editor.fireEvent("fullscreenchanged", fullscreen);
  30893. this.triggerLayout();
  30894. }
  30895. }
  30896. },
  30897. _updateFullScreen: function() {
  30898. if (this._fullscreen) {
  30899. var vpRect = uiUtils.getViewportRect();
  30900. this.getDom().style.cssText =
  30901. "border:0;position:absolute;left:0;top:" +
  30902. (this.editor.options.topOffset || 0) +
  30903. "px;width:" +
  30904. vpRect.width +
  30905. "px;height:" +
  30906. vpRect.height +
  30907. "px;z-index:" +
  30908. (this.getDom().style.zIndex * 1 + 100);
  30909. uiUtils.setViewportOffset(this.getDom(), {
  30910. left: 0,
  30911. top: this.editor.options.topOffset || 0
  30912. });
  30913. this.editor.setHeight(
  30914. vpRect.height -
  30915. this.getDom("toolbarbox").offsetHeight -
  30916. this.getDom("bottombar").offsetHeight -
  30917. (this.editor.options.topOffset || 0),
  30918. true
  30919. );
  30920. //不手动调一下,会导致全屏失效
  30921. if (browser.gecko) {
  30922. try {
  30923. window.onresize();
  30924. } catch (e) {}
  30925. }
  30926. }
  30927. },
  30928. _updateElementPath: function() {
  30929. var bottom = this.getDom("elementpath"),
  30930. list;
  30931. if (
  30932. this.elementPathEnabled &&
  30933. (list = this.editor.queryCommandValue("elementpath"))
  30934. ) {
  30935. var buff = [];
  30936. for (var i = 0, ci; (ci = list[i]); i++) {
  30937. buff[i] = this.formatHtml(
  30938. '<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' +
  30939. i +
  30940. '&quot;);">' +
  30941. ci +
  30942. "</span>"
  30943. );
  30944. }
  30945. bottom.innerHTML =
  30946. '<div class="edui-editor-breadcrumb" onmousedown="return false;">' +
  30947. this.editor.getLang("elementPathTip") +
  30948. ": " +
  30949. buff.join(" &gt; ") +
  30950. "</div>";
  30951. } else {
  30952. bottom.style.display = "none";
  30953. }
  30954. },
  30955. disableElementPath: function() {
  30956. var bottom = this.getDom("elementpath");
  30957. bottom.innerHTML = "";
  30958. bottom.style.display = "none";
  30959. this.elementPathEnabled = false;
  30960. },
  30961. enableElementPath: function() {
  30962. var bottom = this.getDom("elementpath");
  30963. bottom.style.display = "";
  30964. this.elementPathEnabled = true;
  30965. this._updateElementPath();
  30966. },
  30967. _scale: function() {
  30968. var doc = document,
  30969. editor = this.editor,
  30970. editorHolder = editor.container,
  30971. editorDocument = editor.document,
  30972. toolbarBox = this.getDom("toolbarbox"),
  30973. bottombar = this.getDom("bottombar"),
  30974. scale = this.getDom("scale"),
  30975. scalelayer = this.getDom("scalelayer");
  30976. var isMouseMove = false,
  30977. position = null,
  30978. minEditorHeight = 0,
  30979. minEditorWidth = editor.options.minFrameWidth,
  30980. pageX = 0,
  30981. pageY = 0,
  30982. scaleWidth = 0,
  30983. scaleHeight = 0;
  30984. function down() {
  30985. position = domUtils.getXY(editorHolder);
  30986. if (!minEditorHeight) {
  30987. minEditorHeight =
  30988. editor.options.minFrameHeight +
  30989. toolbarBox.offsetHeight +
  30990. bottombar.offsetHeight;
  30991. }
  30992. scalelayer.style.cssText =
  30993. "position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:" +
  30994. editorHolder.offsetWidth +
  30995. "px;height:" +
  30996. editorHolder.offsetHeight +
  30997. "px;z-index:" +
  30998. (editor.options.zIndex + 1);
  30999. domUtils.on(doc, "mousemove", move);
  31000. domUtils.on(editorDocument, "mouseup", up);
  31001. domUtils.on(doc, "mouseup", up);
  31002. }
  31003. var me = this;
  31004. //by xuheng 全屏时关掉缩放
  31005. this.editor.addListener("fullscreenchanged", function(e, fullScreen) {
  31006. if (fullScreen) {
  31007. me.disableScale();
  31008. } else {
  31009. if (me.editor.options.scaleEnabled) {
  31010. me.enableScale();
  31011. var tmpNode = me.editor.document.createElement("span");
  31012. me.editor.body.appendChild(tmpNode);
  31013. me.editor.body.style.height =
  31014. Math.max(
  31015. domUtils.getXY(tmpNode).y,
  31016. me.editor.iframe.offsetHeight - 20
  31017. ) + "px";
  31018. domUtils.remove(tmpNode);
  31019. }
  31020. }
  31021. });
  31022. function move(event) {
  31023. clearSelection();
  31024. var e = event || window.event;
  31025. pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX;
  31026. pageY = e.pageY || doc.documentElement.scrollTop + e.clientY;
  31027. scaleWidth = pageX - position.x;
  31028. scaleHeight = pageY - position.y;
  31029. if (scaleWidth >= minEditorWidth) {
  31030. isMouseMove = true;
  31031. scalelayer.style.width = scaleWidth + "px";
  31032. }
  31033. if (scaleHeight >= minEditorHeight) {
  31034. isMouseMove = true;
  31035. scalelayer.style.height = scaleHeight + "px";
  31036. }
  31037. }
  31038. function up() {
  31039. if (isMouseMove) {
  31040. isMouseMove = false;
  31041. editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
  31042. editorHolder.style.width = editor.ui._actualFrameWidth + "px";
  31043. editor.setHeight(
  31044. scalelayer.offsetHeight -
  31045. bottombar.offsetHeight -
  31046. toolbarBox.offsetHeight -
  31047. 2,
  31048. true
  31049. );
  31050. }
  31051. if (scalelayer) {
  31052. scalelayer.style.display = "none";
  31053. }
  31054. clearSelection();
  31055. domUtils.un(doc, "mousemove", move);
  31056. domUtils.un(editorDocument, "mouseup", up);
  31057. domUtils.un(doc, "mouseup", up);
  31058. }
  31059. function clearSelection() {
  31060. if (browser.ie) doc.selection.clear();
  31061. else window.getSelection().removeAllRanges();
  31062. }
  31063. this.enableScale = function() {
  31064. //trace:2868
  31065. if (editor.queryCommandState("source") == 1) return;
  31066. scale.style.display = "";
  31067. this.scaleEnabled = true;
  31068. domUtils.on(scale, "mousedown", down);
  31069. };
  31070. this.disableScale = function() {
  31071. scale.style.display = "none";
  31072. this.scaleEnabled = false;
  31073. domUtils.un(scale, "mousedown", down);
  31074. };
  31075. },
  31076. isFullScreen: function() {
  31077. return this._fullscreen;
  31078. },
  31079. postRender: function() {
  31080. UIBase.prototype.postRender.call(this);
  31081. for (var i = 0; i < this.toolbars.length; i++) {
  31082. this.toolbars[i].postRender();
  31083. }
  31084. var me = this;
  31085. var timerId,
  31086. domUtils = baidu.editor.dom.domUtils,
  31087. updateFullScreenTime = function() {
  31088. clearTimeout(timerId);
  31089. timerId = setTimeout(function() {
  31090. me._updateFullScreen();
  31091. });
  31092. };
  31093. domUtils.on(window, "resize", updateFullScreenTime);
  31094. me.addListener("destroy", function() {
  31095. domUtils.un(window, "resize", updateFullScreenTime);
  31096. clearTimeout(timerId);
  31097. });
  31098. },
  31099. showToolbarMsg: function(msg, flag) {
  31100. this.getDom("toolbarmsg_label").innerHTML = msg;
  31101. this.getDom("toolbarmsg").style.display = "";
  31102. //
  31103. if (!flag) {
  31104. var w = this.getDom("upload_dialog");
  31105. w.style.display = "none";
  31106. }
  31107. },
  31108. hideToolbarMsg: function() {
  31109. this.getDom("toolbarmsg").style.display = "none";
  31110. },
  31111. mapUrl: function(url) {
  31112. return url
  31113. ? url.replace("~/", this.editor.options.UEDITOR_HOME_URL || "")
  31114. : "";
  31115. },
  31116. triggerLayout: function() {
  31117. var dom = this.getDom();
  31118. if (dom.style.zoom == "1") {
  31119. dom.style.zoom = "100%";
  31120. } else {
  31121. dom.style.zoom = "1";
  31122. }
  31123. }
  31124. };
  31125. utils.inherits(EditorUI, baidu.editor.ui.UIBase);
  31126. var instances = {};
  31127. UE.ui.Editor = function(options) {
  31128. var editor = new UE.Editor(options);
  31129. editor.options.editor = editor;
  31130. utils.loadFile(document, {
  31131. href:
  31132. editor.options.themePath + editor.options.theme + "/css/neditor.css",
  31133. tag: "link",
  31134. type: "text/css",
  31135. rel: "stylesheet"
  31136. });
  31137. var oldRender = editor.render;
  31138. editor.render = function(holder) {
  31139. if (holder.constructor === String) {
  31140. editor.key = holder;
  31141. instances[holder] = editor;
  31142. }
  31143. utils.domReady(function() {
  31144. editor.langIsReady
  31145. ? renderUI()
  31146. : editor.addListener("langReady", renderUI);
  31147. function renderUI() {
  31148. editor.setOpt({
  31149. labelMap: editor.options.labelMap || editor.getLang("labelMap")
  31150. });
  31151. new EditorUI(editor.options);
  31152. if (holder) {
  31153. if (holder.constructor === String) {
  31154. holder = document.getElementById(holder);
  31155. }
  31156. holder &&
  31157. holder.getAttribute("name") &&
  31158. (editor.options.textarea = holder.getAttribute("name"));
  31159. if (holder && /script|textarea/gi.test(holder.tagName)) {
  31160. var newDiv = document.createElement("div");
  31161. holder.parentNode.insertBefore(newDiv, holder);
  31162. var cont = holder.value || holder.innerHTML;
  31163. editor.options.initialContent = /^[\t\r\n ]*$/.test(cont)
  31164. ? editor.options.initialContent
  31165. : cont
  31166. .replace(/>[\n\r\t]+([ ]{4})+/g, ">")
  31167. .replace(/[\n\r\t]+([ ]{4})+</g, "<")
  31168. .replace(/>[\n\r\t]+</g, "><");
  31169. holder.className && (newDiv.className = holder.className);
  31170. holder.style.cssText &&
  31171. (newDiv.style.cssText = holder.style.cssText);
  31172. if (/textarea/i.test(holder.tagName)) {
  31173. editor.textarea = holder;
  31174. editor.textarea.style.display = "none";
  31175. } else {
  31176. holder.parentNode.removeChild(holder);
  31177. }
  31178. if (holder.id) {
  31179. newDiv.id = holder.id;
  31180. domUtils.removeAttributes(holder, "id");
  31181. }
  31182. holder = newDiv;
  31183. holder.innerHTML = "";
  31184. }
  31185. }
  31186. domUtils.addClass(holder, "edui-" + editor.options.theme);
  31187. editor.ui.render(holder);
  31188. var opt = editor.options;
  31189. //给实例添加一个编辑器的容器引用
  31190. editor.container = editor.ui.getDom();
  31191. var parents = domUtils.findParents(holder, true);
  31192. var displays = [];
  31193. for (var i = 0, ci; (ci = parents[i]); i++) {
  31194. displays[i] = ci.style.display;
  31195. ci.style.display = "block";
  31196. }
  31197. if (opt.initialFrameWidth) {
  31198. opt.minFrameWidth = opt.initialFrameWidth;
  31199. } else {
  31200. opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth;
  31201. var styleWidth = holder.style.width;
  31202. if (/%$/.test(styleWidth)) {
  31203. opt.initialFrameWidth = styleWidth;
  31204. }
  31205. }
  31206. if (opt.initialFrameHeight) {
  31207. opt.minFrameHeight = opt.initialFrameHeight;
  31208. } else {
  31209. opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight;
  31210. }
  31211. for (var i = 0, ci; (ci = parents[i]); i++) {
  31212. ci.style.display = displays[i];
  31213. }
  31214. //编辑器最外容器设置了高度,会导致,编辑器不占位
  31215. //todo 先去掉,没有找到原因
  31216. if (holder.style.height) {
  31217. holder.style.height = "";
  31218. }
  31219. editor.container.style.width =
  31220. opt.initialFrameWidth +
  31221. (/%$/.test(opt.initialFrameWidth) ? "" : "px");
  31222. editor.container.style.zIndex = opt.zIndex;
  31223. oldRender.call(editor, editor.ui.getDom("iframeholder"));
  31224. editor.fireEvent("afteruiready");
  31225. }
  31226. });
  31227. };
  31228. return editor;
  31229. };
  31230. /**
  31231. * @file
  31232. * @name UE
  31233. * @short UE
  31234. * @desc UEditor的顶部命名空间
  31235. */
  31236. /**
  31237. * @name getEditor
  31238. * @since 1.2.4+
  31239. * @grammar UE.getEditor(id,[opt]) => Editor实例
  31240. * @desc 提供一个全局的方法得到编辑器实例
  31241. *
  31242. * * ''id'' 放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
  31243. * * ''opt'' 编辑器的可选参数
  31244. * @example
  31245. * UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
  31246. * this.setContent('hello')
  31247. * }});
  31248. * UE.getEditor('containerId'); //返回刚创建的实例
  31249. *
  31250. */
  31251. UE.getEditor = function(id, opt) {
  31252. var editor = instances[id];
  31253. if (!editor) {
  31254. editor = instances[id] = new UE.ui.Editor(opt);
  31255. editor.render(id);
  31256. }
  31257. return editor;
  31258. };
  31259. UE.delEditor = function(id) {
  31260. var editor;
  31261. if ((editor = instances[id])) {
  31262. editor.key && editor.destroy();
  31263. delete instances[id];
  31264. }
  31265. };
  31266. UE.registerUI = function(uiName, fn, index, editorId) {
  31267. utils.each(uiName.split(/\s+/), function(name) {
  31268. baidu.editor.ui[name] = {
  31269. id: editorId,
  31270. execFn: fn,
  31271. index: index
  31272. };
  31273. });
  31274. };
  31275. })();
  31276. // adapter/message.js
  31277. UE.registerUI("message", function(editor) {
  31278. var editorui = baidu.editor.ui;
  31279. var Message = editorui.Message;
  31280. var holder;
  31281. var _messageItems = [];
  31282. var me = editor;
  31283. me.setOpt("enableMessageShow", true);
  31284. if (me.getOpt("enableMessageShow") === false) {
  31285. return;
  31286. }
  31287. me.addListener("ready", function() {
  31288. holder = document.getElementById(me.ui.id + "_message_holder");
  31289. updateHolderPos();
  31290. setTimeout(function() {
  31291. updateHolderPos();
  31292. }, 500);
  31293. });
  31294. me.addListener("showmessage", function(type, opt) {
  31295. opt = utils.isString(opt)
  31296. ? {
  31297. content: opt
  31298. }
  31299. : opt;
  31300. var message = new Message({
  31301. timeout: opt.timeout,
  31302. type: opt.type,
  31303. content: opt.content,
  31304. keepshow: opt.keepshow,
  31305. editor: me
  31306. }),
  31307. mid = opt.id || "msg_" + (+new Date()).toString(36);
  31308. message.render(holder);
  31309. _messageItems[mid] = message;
  31310. message.reset(opt);
  31311. updateHolderPos();
  31312. return mid;
  31313. });
  31314. me.addListener("updatemessage", function(type, id, opt) {
  31315. opt = utils.isString(opt)
  31316. ? {
  31317. content: opt
  31318. }
  31319. : opt;
  31320. var message = _messageItems[id];
  31321. message.render(holder);
  31322. message && message.reset(opt);
  31323. });
  31324. me.addListener("hidemessage", function(type, id) {
  31325. var message = _messageItems[id];
  31326. message && message.hide();
  31327. });
  31328. function updateHolderPos() {
  31329. if (!holder || !me.ui) return;
  31330. var toolbarbox = me.ui.getDom("toolbarbox");
  31331. if (toolbarbox) {
  31332. holder.style.top = toolbarbox.offsetHeight + 3 + "px";
  31333. }
  31334. holder.style.zIndex =
  31335. Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1;
  31336. }
  31337. });
  31338. // adapter/autosave.js
  31339. UE.registerUI("autosave", function(editor) {
  31340. var timer = null,
  31341. uid = null;
  31342. editor.on("afterautosave", function() {
  31343. clearTimeout(timer);
  31344. timer = setTimeout(function() {
  31345. if (uid) {
  31346. editor.trigger("hidemessage", uid);
  31347. }
  31348. uid = editor.trigger("showmessage", {
  31349. content: editor.getLang("autosave.success"),
  31350. timeout: 2000
  31351. });
  31352. }, 2000);
  31353. });
  31354. });
  31355. })();