editor_all.js 656 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642
  1. (function(){UEDITOR_CONFIG = window.UEDITOR_CONFIG || {};
  2. var baidu = window.baidu || {};
  3. window.baidu = baidu;
  4. window.UE = baidu.editor = {};
  5. UE.plugins = {};
  6. UE.commands = {};
  7. UE.instants = {};
  8. UE.I18N = {};
  9. //UE.defaultplugins = {};
  10. //
  11. //UE.commands = function(){
  12. // var commandList = {},tmpList= {};
  13. // return {
  14. //
  15. // register : function(commandsName,pluginName){
  16. // commandsName = commandsName.split(',');
  17. // for(var i= 0,ci;ci=commandsName[i++];){
  18. // commandList[ci] = pluginName;
  19. // }
  20. //
  21. // },
  22. // get : function(commandName){
  23. // return commandList[commandName];
  24. // },
  25. // getList : function(){
  26. // return commandList;
  27. // }
  28. // }
  29. //}();
  30. UE.version = "1.2.3.0";
  31. var dom = UE.dom = {};
  32. ///import editor.js
  33. /**
  34. * @class baidu.editor.browser 判断浏览器
  35. */
  36. var browser = UE.browser = function(){
  37. var agent = navigator.userAgent.toLowerCase(),
  38. opera = window.opera,
  39. browser = {
  40. /**
  41. * 检测浏览器是否为IE
  42. * @name baidu.editor.browser.ie
  43. * @property 检测浏览器是否为IE
  44. * @grammar baidu.editor.browser.ie
  45. * @return {Boolean} 返回是否为ie浏览器
  46. */
  47. ie : !!window.ActiveXObject,
  48. /**
  49. * 检测浏览器是否为Opera
  50. * @name baidu.editor.browser.opera
  51. * @property 检测浏览器是否为Opera
  52. * @grammar baidu.editor.browser.opera
  53. * @return {Boolean} 返回是否为opera浏览器
  54. */
  55. opera : ( !!opera && opera.version ),
  56. /**
  57. * 检测浏览器是否为WebKit内核
  58. * @name baidu.editor.browser.webkit
  59. * @property 检测浏览器是否为WebKit内核
  60. * @grammar baidu.editor.browser.webkit
  61. * @return {Boolean} 返回是否为WebKit内核
  62. */
  63. webkit : ( agent.indexOf( ' applewebkit/' ) > -1 ),
  64. /**
  65. * 检查是否为Macintosh系统
  66. * @name baidu.editor.browser.mac
  67. * @property 检查是否为Macintosh系统
  68. * @grammar baidu.editor.browser.mac
  69. * @return {Boolean} 返回是否为Macintosh系统
  70. */
  71. mac : ( agent.indexOf( 'macintosh' ) > -1 ),
  72. /**
  73. * 检查浏览器是否为quirks模式
  74. * @name baidu.editor.browser.quirks
  75. * @property 检查浏览器是否为quirks模式
  76. * @grammar baidu.editor.browser.quirks
  77. * @return {Boolean} 返回是否为quirks模式
  78. */
  79. quirks : ( document.compatMode == 'BackCompat' )
  80. };
  81. /**
  82. * 检测浏览器是否为Gecko内核,如Firefox
  83. * @name baidu.editor.browser.gecko
  84. * @property 检测浏览器是否为Gecko内核
  85. * @grammar baidu.editor.browser.gecko
  86. * @return {Boolean} 返回是否为Gecko内核
  87. */
  88. browser.gecko = ( navigator.product == 'Gecko' && !browser.webkit && !browser.opera );
  89. var version = 0;
  90. // Internet Explorer 6.0+
  91. if ( browser.ie )
  92. {
  93. version = parseFloat( agent.match( /msie (\d+)/ )[1] );
  94. /**
  95. * 检测浏览器是否为 IE9 模式
  96. */
  97. browser.ie9Compat = document.documentMode == 9;
  98. /**
  99. * 检测浏览器是否为 IE8 浏览器
  100. * @name baidu.editor.browser.IE8
  101. * @property 检测浏览器是否为 IE8 浏览器
  102. * @grammar baidu.editor.browser.IE8
  103. * @return {Boolean} 返回是否为 IE8 浏览器
  104. */
  105. browser.ie8 = !!document.documentMode;
  106. /**
  107. * 检测浏览器是否为 IE8 模式
  108. * @name baidu.editor.browser.ie8Compat
  109. * @property 检测浏览器是否为 IE8 模式
  110. * @grammar baidu.editor.browser.ie8Compat
  111. * @return {Boolean} 返回是否为 IE8 模式
  112. */
  113. browser.ie8Compat = document.documentMode == 8;
  114. /**
  115. * 检测浏览器是否运行在 兼容IE7模式
  116. * @name baidu.editor.browser.ie7Compat
  117. * @property 检测浏览器是否为兼容IE7模式
  118. * @grammar baidu.editor.browser.ie7Compat
  119. * @return {Boolean} 返回是否为兼容IE7模式
  120. */
  121. browser.ie7Compat = ( ( version == 7 && !document.documentMode )
  122. || document.documentMode == 7 );
  123. /**
  124. * 检测浏览器是否IE6模式或怪异模式
  125. * @name baidu.editor.browser.ie6Compat
  126. * @property 检测浏览器是否IE6 模式或怪异模式
  127. * @grammar baidu.editor.browser.ie6Compat
  128. * @return {Boolean} 返回是否为IE6 模式或怪异模式
  129. */
  130. browser.ie6Compat = ( version < 7 || browser.quirks );
  131. }
  132. // Gecko.
  133. if ( browser.gecko )
  134. {
  135. var geckoRelease = agent.match( /rv:([\d\.]+)/ );
  136. if ( geckoRelease )
  137. {
  138. geckoRelease = geckoRelease[1].split( '.' );
  139. version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1;
  140. }
  141. }
  142. /**
  143. * 检测浏览器是否为chrome
  144. * @name baidu.editor.browser.chrome
  145. * @property 检测浏览器是否为chrome
  146. * @grammar baidu.editor.browser.chrome
  147. * @return {Boolean} 返回是否为chrome浏览器
  148. */
  149. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  150. browser.chrome = + RegExp['\x241'];
  151. }
  152. /**
  153. * 检测浏览器是否为safari
  154. * @name baidu.editor.browser.safari
  155. * @property 检测浏览器是否为safari
  156. * @grammar baidu.editor.browser.safari
  157. * @return {Boolean} 返回是否为safari浏览器
  158. */
  159. if(/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)){
  160. browser.safari = + (RegExp['\x241'] || RegExp['\x242']);
  161. }
  162. // Opera 9.50+
  163. if ( browser.opera )
  164. version = parseFloat( opera.version() );
  165. // WebKit 522+ (Safari 3+)
  166. if ( browser.webkit )
  167. version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[1] );
  168. /**
  169. * 浏览器版本
  170. *
  171. * gecko内核浏览器的版本会转换成这样(如 1.9.0.2 -> 10900).
  172. *
  173. * webkit内核浏览器版本号使用其build号 (如 522).
  174. * @name baidu.editor.browser.version
  175. * @grammar baidu.editor.browser.version
  176. * @return {Boolean} 返回浏览器版本号
  177. * @example
  178. * if ( baidu.editor.browser.ie && <b>baidu.editor.browser.version</b> <= 6 )
  179. * alert( "Ouch!" );
  180. */
  181. browser.version = version;
  182. /**
  183. * 是否是兼容模式的浏览器
  184. * @name baidu.editor.browser.isCompatible
  185. * @grammar baidu.editor.browser.isCompatible
  186. * @return {Boolean} 返回是否是兼容模式的浏览器
  187. * @example
  188. * if ( baidu.editor.browser.isCompatible )
  189. * alert( "Your browser is pretty cool!" );
  190. */
  191. browser.isCompatible =
  192. !browser.mobile && (
  193. ( browser.ie && version >= 6 ) ||
  194. ( browser.gecko && version >= 10801 ) ||
  195. ( browser.opera && version >= 9.5 ) ||
  196. ( browser.air && version >= 1 ) ||
  197. ( browser.webkit && version >= 522 ) ||
  198. false );
  199. return browser;
  200. }();
  201. //快捷方式
  202. var ie = browser.ie,
  203. webkit = browser.webkit,
  204. gecko = browser.gecko,
  205. opera = browser.opera;
  206. ///import editor.js
  207. ///import core/utils.js
  208. /**
  209. * @class baidu.editor.utils 工具类
  210. */
  211. var utils = UE.utils =
  212. /**@lends baidu.editor.utils.prototype*/
  213. {
  214. /**
  215. * 以obj为原型创建实例
  216. * @public
  217. * @function
  218. * @param {Object} obj
  219. * @return {Object} 返回新的对象
  220. */
  221. makeInstance: function(obj) {
  222. var noop = new Function();
  223. noop.prototype = obj;
  224. obj = new noop;
  225. noop.prototype = null;
  226. return obj;
  227. },
  228. /**
  229. * 将s对象中的属性扩展到t对象上
  230. * @public
  231. * @function
  232. * @param {Object} t
  233. * @param {Object} s
  234. * @param {Boolean} b 是否保留已有属性
  235. * @returns {Object} t 返回扩展了s对象属性的t
  236. */
  237. extend: function(t, s, b) {
  238. if (s) {
  239. for (var k in s) {
  240. if (!b || !t.hasOwnProperty(k)) {
  241. t[k] = s[k];
  242. }
  243. }
  244. }
  245. return t;
  246. },
  247. /**
  248. * 判断是否为数组
  249. * @public
  250. * @function
  251. * @param {Object} array
  252. * @return {Boolean} true:为数组,false:不为数组
  253. */
  254. isArray: function(array) {
  255. return Object.prototype.toString.apply(array) === '[object Array]';
  256. },
  257. /**
  258. * 判断是否为字符串
  259. * @public
  260. * @function
  261. * @param {Object} str
  262. * @return {Boolean} true:为字符串。 false:不为字符串
  263. */
  264. isString: function(str) {
  265. return typeof str == 'string' || str.constructor == String;
  266. },
  267. /**
  268. * subClass继承superClass
  269. * @public
  270. * @function
  271. * @param {Object} subClass 子类
  272. * @param {Object} superClass 超类
  273. * @return {Object} 扩展后的新对象
  274. */
  275. inherits: function(subClass, superClass) {
  276. var oldP = subClass.prototype,
  277. newP = utils.makeInstance(superClass.prototype);
  278. utils.extend(newP, oldP, true);
  279. subClass.prototype = newP;
  280. return (newP.constructor = subClass);
  281. },
  282. /**
  283. * 为对象绑定函数
  284. * @public
  285. * @function
  286. * @param {Function} fn 函数
  287. * @param {Object} this_ 对象
  288. * @return {Function} 绑定后的函数
  289. */
  290. bind: function(fn, this_) {
  291. return function() {
  292. return fn.apply(this_, arguments);
  293. };
  294. },
  295. /**
  296. * 创建延迟执行的函数
  297. * @public
  298. * @function
  299. * @param {Function} fn 要执行的函数
  300. * @param {Number} delay 延迟时间,单位为毫秒
  301. * @param {Boolean} exclusion 是否互斥执行,true则执行下一次defer时会先把前一次的延迟函数删除
  302. * @return {Function} 延迟执行的函数
  303. */
  304. defer: function(fn, delay, exclusion) {
  305. var timerID;
  306. return function() {
  307. if (exclusion) {
  308. clearTimeout(timerID);
  309. }
  310. timerID = setTimeout(fn, delay);
  311. };
  312. },
  313. /**
  314. * 查找元素在数组中的索引, 若找不到返回-1
  315. * @public
  316. * @function
  317. * @param {Array} array 要查找的数组
  318. * @param {*} item 查找的元素
  319. * @param {Number} at 开始查找的位置
  320. * @returns {Number} 返回在数组中的索引
  321. */
  322. indexOf: function(array, item, at) {
  323. for(var i=at||0,l = array.length;i<l;i++){
  324. if(array[i] === item){
  325. return i;
  326. }
  327. }
  328. return -1;
  329. },
  330. findNode : function(nodes,tagNames,fn){
  331. for(var i=0,ci;ci=nodes[i++];){
  332. if(fn? fn(ci) : this.indexOf(tagNames,ci.tagName.toLowerCase())!=-1){
  333. return ci;
  334. }
  335. }
  336. },
  337. /**
  338. * 移除数组中的元素
  339. * @public
  340. * @function
  341. * @param {Array} array 要删除元素的数组
  342. * @param {*} item 要删除的元素
  343. */
  344. removeItem: function(array, item) {
  345. for(var i=0,l = array.length;i<l;i++){
  346. if(array[i] === item){
  347. array.splice(i,1);
  348. i--;
  349. }
  350. }
  351. },
  352. /**
  353. * 删除字符串首尾空格
  354. * @public
  355. * @function
  356. * @param {String} str 字符串
  357. * @return {String} str 删除空格后的字符串
  358. */
  359. trim: function(str) {
  360. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
  361. },
  362. /**
  363. * 将字符串转换成hashmap
  364. * @public
  365. * @function
  366. * @param {String/Array} list 字符串,以‘,’隔开
  367. * @returns {Object} 转成hashmap的对象
  368. */
  369. listToMap: function(list) {
  370. if(!list)return {};
  371. list = utils.isArray(list) ? list : list.split(',');
  372. for(var i=0,ci,obj={};ci=list[i++];){
  373. obj[ci.toUpperCase()] = obj[ci] = 1;
  374. }
  375. return obj;
  376. },
  377. /**
  378. * 将str中的html符号转义
  379. * @public
  380. * @function
  381. * @param {String} str 需要转义的字符串
  382. * @returns {String} 转义后的字符串
  383. */
  384. unhtml: function(str,reg) {
  385. return str ? str.replace(reg || /[&<">]/g, function(m){
  386. return {
  387. '<': '&lt;',
  388. '&': '&amp;',
  389. '"': '&quot;',
  390. '>': '&gt;'
  391. }[m]
  392. }) : '';
  393. },
  394. html: function(str) {
  395. return str ? str.replace(/&((g|l|quo)t|amp);/g, function(m){
  396. return {
  397. '&lt;':'<',
  398. '&amp;':'&',
  399. '&quot;':'"',
  400. '&gt;': '>'
  401. }[m]
  402. }) : '';
  403. },
  404. /**
  405. * 将css样式转换为驼峰的形式。如font-size -> fontSize
  406. * @public
  407. * @function
  408. * @param {String} cssName 需要转换的样式
  409. * @returns {String} 转换后的样式
  410. */
  411. cssStyleToDomStyle: function() {
  412. var test = document.createElement('div').style,
  413. cache = {
  414. 'float': test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat': 'float'
  415. };
  416. return function(cssName) {
  417. return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function(match){return match.charAt(1).toUpperCase();}));
  418. };
  419. }(),
  420. /**
  421. * 加载css文件,执行回调函数
  422. * @public
  423. * @function
  424. * @param {document} doc document对象
  425. * @param {String} path 文件路径
  426. * @param {Function} fun 回调函数
  427. * @param {String} id 元素id
  428. */
  429. loadFile : function(){
  430. var tmpList = {};
  431. return function(doc,obj,fun){
  432. var item = tmpList[obj.src||obj.href];
  433. if(item){
  434. if(utils.isArray(item.funs)){
  435. item.ready?fun():tmpList[obj.src||obj.href].funs.push(fun);
  436. }
  437. return;
  438. }
  439. tmpList[obj.src||obj.href] = fun? {'funs' : [fun]} :1;
  440. if(!doc.body){
  441. doc.write('<script src="'+obj.src+'"></script>');
  442. return;
  443. }
  444. if (obj.id && doc.getElementById(obj.id)) {
  445. return;
  446. }
  447. var element = doc.createElement(obj.tag);
  448. delete obj.tag;
  449. for(var p in obj){
  450. element.setAttribute(p,obj[p]);
  451. }
  452. element.onload = element.onreadystatechange = function() {
  453. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  454. item = tmpList[obj.src||obj.href];
  455. if(item.funs){
  456. item.ready = 1;
  457. for(var fi;fi=item.funs.pop();){
  458. fi();
  459. }
  460. }
  461. element.onload = element.onreadystatechange = null;
  462. }
  463. };
  464. doc.getElementsByTagName("head")[0].appendChild(element);
  465. }
  466. }(),
  467. /**
  468. * 判断对象是否为空
  469. * @param {Object} obj
  470. * @return {Boolean} true 空,false 不空
  471. */
  472. isEmptyObject : function(obj){
  473. for ( var p in obj ) {
  474. return false;
  475. }
  476. return true;
  477. },
  478. isFunction : function (source) {
  479. // chrome下,'function' == typeof /a/ 为true.
  480. return '[object Function]' == Object.prototype.toString.call(source);
  481. },
  482. fixColor : function (name, value) {
  483. if (/color/i.test(name) && /rgba?/.test(value)) {
  484. var array = value.split(",");
  485. if (array.length > 3)
  486. return "";
  487. value = "#";
  488. for (var i = 0, color; color = array[i++];) {
  489. color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
  490. value += color.length == 1 ? "0" + color : color;
  491. }
  492. value = value.toUpperCase();
  493. }
  494. return value;
  495. },
  496. /**
  497. * 只针对border,padding,margin做了处理,因为性能问题
  498. * @public
  499. * @function
  500. * @param {String} val style字符串
  501. */
  502. optCss : function(val){
  503. var padding,margin,border;
  504. val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi,function(str,key,name,val){
  505. if(val.split(' ').length == 1){
  506. switch (key){
  507. case 'padding':
  508. !padding && (padding = {});
  509. padding[name] = val;
  510. return '';
  511. case 'margin':
  512. !margin && (margin = {});
  513. margin[name] = val;
  514. return '';
  515. case 'border':
  516. return val == 'initial' ? '' : str;
  517. }
  518. }
  519. return str;
  520. });
  521. function opt(obj,name){
  522. if(!obj){
  523. return '';
  524. }
  525. var t = obj.top ,b = obj.bottom,l = obj.left,r = obj.right,val = '';
  526. if(!t || !l || !b || !r){
  527. for(var p in obj){
  528. val +=';'+name+'-' + p + ':' + obj[p]+';';
  529. }
  530. }else{
  531. val += ';'+name+':' +
  532. (t == b && b == l && l == r ? t :
  533. t == b && l == r ? (t + ' ' + l) :
  534. l == r ? (t + ' ' + l + ' ' + b) : (t + ' ' + r + ' ' + b + ' ' + l))+';'
  535. }
  536. return val;
  537. }
  538. val += opt(padding,'padding') + opt(margin,'margin');
  539. return val.replace(/^[ \n\r\t;]*|[ \n\r\t]*$/,'').replace(/;([ \n\r\t]+)|\1;/g,';')
  540. .replace(/(&((l|g)t|quot|#39))?;{2,}/g,function(a,b){
  541. return b ? b + ";;" : ';'
  542. });
  543. },
  544. /**
  545. * DOMContentLoaded 事件注册
  546. * @public
  547. * @function
  548. * @param {Function} 触发的事件
  549. */
  550. domReady : function (){
  551. var isReady = false,
  552. fnArr = [];
  553. function doReady(){
  554. //确保onready只执行一次
  555. isReady = true;
  556. for(var ci;ci=fnArr.pop();){
  557. ci();
  558. }
  559. }
  560. return function(onready){
  561. if ( document.readyState === "complete" ) {
  562. return onready && setTimeout( onready, 1 );
  563. }
  564. onready && fnArr.push(onready);
  565. isReady && doReady();
  566. if( browser.ie ){
  567. (function(){
  568. if ( isReady ) return;
  569. try {
  570. document.documentElement.doScroll("left");
  571. } catch( error ) {
  572. setTimeout( arguments.callee, 0 );
  573. return;
  574. }
  575. doReady();
  576. })();
  577. window.attachEvent('onload',doReady);
  578. }else{
  579. document.addEventListener( "DOMContentLoaded", function(){
  580. document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
  581. doReady();
  582. }, false );
  583. window.addEventListener('load',doReady,false);
  584. }
  585. }
  586. }()
  587. };
  588. utils.domReady();
  589. ///import editor.js
  590. ///import core/utils.js
  591. /**
  592. * 事件基础类
  593. * @public
  594. * @class
  595. * @name baidu.editor.EventBase
  596. */
  597. var EventBase = UE.EventBase = function(){};
  598. EventBase.prototype = /**@lends baidu.editor.EventBase.prototype*/{
  599. /**
  600. * 注册事件监听器
  601. * @public
  602. * @function
  603. * @param {String} types 事件名
  604. * @param {Function} listener 监听器数组
  605. */
  606. addListener : function ( types, listener ) {
  607. types = utils.trim(types).split(' ');
  608. for(var i= 0,ti;ti=types[i++];){
  609. getListener( this, ti, true ).push( listener );
  610. }
  611. },
  612. /**
  613. * 移除事件监听器
  614. * @public
  615. * @function
  616. * @param {String} types 事件名
  617. * @param {Function} listener 监听器数组
  618. */
  619. removeListener : function ( types, listener ) {
  620. types = utils.trim(types).split(' ');
  621. for(var i= 0,ti;ti=types[i++];){
  622. utils.removeItem( getListener( this, ti ) || [], listener );
  623. }
  624. },
  625. /**
  626. * 触发事件
  627. * @public
  628. * @function
  629. * @param {String} type 事件名
  630. *
  631. */
  632. fireEvent : function ( types ) {
  633. types = utils.trim(types).split(' ');
  634. for(var i= 0,ti;ti=types[i++];){
  635. var listeners = getListener( this, ti ),
  636. r, t, k;
  637. if ( listeners ) {
  638. k = listeners.length;
  639. while ( k -- ) {
  640. t = listeners[k].apply( this, arguments );
  641. if ( t !== undefined ) {
  642. r = t;
  643. }
  644. }
  645. }
  646. if ( t = this['on' + ti.toLowerCase()] ) {
  647. r = t.apply( this, arguments );
  648. }
  649. }
  650. return r;
  651. }
  652. };
  653. /**
  654. * 获得对象所拥有监听类型的所有监听器
  655. * @public
  656. * @function
  657. * @param {Object} obj 查询监听器的对象
  658. * @param {String} type 事件类型
  659. * @param {Boolean} force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  660. * @returns {Array} 监听器数组
  661. */
  662. function getListener( obj, type, force ) {
  663. var allListeners;
  664. type = type.toLowerCase();
  665. return ( ( allListeners = ( obj.__allListeners || force && ( obj.__allListeners = {} ) ) )
  666. && ( allListeners[type] || force && ( allListeners[type] = [] ) ) );
  667. }
  668. ///import editor.js
  669. ///import core/dom/dom.js
  670. /**
  671. * dtd html语义化的体现类
  672. * @constructor
  673. * @namespace dtd
  674. */
  675. var dtd = dom.dtd = (function() {
  676. function _( s ) {
  677. for (var k in s) {
  678. s[k.toUpperCase()] = s[k];
  679. }
  680. return s;
  681. }
  682. function X( t ) {
  683. var a = arguments;
  684. for ( var i=1; i<a.length; i++ ) {
  685. var x = a[i];
  686. for ( var k in x ) {
  687. if (!t.hasOwnProperty(k)) {
  688. t[k] = x[k];
  689. }
  690. }
  691. }
  692. return t;
  693. }
  694. var A = _({isindex:1,fieldset:1}),
  695. B = _({input:1,button:1,select:1,textarea:1,label:1}),
  696. C = X( _({a:1}), B ),
  697. D = X( {iframe:1}, C ),
  698. E = _({hr:1,ul:1,menu:1,div:1,blockquote:1,noscript:1,table:1,center:1,address:1,dir:1,pre:1,h5:1,dl:1,h4:1,noframes:1,h6:1,ol:1,h1:1,h3:1,h2:1}),
  699. F = _({ins:1,del:1,script:1,style:1}),
  700. G = X( _({b:1,acronym:1,bdo:1,'var':1,'#':1,abbr:1,code:1,br:1,i:1,cite:1,kbd:1,u:1,strike:1,s:1,tt:1,strong:1,q:1,samp:1,em:1,dfn:1,span:1}), F ),
  701. H = X( _({sub:1,img:1,embed:1,object:1,sup:1,basefont:1,map:1,applet:1,font:1,big:1,small:1}), G ),
  702. I = X( _({p:1}), H ),
  703. J = X( _({iframe:1}), H, B ),
  704. K = _({img:1,embed:1,noscript:1,br:1,kbd:1,center:1,button:1,basefont:1,h5:1,h4:1,samp:1,h6:1,ol:1,h1:1,h3:1,h2:1,form:1,font:1,'#':1,select:1,menu:1,ins:1,abbr:1,label:1,code:1,table:1,script:1,cite:1,input:1,iframe:1,strong:1,textarea:1,noframes:1,big:1,small:1,span:1,hr:1,sub:1,bdo:1,'var':1,div:1,object:1,sup:1,strike:1,dir:1,map:1,dl:1,applet:1,del:1,isindex:1,fieldset:1,ul:1,b:1,acronym:1,a:1,blockquote:1,i:1,u:1,s:1,tt:1,address:1,q:1,pre:1,p:1,em:1,dfn:1}),
  705. L = X( _({a:0}), J ),//a不能被切开,所以把他
  706. M = _({tr:1}),
  707. N = _({'#':1}),
  708. O = X( _({param:1}), K ),
  709. P = X( _({form:1}), A, D, E, I ),
  710. Q = _({li:1}),
  711. R = _({style:1,script:1}),
  712. S = _({base:1,link:1,meta:1,title:1}),
  713. T = X( S, R ),
  714. U = _({head:1,body:1}),
  715. V = _({html:1});
  716. var block = _({address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1}),
  717. //针对优酷的embed他添加了结束标识,导致粘贴进来会变成两个,暂时去掉 ,embed:1
  718. empty = _({area:1,base:1,br:1,col:1,hr:1,img:1,input:1,link:1,meta:1,param:1,embed:1});
  719. return _({
  720. // $ 表示自定的属性
  721. // body外的元素列表.
  722. $nonBodyContent: X( V, U, S ),
  723. //块结构元素列表
  724. $block : block,
  725. //内联元素列表
  726. $inline : L,
  727. $body : X( _({script:1,style:1}), block ),
  728. $cdata : _({script:1,style:1}),
  729. //自闭和元素
  730. $empty : empty,
  731. //不是自闭合,但不能让range选中里边
  732. $nonChild : _({iframe:1,textarea:1}),
  733. //列表元素列表
  734. $listItem : _({dd:1,dt:1,li:1}),
  735. //列表根元素列表
  736. $list: _({ul:1,ol:1,dl:1}),
  737. //不能认为是空的元素
  738. $isNotEmpty : _({table:1,ul:1,ol:1,dl:1,iframe:1,area:1,base:1,col:1,hr:1,img:1,embed:1,input:1,link:1,meta:1,param:1}),
  739. //如果没有子节点就可以删除的元素列表,像span,a
  740. $removeEmpty : _({a:1,abbr:1,acronym:1,address:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1}),
  741. $removeEmptyBlock : _({'p':1,'div':1}),
  742. //在table元素里的元素列表
  743. $tableContent : _({caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1,table:1}),
  744. //不转换的标签
  745. $notTransContent : _({pre:1,script:1,style:1,textarea:1}),
  746. html: U,
  747. head: T,
  748. style: N,
  749. script: N,
  750. body: P,
  751. base: {},
  752. link: {},
  753. meta: {},
  754. title: N,
  755. col : {},
  756. tr : _({td:1,th:1}),
  757. img : {},
  758. embed: {},
  759. colgroup : _({thead:1,col:1,tbody:1,tr:1,tfoot:1}),
  760. noscript : P,
  761. td : P,
  762. br : {},
  763. th : P,
  764. center : P,
  765. kbd : L,
  766. button : X( I, E ),
  767. basefont : {},
  768. h5 : L,
  769. h4 : L,
  770. samp : L,
  771. h6 : L,
  772. ol : Q,
  773. h1 : L,
  774. h3 : L,
  775. option : N,
  776. h2 : L,
  777. form : X( A, D, E, I ),
  778. select : _({optgroup:1,option:1}),
  779. font : L,
  780. ins : L,
  781. menu : Q,
  782. abbr : L,
  783. label : L,
  784. table : _({thead:1,col:1,tbody:1,tr:1,colgroup:1,caption:1,tfoot:1}),
  785. code : L,
  786. tfoot : M,
  787. cite : L,
  788. li : P,
  789. input : {},
  790. iframe : P,
  791. strong : L,
  792. textarea : N,
  793. noframes : P,
  794. big : L,
  795. small : L,
  796. span :_({'#':1,br:1}),
  797. hr : L,
  798. dt : L,
  799. sub : L,
  800. optgroup : _({option:1}),
  801. param : {},
  802. bdo : L,
  803. 'var' : L,
  804. div : P,
  805. object : O,
  806. sup : L,
  807. dd : P,
  808. strike : L,
  809. area : {},
  810. dir : Q,
  811. map : X( _({area:1,form:1,p:1}), A, F, E ),
  812. applet : O,
  813. dl : _({dt:1,dd:1}),
  814. del : L,
  815. isindex : {},
  816. fieldset : X( _({legend:1}), K ),
  817. thead : M,
  818. ul : Q,
  819. acronym : L,
  820. b : L,
  821. a : X( _({a:1}), J ),
  822. blockquote :X(_({td:1,tr:1,tbody:1,li:1}),P),
  823. caption : L,
  824. i : L,
  825. u : L,
  826. tbody : M,
  827. s : L,
  828. address : X( D, I ),
  829. tt : L,
  830. legend : L,
  831. q : L,
  832. pre : X( G, C ),
  833. p : X(_({'a':1}),L),
  834. em :L,
  835. dfn : L
  836. });
  837. })();
  838. ///import editor.js
  839. ///import core/utils.js
  840. ///import core/browser.js
  841. ///import core/dom/dom.js
  842. ///import core/dom/dtd.js
  843. /**
  844. * for getNextDomNode getPreviousDomNode
  845. */
  846. function getDomNode( node, start, ltr, startFromChild, fn, guard ) {
  847. var tmpNode = startFromChild && node[start],
  848. parent;
  849. !tmpNode && (tmpNode = node[ltr]);
  850. while ( !tmpNode && (parent = (parent || node).parentNode) ) {
  851. if ( parent.tagName == 'BODY' || guard && !guard( parent ) ) {
  852. return null;
  853. }
  854. tmpNode = parent[ltr];
  855. }
  856. if ( tmpNode && fn && !fn( tmpNode ) ) {
  857. return getDomNode( tmpNode, start, ltr, false, fn );
  858. }
  859. return tmpNode;
  860. }
  861. var attrFix = ie && browser.version < 9 ? {
  862. tabindex:"tabIndex",
  863. readonly:"readOnly",
  864. "for":"htmlFor",
  865. "class":"className",
  866. maxlength:"maxLength",
  867. cellspacing:"cellSpacing",
  868. cellpadding:"cellPadding",
  869. rowspan:"rowSpan",
  870. colspan:"colSpan",
  871. usemap:"useMap",
  872. frameborder:"frameBorder"
  873. } : {
  874. tabindex:"tabIndex",
  875. readonly:"readOnly"
  876. },
  877. styleBlock = utils.listToMap( [
  878. '-webkit-box', '-moz-box', 'block' ,
  879. 'list-item' , 'table' , 'table-row-group' ,
  880. 'table-header-group', 'table-footer-group' ,
  881. 'table-row' , 'table-column-group' , 'table-column' ,
  882. 'table-cell' , 'table-caption'
  883. ] );
  884. var domUtils = dom.domUtils = {
  885. //节点常量
  886. NODE_ELEMENT:1,
  887. NODE_DOCUMENT:9,
  888. NODE_TEXT:3,
  889. NODE_COMMENT:8,
  890. NODE_DOCUMENT_FRAGMENT:11,
  891. //位置关系
  892. POSITION_IDENTICAL:0,
  893. POSITION_DISCONNECTED:1,
  894. POSITION_FOLLOWING:2,
  895. POSITION_PRECEDING:4,
  896. POSITION_IS_CONTAINED:8,
  897. POSITION_CONTAINS:16,
  898. //ie6使用其他的会有一段空白出现
  899. fillChar:ie && browser.version == '6' ? '\ufeff' : '\u200B',
  900. //-------------------------Node部分--------------------------------
  901. keys:{
  902. /*Backspace*/ 8:1, /*Delete*/ 46:1,
  903. /*Shift*/ 16:1, /*Ctrl*/ 17:1, /*Alt*/ 18:1,
  904. 37:1, 38:1, 39:1, 40:1,
  905. 13:1 /*enter*/
  906. },
  907. /**
  908. * 获取两个节点的位置关系
  909. * @function
  910. * @param {Node} nodeA 节点A
  911. * @param {Node} nodeB 节点B
  912. * @returns {Number} 返回位置关系
  913. */
  914. getPosition:function ( nodeA, nodeB ) {
  915. // 如果两个节点是同一个节点
  916. if ( nodeA === nodeB ) {
  917. // domUtils.POSITION_IDENTICAL
  918. return 0;
  919. }
  920. var node,
  921. parentsA = [nodeA],
  922. parentsB = [nodeB];
  923. node = nodeA;
  924. while ( node = node.parentNode ) {
  925. // 如果nodeB是nodeA的祖先节点
  926. if ( node === nodeB ) {
  927. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  928. return 10;
  929. }
  930. parentsA.push( node );
  931. }
  932. node = nodeB;
  933. while ( node = node.parentNode ) {
  934. // 如果nodeA是nodeB的祖先节点
  935. if ( node === nodeA ) {
  936. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  937. return 20;
  938. }
  939. parentsB.push( node );
  940. }
  941. parentsA.reverse();
  942. parentsB.reverse();
  943. if ( parentsA[0] !== parentsB[0] ) {
  944. // domUtils.POSITION_DISCONNECTED
  945. return 1;
  946. }
  947. var i = -1;
  948. while ( i++, parentsA[i] === parentsB[i] ) {
  949. }
  950. nodeA = parentsA[i];
  951. nodeB = parentsB[i];
  952. while ( nodeA = nodeA.nextSibling ) {
  953. if ( nodeA === nodeB ) {
  954. // domUtils.POSITION_PRECEDING
  955. return 4
  956. }
  957. }
  958. // domUtils.POSITION_FOLLOWING
  959. return 2;
  960. },
  961. /**
  962. * 返回节点索引,zero-based
  963. * @function
  964. * @param {Node} node 节点
  965. * @returns {Number} 节点的索引
  966. */
  967. getNodeIndex : function (node,normalized) {
  968. var preNode = node,i=0;
  969. while(preNode = preNode.previousSibling){
  970. if(normalized && preNode.nodeType == 3){
  971. continue;
  972. }
  973. i++;
  974. }
  975. return i;
  976. },
  977. /**
  978. * 判断节点是否在树上
  979. * @param node
  980. */
  981. inDoc:function ( node, doc ) {
  982. while ( node = node.parentNode ) {
  983. if ( node === doc ) {
  984. return true;
  985. }
  986. }
  987. return false;
  988. },
  989. /**
  990. * 查找祖先节点
  991. * @function
  992. * @param {Node} node 节点
  993. * @param {Function} tester 以函数为规律
  994. * @param {Boolean} includeSelf 包含自己
  995. * @returns {Node} 返回祖先节点
  996. */
  997. findParent:function ( node, tester, includeSelf ) {
  998. if ( !domUtils.isBody( node ) ) {
  999. node = includeSelf ? node : node.parentNode;
  1000. while ( node ) {
  1001. if ( !tester || tester( node ) || this.isBody( node ) ) {
  1002. return tester && !tester( node ) && this.isBody( node ) ? null : node;
  1003. }
  1004. node = node.parentNode;
  1005. }
  1006. }
  1007. return null;
  1008. },
  1009. /**
  1010. * 查找祖先节点
  1011. * @function
  1012. * @param {Node} node 节点
  1013. * @param {String} tagName 标签名称
  1014. * @param {Boolean} includeSelf 包含自己
  1015. * @returns {Node} 返回祖先节点
  1016. */
  1017. findParentByTagName:function ( node, tagName, includeSelf, excludeFn ) {
  1018. if ( node && node.nodeType && !this.isBody( node ) && (node.nodeType == 1 || node.nodeType) ) {
  1019. tagName = utils.listToMap( utils.isArray( tagName ) ? tagName : [tagName] );
  1020. node = node.nodeType == 3 || !includeSelf ? node.parentNode : node;
  1021. while ( node && node.tagName && node.nodeType != 9 ) {
  1022. if ( excludeFn && excludeFn( node ) ) {
  1023. break;
  1024. }
  1025. if ( tagName[node.tagName] )
  1026. return node;
  1027. node = node.parentNode;
  1028. }
  1029. }
  1030. return null;
  1031. },
  1032. /**
  1033. * 查找祖先节点集合
  1034. * @param {Node} node 节点
  1035. * @param {Function} tester 函数
  1036. * @param {Boolean} includeSelf 是否从自身开始找
  1037. * @param {Boolean} closerFirst
  1038. * @returns {Array} 祖先节点集合
  1039. */
  1040. findParents:function ( node, includeSelf, tester, closerFirst ) {
  1041. var parents = includeSelf && ( tester && tester( node ) || !tester ) ? [node] : [];
  1042. while ( node = domUtils.findParent( node, tester ) ) {
  1043. parents.push( node );
  1044. }
  1045. return closerFirst ? parents : parents.reverse();
  1046. },
  1047. /**
  1048. * 往后插入节点
  1049. * @function
  1050. * @param {Node} node 基准节点
  1051. * @param {Node} nodeToInsert 要插入的节点
  1052. * @return {Node} 返回node
  1053. */
  1054. insertAfter:function ( node, nodeToInsert ) {
  1055. return node.parentNode.insertBefore( nodeToInsert, node.nextSibling );
  1056. },
  1057. /**
  1058. * 删除该节点
  1059. * @function
  1060. * @param {Node} node 要删除的节点
  1061. * @param {Boolean} keepChildren 是否保留子节点不删除
  1062. * @return {Node} 返回要删除的节点
  1063. */
  1064. remove:function ( node, keepChildren ) {
  1065. var parent = node.parentNode,
  1066. child;
  1067. if ( parent ) {
  1068. if ( keepChildren && node.hasChildNodes() ) {
  1069. while ( child = node.firstChild ) {
  1070. parent.insertBefore( child, node );
  1071. }
  1072. }
  1073. parent.removeChild( node );
  1074. }
  1075. return node;
  1076. },
  1077. /**
  1078. * 取得node节点在dom树上的下一个节点
  1079. * @function
  1080. * @param {Node} node 节点
  1081. * @param {Boolean} startFromChild 为true从子节点开始找
  1082. * @param {Function} fn fn为真的节点
  1083. * @return {Node} 返回下一个节点
  1084. */
  1085. getNextDomNode:function ( node, startFromChild, filter, guard ) {
  1086. return getDomNode( node, 'firstChild', 'nextSibling', startFromChild, filter, guard );
  1087. },
  1088. /**
  1089. * 是bookmark节点
  1090. * @param {Node} node 判断是否为书签节点
  1091. * @return {Boolean} 返回是否为书签节点
  1092. */
  1093. isBookmarkNode:function ( node ) {
  1094. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test( node.id );
  1095. },
  1096. /**
  1097. * 获取节点所在window对象
  1098. * @param {Node} node 节点
  1099. * @return {window} 返回window对象
  1100. */
  1101. getWindow:function ( node ) {
  1102. var doc = node.ownerDocument || node;
  1103. return doc.defaultView || doc.parentWindow;
  1104. },
  1105. /**
  1106. * 得到公共的祖先节点
  1107. * @param {Node} nodeA 节点A
  1108. * @param {Node} nodeB 节点B
  1109. * @return {Node} nodeA和nodeB的公共节点
  1110. */
  1111. getCommonAncestor:function ( nodeA, nodeB ) {
  1112. if ( nodeA === nodeB )
  1113. return nodeA;
  1114. var parentsA = [nodeA] , parentsB = [nodeB], parent = nodeA, i = -1;
  1115. while ( parent = parent.parentNode ) {
  1116. if ( parent === nodeB ) {
  1117. return parent;
  1118. }
  1119. parentsA.push( parent );
  1120. }
  1121. parent = nodeB;
  1122. while ( parent = parent.parentNode ) {
  1123. if ( parent === nodeA )
  1124. return parent;
  1125. parentsB.push( parent );
  1126. }
  1127. parentsA.reverse();
  1128. parentsB.reverse();
  1129. while ( i++, parentsA[i] === parentsB[i] ) {
  1130. }
  1131. return i == 0 ? null : parentsA[i - 1];
  1132. },
  1133. /**
  1134. * 清除该节点左右空的inline节点
  1135. * @function
  1136. * @param {Node} node
  1137. * @param {Boolean} ingoreNext 默认为false清除右边为空的inline节点。true为不清除右边为空的inline节点
  1138. * @param {Boolean} ingorePre 默认为false清除左边为空的inline节点。true为不清除左边为空的inline节点
  1139. * @exmaple <b></b><i></i>xxxx<b>bb</b> --> xxxx<b>bb</b>
  1140. */
  1141. clearEmptySibling:function ( node, ingoreNext, ingorePre ) {
  1142. function clear( next, dir ) {
  1143. var tmpNode;
  1144. while ( next && !domUtils.isBookmarkNode( next ) && (domUtils.isEmptyInlineElement( next )
  1145. //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
  1146. || !new RegExp( '[^\t\n\r' + domUtils.fillChar + ']' ).test( next.nodeValue ) ) ) {
  1147. tmpNode = next[dir];
  1148. domUtils.remove( next );
  1149. next = tmpNode;
  1150. }
  1151. }
  1152. !ingoreNext && clear( node.nextSibling, 'nextSibling' );
  1153. !ingorePre && clear( node.previousSibling, 'previousSibling' );
  1154. },
  1155. //---------------------------Text----------------------------------
  1156. /**
  1157. * 将一个文本节点拆分成两个文本节点
  1158. * @param {TextNode} node 文本节点
  1159. * @param {Integer} offset 拆分的位置
  1160. * @return {TextNode} 拆分后的后一个文本节
  1161. */
  1162. split:function ( node, offset ) {
  1163. var doc = node.ownerDocument;
  1164. if ( browser.ie && offset == node.nodeValue.length ) {
  1165. var next = doc.createTextNode( '' );
  1166. return domUtils.insertAfter( node, next );
  1167. }
  1168. var retval = node.splitText( offset );
  1169. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  1170. if ( browser.ie8 ) {
  1171. var tmpNode = doc.createTextNode( '' );
  1172. domUtils.insertAfter( retval, tmpNode );
  1173. domUtils.remove( tmpNode );
  1174. }
  1175. return retval;
  1176. },
  1177. /**
  1178. * 判断是否为空白节点
  1179. * @param {TextNode} node 节点
  1180. * @return {Boolean} 返回是否为文本节点
  1181. */
  1182. isWhitespace:function ( node ) {
  1183. return !new RegExp( '[^ \t\n\r' + domUtils.fillChar + ']' ).test( node.nodeValue );
  1184. },
  1185. //------------------------------Element-------------------------------------------
  1186. /**
  1187. * 获取元素相对于viewport的像素坐标
  1188. * @param {Element} element 元素
  1189. * @returns {Object} 返回坐标对象{x:left,y:top}
  1190. */
  1191. getXY:function ( element ) {
  1192. var x = 0, y = 0;
  1193. while ( element.offsetParent ) {
  1194. y += element.offsetTop;
  1195. x += element.offsetLeft;
  1196. element = element.offsetParent;
  1197. }
  1198. return {
  1199. 'x':x,
  1200. 'y':y
  1201. };
  1202. },
  1203. /**
  1204. * 绑原生DOM事件
  1205. * @param {Element|Window|Document} target 元素
  1206. * @param {Array|String} type 事件类型
  1207. * @param {Function} handler 执行函数
  1208. */
  1209. on:function ( obj, type, handler ) {
  1210. var types = utils.isArray(type) ? type : [type],
  1211. k = types.length;
  1212. if ( k ) while ( k-- ) {
  1213. type = types[k];
  1214. if ( obj.addEventListener ) {
  1215. obj.addEventListener( type, handler, false );
  1216. } else {
  1217. if ( !handler._d ) {
  1218. handler._d = {};
  1219. }
  1220. var key = type + handler.toString();
  1221. if ( !handler._d[key] ) {
  1222. handler._d[key] = function ( evt ) {
  1223. return handler.call( evt.srcElement, evt || window.event );
  1224. };
  1225. obj.attachEvent( 'on' + type, handler._d[key] );
  1226. }
  1227. }
  1228. }
  1229. obj = null;
  1230. },
  1231. /**
  1232. * 解除原生DOM事件绑定
  1233. * @param {Element|Window|Document} obj 元素
  1234. * @param {Array|String} type 事件类型
  1235. * @param {Function} handler 执行函数
  1236. */
  1237. un:function ( obj, type, handler ) {
  1238. var types = utils.isArray(type) ? type : [type],
  1239. k = types.length;
  1240. if ( k ) while ( k-- ) {
  1241. type = types[k];
  1242. if ( obj.removeEventListener ) {
  1243. obj.removeEventListener( type, handler, false );
  1244. } else {
  1245. var key = type + handler.toString();
  1246. obj.detachEvent( 'on' + type, handler._d ? handler._d[key] : handler );
  1247. if ( handler._d && handler._d[key] ) {
  1248. delete handler._d[key];
  1249. }
  1250. }
  1251. }
  1252. },
  1253. /**
  1254. * 比较两个节点是否tagName相同且有相同的属性和属性值
  1255. * @param {Element} nodeA 节点A
  1256. * @param {Element} nodeB 节点B
  1257. * @return {Boolean} 返回两个节点的标签,属性和属性值是否相同
  1258. * @example
  1259. * &lt;span style="font-size:12px"&gt;ssss&lt;/span&gt;和&lt;span style="font-size:12px"&gt;bbbbb&lt;/span&gt; 相等
  1260. * &lt;span style="font-size:13px"&gt;ssss&lt;/span&gt;和&lt;span style="font-size:12px"&gt;bbbbb&lt;/span&gt; 不相等
  1261. */
  1262. isSameElement:function ( nodeA, nodeB ) {
  1263. if ( nodeA.tagName != nodeB.tagName ) {
  1264. return 0;
  1265. }
  1266. var thisAttribs = nodeA.attributes,
  1267. otherAttribs = nodeB.attributes;
  1268. if ( !ie && thisAttribs.length != otherAttribs.length ) {
  1269. return 0;
  1270. }
  1271. var attrA, attrB, al = 0, bl = 0;
  1272. for ( var i = 0; attrA = thisAttribs[i++]; ) {
  1273. if ( attrA.nodeName == 'style' ) {
  1274. if ( attrA.specified ) {
  1275. al++;
  1276. }
  1277. if ( domUtils.isSameStyle( nodeA, nodeB ) ) {
  1278. continue;
  1279. } else {
  1280. return 0;
  1281. }
  1282. }
  1283. if ( ie ) {
  1284. if ( attrA.specified ) {
  1285. al++;
  1286. attrB = otherAttribs.getNamedItem( attrA.nodeName );
  1287. } else {
  1288. continue;
  1289. }
  1290. } else {
  1291. attrB = nodeB.attributes[attrA.nodeName];
  1292. }
  1293. if ( !attrB.specified || attrA.nodeValue != attrB.nodeValue ) {
  1294. return 0;
  1295. }
  1296. }
  1297. // 有可能attrB的属性包含了attrA的属性之外还有自己的属性
  1298. if ( ie ) {
  1299. for ( i = 0; attrB = otherAttribs[i++]; ) {
  1300. if ( attrB.specified ) {
  1301. bl++;
  1302. }
  1303. }
  1304. if ( al != bl ) {
  1305. return 0;
  1306. }
  1307. }
  1308. return 1;
  1309. },
  1310. /**
  1311. * 判断两个元素的style属性是不是一致
  1312. * @param {Element} elementA 元素A
  1313. * @param {Element} elementB 元素B
  1314. * @return {boolean} 返回判断结果,true为一致
  1315. */
  1316. isSameStyle:function ( elementA, elementB ) {
  1317. var styleA = elementA.style.cssText.replace( /( ?; ?)/g, ';' ).replace( /( ?: ?)/g, ':' ),
  1318. styleB = elementB.style.cssText.replace( /( ?; ?)/g, ';' ).replace( /( ?: ?)/g, ':' );
  1319. if ( browser.opera ) {
  1320. styleA = elementA.style;
  1321. styleB = elementB.style;
  1322. if ( styleA.length != styleB.length )
  1323. return 0;
  1324. for ( var p in styleA ) {
  1325. if ( /^(\d+|csstext)$/i.test( p ) ) {
  1326. continue;
  1327. }
  1328. if ( styleA[p] != styleB[p] ) {
  1329. return 0;
  1330. }
  1331. }
  1332. return 1;
  1333. }
  1334. if ( !styleA || !styleB ) {
  1335. return styleA == styleB ? 1 : 0;
  1336. }
  1337. styleA = styleA.split( ';' );
  1338. styleB = styleB.split( ';' );
  1339. if ( styleA.length != styleB.length ) {
  1340. return 0;
  1341. }
  1342. for ( var i = 0, ci; ci = styleA[i++]; ) {
  1343. if ( utils.indexOf( styleB, ci ) == -1 ) {
  1344. return 0;
  1345. }
  1346. }
  1347. return 1;
  1348. },
  1349. /**
  1350. * 检查是否为块元素
  1351. * @function
  1352. * @param {Element} node 元素
  1353. * @param {String} customNodeNames 自定义的块元素的tagName
  1354. * @return {Boolean} 是否为块元素
  1355. */
  1356. isBlockElm:function ( node ) {
  1357. return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle( node, 'display' )]) && !dtd.$nonChild[node.tagName];
  1358. },
  1359. /**
  1360. * 判断是否body
  1361. * @param {Node} 节点
  1362. * @return {Boolean} 是否是body节点
  1363. */
  1364. isBody:function ( node ) {
  1365. return node && node.nodeType == 1 && node.tagName.toLowerCase() == 'body';
  1366. },
  1367. /**
  1368. * 以node节点为中心,将该节点的父节点拆分成2块
  1369. * @param {Element} node 节点
  1370. * @param {Element} parent 要被拆分的父节点
  1371. * @example <div>xxxx<b>xxx</b>xxx</div> ==> <div>xxx</div><b>xx</b><div>xxx</div>
  1372. */
  1373. breakParent:function ( node, parent ) {
  1374. var tmpNode, parentClone = node, clone = node, leftNodes, rightNodes;
  1375. do {
  1376. parentClone = parentClone.parentNode;
  1377. if ( leftNodes ) {
  1378. tmpNode = parentClone.cloneNode( false );
  1379. tmpNode.appendChild( leftNodes );
  1380. leftNodes = tmpNode;
  1381. tmpNode = parentClone.cloneNode( false );
  1382. tmpNode.appendChild( rightNodes );
  1383. rightNodes = tmpNode;
  1384. } else {
  1385. leftNodes = parentClone.cloneNode( false );
  1386. rightNodes = leftNodes.cloneNode( false );
  1387. }
  1388. while ( tmpNode = clone.previousSibling ) {
  1389. leftNodes.insertBefore( tmpNode, leftNodes.firstChild );
  1390. }
  1391. while ( tmpNode = clone.nextSibling ) {
  1392. rightNodes.appendChild( tmpNode );
  1393. }
  1394. clone = parentClone;
  1395. } while ( parent !== parentClone );
  1396. tmpNode = parent.parentNode;
  1397. tmpNode.insertBefore( leftNodes, parent );
  1398. tmpNode.insertBefore( rightNodes, parent );
  1399. tmpNode.insertBefore( node, rightNodes );
  1400. domUtils.remove( parent );
  1401. return node;
  1402. },
  1403. /**
  1404. * 检查是否是空inline节点
  1405. * @param {Node} node 节点
  1406. * @return {Boolean} 返回1为是,0为否
  1407. * @example
  1408. * &lt;b&gt;&lt;i&gt;&lt;/i&gt;&lt;/b&gt; //true
  1409. * <b><i></i><u></u></b> true
  1410. * &lt;b&gt;&lt;/b&gt; true &lt;b&gt;xx&lt;i&gt;&lt;/i&gt;&lt;/b&gt; //false
  1411. */
  1412. isEmptyInlineElement:function ( node ) {
  1413. if ( node.nodeType != 1 || !dtd.$removeEmpty[ node.tagName ] ) {
  1414. return 0;
  1415. }
  1416. node = node.firstChild;
  1417. while ( node ) {
  1418. //如果是创建的bookmark就跳过
  1419. if ( domUtils.isBookmarkNode( node ) ) {
  1420. return 0;
  1421. }
  1422. if ( node.nodeType == 1 && !domUtils.isEmptyInlineElement( node ) ||
  1423. node.nodeType == 3 && !domUtils.isWhitespace( node )
  1424. ) {
  1425. return 0;
  1426. }
  1427. node = node.nextSibling;
  1428. }
  1429. return 1;
  1430. },
  1431. /**
  1432. * 删除空白子节点
  1433. * @param {Element} node 需要删除空白子节点的元素
  1434. */
  1435. trimWhiteTextNode:function ( node ) {
  1436. function remove( dir ) {
  1437. var child;
  1438. while ( (child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace( child ) ) {
  1439. node.removeChild( child )
  1440. }
  1441. }
  1442. remove( 'firstChild' );
  1443. remove( 'lastChild' );
  1444. },
  1445. /**
  1446. * 合并子节点
  1447. * @param {Node} node 节点
  1448. * @param {String} tagName 标签
  1449. * @param {String} attrs 属性
  1450. * @example &lt;span style="font-size:12px;"&gt;xx&lt;span style="font-size:12px;"&gt;aa&lt;/span&gt;xx&lt;/span 使用后
  1451. * &lt;span style="font-size:12px;"&gt;xxaaxx&lt;/span
  1452. */
  1453. mergChild:function ( node, tagName, attrs ) {
  1454. var list = domUtils.getElementsByTagName( node, node.tagName.toLowerCase() );
  1455. for ( var i = 0, ci; ci = list[i++]; ) {
  1456. if ( !ci.parentNode || domUtils.isBookmarkNode( ci ) ) {
  1457. continue;
  1458. }
  1459. //span单独处理
  1460. if ( ci.tagName.toLowerCase() == 'span' ) {
  1461. if ( node === ci.parentNode ) {
  1462. domUtils.trimWhiteTextNode( node );
  1463. if ( node.childNodes.length == 1 ) {
  1464. node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
  1465. domUtils.remove( ci, true );
  1466. continue;
  1467. }
  1468. }
  1469. ci.style.cssText = node.style.cssText + ';' + ci.style.cssText;
  1470. if ( attrs ) {
  1471. var style = attrs.style;
  1472. if ( style ) {
  1473. style = style.split( ';' );
  1474. for ( var j = 0, s; s = style[j++]; ) {
  1475. ci.style[utils.cssStyleToDomStyle( s.split( ':' )[0] )] = s.split( ':' )[1];
  1476. }
  1477. }
  1478. }
  1479. if ( domUtils.isSameStyle( ci, node ) ) {
  1480. domUtils.remove( ci, true );
  1481. }
  1482. continue;
  1483. }
  1484. if ( domUtils.isSameElement( node, ci ) ) {
  1485. domUtils.remove( ci, true );
  1486. }
  1487. }
  1488. if ( tagName == 'span' ) {
  1489. var as = domUtils.getElementsByTagName( node, 'a' );
  1490. for ( var i = 0, ai; ai = as[i++]; ) {
  1491. ai.style.cssText = ';' + node.style.cssText;
  1492. ai.style.textDecoration = 'underline';
  1493. }
  1494. }
  1495. },
  1496. /**
  1497. * 封装原生的getElemensByTagName
  1498. * @param {Node} node 根节点
  1499. * @param {String} name 标签的tagName
  1500. * @return {Array} 返回符合条件的元素数组
  1501. */
  1502. getElementsByTagName:function ( node, name ) {
  1503. var list = node.getElementsByTagName( name ), arr = [];
  1504. for ( var i = 0, ci; ci = list[i++]; ) {
  1505. arr.push( ci )
  1506. }
  1507. return arr;
  1508. },
  1509. /**
  1510. * 将子节点合并到父节点上
  1511. * @param {Element} node 节点
  1512. * @example &lt;span style="color:#ff"&gt;&lt;span style="font-size:12px"&gt;xxx&lt;/span&gt;&lt;/span&gt; ==&gt; &lt;span style="color:#ff;font-size:12px"&gt;xxx&lt;/span&gt;
  1513. */
  1514. mergToParent:function ( node ) {
  1515. var parent = node.parentNode;
  1516. while ( parent && dtd.$removeEmpty[parent.tagName] ) {
  1517. if ( parent.tagName == node.tagName || parent.tagName == 'A' ) {//针对a标签单独处理
  1518. domUtils.trimWhiteTextNode( parent );
  1519. //span需要特殊处理 不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
  1520. if ( parent.tagName == 'SPAN' && !domUtils.isSameStyle( parent, node )
  1521. || (parent.tagName == 'A' && node.tagName == 'SPAN') ) {
  1522. if ( parent.childNodes.length > 1 || parent !== node.parentNode ) {
  1523. node.style.cssText = parent.style.cssText + ";" + node.style.cssText;
  1524. parent = parent.parentNode;
  1525. continue;
  1526. } else {
  1527. parent.style.cssText += ";" + node.style.cssText;
  1528. //trace:952 a标签要保持下划线
  1529. if ( parent.tagName == 'A' ) {
  1530. parent.style.textDecoration = 'underline';
  1531. }
  1532. }
  1533. }
  1534. if ( parent.tagName != 'A' ) {
  1535. parent === node.parentNode && domUtils.remove( node, true );
  1536. break;
  1537. }
  1538. }
  1539. parent = parent.parentNode;
  1540. }
  1541. },
  1542. /**
  1543. * 合并左右兄弟节点
  1544. * @function
  1545. * @param {Node} node
  1546. * @param {Boolean} ingoreNext 默认为false合并上一个兄弟节点。true为不合并上一个兄弟节点
  1547. * @param {Boolean} ingorePre 默认为false合并下一个兄弟节点。true为不合并下一个兄弟节点
  1548. * @example &lt;b&gt;xxxx&lt;/b&gt;&lt;b&gt;xxx&lt;/b&gt;&lt;b&gt;xxxx&lt;/b&gt; ==> &lt;b&gt;xxxxxxxxxxx&lt;/b&gt;
  1549. */
  1550. mergSibling:function ( node, ingorePre, ingoreNext ) {
  1551. function merg( rtl, start, node ) {
  1552. var next;
  1553. if ( (next = node[rtl]) && !domUtils.isBookmarkNode( next ) && next.nodeType == 1 && domUtils.isSameElement( node, next ) ) {
  1554. while ( next.firstChild ) {
  1555. if ( start == 'firstChild' ) {
  1556. node.insertBefore( next.lastChild, node.firstChild );
  1557. } else {
  1558. node.appendChild( next.firstChild );
  1559. }
  1560. }
  1561. domUtils.remove( next );
  1562. }
  1563. }
  1564. !ingorePre && merg( 'previousSibling', 'firstChild', node );
  1565. !ingoreNext && merg( 'nextSibling', 'lastChild', node );
  1566. },
  1567. /**
  1568. * 使得元素及其子节点不能被选择
  1569. * @function
  1570. * @param {Node} node 节点
  1571. */
  1572. unselectable:ie || browser.opera ? function ( node ) {
  1573. //for ie9
  1574. node.onselectstart = function () {
  1575. return false;
  1576. };
  1577. node.onclick = node.onkeyup = node.onkeydown = function () {
  1578. return false;
  1579. };
  1580. node.unselectable = 'on';
  1581. node.setAttribute( "unselectable", "on" );
  1582. for ( var i = 0, ci; ci = node.all[i++]; ) {
  1583. switch ( ci.tagName.toLowerCase() ) {
  1584. case 'iframe' :
  1585. case 'textarea' :
  1586. case 'input' :
  1587. case 'select' :
  1588. break;
  1589. default :
  1590. ci.unselectable = 'on';
  1591. node.setAttribute( "unselectable", "on" );
  1592. }
  1593. }
  1594. } : function ( node ) {
  1595. node.style.MozUserSelect =
  1596. node.style.webkitUserSelect =
  1597. node.style.KhtmlUserSelect = 'none';
  1598. },
  1599. /**
  1600. * 删除元素上的属性,可以删除多个
  1601. * @function
  1602. * @param {Element} element 元素
  1603. * @param {Array} attrNames 要删除的属性数组
  1604. */
  1605. removeAttributes:function ( elm, attrNames ) {
  1606. for ( var i = 0, ci; ci = attrNames[i++]; ) {
  1607. ci = attrFix[ci] || ci;
  1608. switch ( ci ) {
  1609. case 'className':
  1610. elm[ci] = '';
  1611. break;
  1612. case 'style':
  1613. elm.style.cssText = '';
  1614. !browser.ie && elm.removeAttributeNode( elm.getAttributeNode( 'style' ) )
  1615. }
  1616. elm.removeAttribute( ci );
  1617. }
  1618. },
  1619. creElm:function ( doc, tag, attrs ) {
  1620. return this.setAttributes( doc.createElement( tag ), attrs )
  1621. },
  1622. /**
  1623. * 给节点添加属性
  1624. * @function
  1625. * @param {Node} node 节点
  1626. * @param {Object} attrNames 要添加的属性名称,采用json对象存放
  1627. */
  1628. setAttributes:function ( node, attrs ) {
  1629. for ( var name in attrs ) {
  1630. var value = attrs[name];
  1631. switch ( name ) {
  1632. case 'class':
  1633. //ie下要这样赋值,setAttribute不起作用
  1634. node.className = value;
  1635. break;
  1636. case 'style' :
  1637. node.style.cssText = node.style.cssText + ";" + value;
  1638. break;
  1639. case 'innerHTML':
  1640. node[name] = value;
  1641. break;
  1642. case 'value':
  1643. node.value = value;
  1644. break;
  1645. default:
  1646. node.setAttribute( attrFix[name] || name, value );
  1647. }
  1648. }
  1649. return node;
  1650. },
  1651. /**
  1652. * 获取元素的样式
  1653. * @function
  1654. * @param {Element} element 元素
  1655. * @param {String} styleName 样式名称
  1656. * @return {String} 样式值
  1657. */
  1658. getComputedStyle:function ( element, styleName ) {
  1659. function fixUnit( key, val ) {
  1660. if ( key == 'font-size' && /pt$/.test( val ) ) {
  1661. val = Math.round( parseFloat( val ) / 0.75 ) + 'px';
  1662. }
  1663. return val;
  1664. }
  1665. if ( element.nodeType == 3 ) {
  1666. element = element.parentNode;
  1667. }
  1668. //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改.
  1669. if ( browser.ie && browser.version < 9 && styleName == 'font-size' && !element.style.fontSize &&
  1670. !dtd.$empty[element.tagName] && !dtd.$nonChild[element.tagName] ) {
  1671. var span = element.ownerDocument.createElement( 'span' );
  1672. span.style.cssText = 'padding:0;border:0;font-family:simsun;';
  1673. span.innerHTML = '.';
  1674. element.appendChild( span );
  1675. var result = span.offsetHeight;
  1676. element.removeChild( span );
  1677. span = null;
  1678. return result + 'px';
  1679. }
  1680. try {
  1681. var value = domUtils.getStyle( element, styleName ) ||
  1682. (window.getComputedStyle ? domUtils.getWindow( element ).getComputedStyle( element, '' ).getPropertyValue( styleName ) :
  1683. ( element.currentStyle || element.style )[utils.cssStyleToDomStyle( styleName )]);
  1684. } catch ( e ) {
  1685. return null;
  1686. }
  1687. return fixUnit( styleName, utils.fixColor( styleName, value ) );
  1688. },
  1689. /**
  1690. * 删除cssClass,可以支持删除多个class
  1691. * @param {Element} element 元素
  1692. * @param {Array} classNames 删除的className
  1693. */
  1694. removeClasses:function ( element, classNames ) {
  1695. classNames = utils.isArray( classNames ) ? classNames : [classNames];
  1696. element.className = (' ' + element.className + ' ').replace(
  1697. new RegExp( '(?:\\s+(?:' + classNames.join( '|' ) + '))+\\s+', 'g' ), ' ' );
  1698. },
  1699. /**
  1700. * 增加一个class
  1701. * @param element
  1702. * @param className
  1703. */
  1704. addClass:function ( element, className ) {
  1705. if ( !this.hasClass( element, className ) ) {
  1706. element.className += " " + className;
  1707. }
  1708. },
  1709. /**
  1710. * 删除元素的样式
  1711. * @param {Element} element元素
  1712. * @param {String} name 删除的样式名称
  1713. */
  1714. removeStyle:function ( node, name ) {
  1715. node.style[utils.cssStyleToDomStyle( name )] = '';
  1716. if ( !node.style.cssText ) {
  1717. domUtils.removeAttributes( node, ['style'] );
  1718. }
  1719. },
  1720. /**
  1721. * 判断元素属性中是否包含某一个classname
  1722. * @param {Element} element 元素
  1723. * @param {String} className 样式名
  1724. * @returns {Boolean} 是否包含该classname
  1725. */
  1726. hasClass:function ( element, className ) {
  1727. return ( ' ' + element.className + ' ' ).indexOf( ' ' + className + ' ' ) > -1;
  1728. },
  1729. /**
  1730. * 阻止事件默认行为
  1731. * @param {Event} evt 需要组织的事件对象
  1732. */
  1733. preventDefault:function ( evt ) {
  1734. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  1735. },
  1736. /**
  1737. * 获得元素样式
  1738. * @param {Element} element 元素
  1739. * @param {String} name 样式名称
  1740. * @return {String} 返回元素样式值
  1741. */
  1742. getStyle:function ( element, name ) {
  1743. var value = element.style[ utils.cssStyleToDomStyle( name ) ];
  1744. return utils.fixColor( name, value );
  1745. },
  1746. setStyle:function ( element, name, value ) {
  1747. element.style[utils.cssStyleToDomStyle( name )] = value;
  1748. },
  1749. setStyles:function ( element, styles ) {
  1750. for ( var name in styles ) {
  1751. if ( styles.hasOwnProperty( name ) ) {
  1752. domUtils.setStyle( element, name, styles[name] );
  1753. }
  1754. }
  1755. },
  1756. /**
  1757. * 删除_moz_dirty属性
  1758. * @function
  1759. * @param {Node} node 节点
  1760. */
  1761. removeDirtyAttr:function ( node ) {
  1762. for ( var i = 0, ci, nodes = node.getElementsByTagName( '*' ); ci = nodes[i++]; ) {
  1763. ci.removeAttribute( '_moz_dirty' );
  1764. }
  1765. node.removeAttribute( '_moz_dirty' );
  1766. },
  1767. /**
  1768. * 返回子节点的数量
  1769. * @function
  1770. * @param {Node} node 父节点
  1771. * @param {Function} fn 过滤子节点的规则,若为空,则得到所有子节点的数量
  1772. * @return {Number} 符合条件子节点的数量
  1773. */
  1774. getChildCount:function ( node, fn ) {
  1775. var count = 0, first = node.firstChild;
  1776. fn = fn || function () {
  1777. return 1;
  1778. };
  1779. while ( first ) {
  1780. if ( fn( first ) ) {
  1781. count++;
  1782. }
  1783. first = first.nextSibling;
  1784. }
  1785. return count;
  1786. },
  1787. /**
  1788. * 判断是否为空节点
  1789. * @function
  1790. * @param {Node} node 节点
  1791. * @return {Boolean} 是否为空节点
  1792. */
  1793. isEmptyNode:function ( node ) {
  1794. return !node.firstChild || domUtils.getChildCount( node, function ( node ) {
  1795. return !domUtils.isBr( node ) && !domUtils.isBookmarkNode( node ) && !domUtils.isWhitespace( node )
  1796. } ) == 0
  1797. },
  1798. /**
  1799. * 清空节点所有的className
  1800. * @function
  1801. * @param {Array} nodes 节点数组
  1802. */
  1803. clearSelectedArr:function ( nodes ) {
  1804. var node;
  1805. while ( node = nodes.pop() ) {
  1806. domUtils.removeAttributes( node, ['class'] );
  1807. }
  1808. },
  1809. /**
  1810. * 将显示区域滚动到显示节点的位置
  1811. * @function
  1812. * @param {Node} node 节点
  1813. * @param {window} win window对象
  1814. * @param {Number} offsetTop 距离上方的偏移量
  1815. */
  1816. scrollToView:function ( node, win, offsetTop ) {
  1817. var getViewPaneSize = function () {
  1818. var doc = win.document,
  1819. mode = doc.compatMode == 'CSS1Compat';
  1820. return {
  1821. width:( mode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
  1822. height:( mode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
  1823. };
  1824. },
  1825. getScrollPosition = function ( win ) {
  1826. if ( 'pageXOffset' in win ) {
  1827. return {
  1828. x:win.pageXOffset || 0,
  1829. y:win.pageYOffset || 0
  1830. };
  1831. }
  1832. else {
  1833. var doc = win.document;
  1834. return {
  1835. x:doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
  1836. y:doc.documentElement.scrollTop || doc.body.scrollTop || 0
  1837. };
  1838. }
  1839. };
  1840. var winHeight = getViewPaneSize().height, offset = winHeight * -1 + offsetTop;
  1841. offset += (node.offsetHeight || 0);
  1842. var elementPosition = domUtils.getXY( node );
  1843. offset += elementPosition.y;
  1844. var currentScroll = getScrollPosition( win ).y;
  1845. // offset += 50;
  1846. if ( offset > currentScroll || offset < currentScroll - winHeight ) {
  1847. win.scrollTo( 0, offset + (offset < 0 ? -20 : 20) );
  1848. }
  1849. },
  1850. /**
  1851. * 判断节点是否为br
  1852. * @function
  1853. * @param {Node} node 节点
  1854. */
  1855. isBr:function ( node ) {
  1856. return node.nodeType == 1 && node.tagName == 'BR';
  1857. },
  1858. isFillChar:function ( node ) {
  1859. return node.nodeType == 3 && !node.nodeValue.replace( new RegExp( domUtils.fillChar ), '' ).length
  1860. },
  1861. isStartInblock:function ( range ) {
  1862. var tmpRange = range.cloneRange(),
  1863. flag = 0,
  1864. start = tmpRange.startContainer,
  1865. tmp;
  1866. while ( start && domUtils.isFillChar( start ) ) {
  1867. tmp = start;
  1868. start = start.previousSibling
  1869. }
  1870. if ( tmp ) {
  1871. tmpRange.setStartBefore( tmp );
  1872. start = tmpRange.startContainer;
  1873. }
  1874. if ( start.nodeType == 1 && domUtils.isEmptyNode( start ) && tmpRange.startOffset == 1 ) {
  1875. tmpRange.setStart( start, 0 ).collapse( true );
  1876. }
  1877. while ( !tmpRange.startOffset ) {
  1878. start = tmpRange.startContainer;
  1879. if ( domUtils.isBlockElm( start ) || domUtils.isBody( start ) ) {
  1880. flag = 1;
  1881. break;
  1882. }
  1883. var pre = tmpRange.startContainer.previousSibling,
  1884. tmpNode;
  1885. if ( !pre ) {
  1886. tmpRange.setStartBefore( tmpRange.startContainer );
  1887. } else {
  1888. while ( pre && domUtils.isFillChar( pre ) ) {
  1889. tmpNode = pre;
  1890. pre = pre.previousSibling;
  1891. }
  1892. if ( tmpNode ) {
  1893. tmpRange.setStartBefore( tmpNode );
  1894. } else {
  1895. tmpRange.setStartBefore( tmpRange.startContainer );
  1896. }
  1897. }
  1898. }
  1899. return flag && !domUtils.isBody( tmpRange.startContainer ) ? 1 : 0;
  1900. },
  1901. isEmptyBlock:function ( node ) {
  1902. var reg = new RegExp( '[ \t\r\n' + domUtils.fillChar + ']', 'g' );
  1903. if ( node[browser.ie ? 'innerText' : 'textContent'].replace( reg, '' ).length > 0 ) {
  1904. return 0;
  1905. }
  1906. for ( var n in dtd.$isNotEmpty ) {
  1907. if ( node.getElementsByTagName( n ).length ) {
  1908. return 0;
  1909. }
  1910. }
  1911. return 1;
  1912. },
  1913. setViewportOffset:function ( element, offset ) {
  1914. var left = parseInt( element.style.left ) | 0;
  1915. var top = parseInt( element.style.top ) | 0;
  1916. var rect = element.getBoundingClientRect();
  1917. var offsetLeft = offset.left - rect.left;
  1918. var offsetTop = offset.top - rect.top;
  1919. if ( offsetLeft ) {
  1920. element.style.left = left + offsetLeft + 'px';
  1921. }
  1922. if ( offsetTop ) {
  1923. element.style.top = top + offsetTop + 'px';
  1924. }
  1925. },
  1926. fillNode:function ( doc, node ) {
  1927. var tmpNode = browser.ie ? doc.createTextNode( domUtils.fillChar ) : doc.createElement( 'br' );
  1928. node.innerHTML = '';
  1929. node.appendChild( tmpNode );
  1930. },
  1931. moveChild:function ( src, tag, dir ) {
  1932. while ( src.firstChild ) {
  1933. if ( dir && tag.firstChild ) {
  1934. tag.insertBefore( src.lastChild, tag.firstChild );
  1935. } else {
  1936. tag.appendChild( src.firstChild );
  1937. }
  1938. }
  1939. },
  1940. //判断是否有额外属性
  1941. hasNoAttributes:function ( node ) {
  1942. return browser.ie ? /^<\w+\s*?>/.test( node.outerHTML ) : node.attributes.length == 0;
  1943. },
  1944. //判断是否是编辑器自定义的参数
  1945. isCustomeNode:function ( node ) {
  1946. return node.nodeType == 1 && node.getAttribute( '_ue_custom_node_' );
  1947. },
  1948. isTagNode:function ( node, tagName ) {
  1949. return node.nodeType == 1 && node.tagName.toLowerCase() == tagName;
  1950. }
  1951. };
  1952. var fillCharReg = new RegExp( domUtils.fillChar, 'g' );
  1953. ///import editor.js
  1954. ///import core/utils.js
  1955. ///import core/browser.js
  1956. ///import core/dom/dom.js
  1957. ///import core/dom/dtd.js
  1958. ///import core/dom/domUtils.js
  1959. /**
  1960. * @class baidu.editor.dom.Range Range类
  1961. */
  1962. /**
  1963. * @description Range类实现
  1964. * @author zhanyi
  1965. */
  1966. (function () {
  1967. var guid = 0,
  1968. fillChar = domUtils.fillChar,
  1969. fillData;
  1970. /**
  1971. * 更新range的collapse状态
  1972. * @param {Range} range range对象
  1973. */
  1974. function updateCollapse( range ) {
  1975. range.collapsed =
  1976. range.startContainer && range.endContainer &&
  1977. range.startContainer === range.endContainer &&
  1978. range.startOffset == range.endOffset;
  1979. }
  1980. function setEndPoint( toStart, node, offset, range ) {
  1981. //如果node是自闭合标签要处理
  1982. if ( node.nodeType == 1 && (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName]) ) {
  1983. offset = domUtils.getNodeIndex( node ) + (toStart ? 0 : 1);
  1984. node = node.parentNode;
  1985. }
  1986. if ( toStart ) {
  1987. range.startContainer = node;
  1988. range.startOffset = offset;
  1989. if ( !range.endContainer ) {
  1990. range.collapse( true );
  1991. }
  1992. } else {
  1993. range.endContainer = node;
  1994. range.endOffset = offset;
  1995. if ( !range.startContainer ) {
  1996. range.collapse( false );
  1997. }
  1998. }
  1999. updateCollapse( range );
  2000. return range;
  2001. }
  2002. function execContentsAction( range, action ) {
  2003. //调整边界
  2004. //range.includeBookmark();
  2005. var start = range.startContainer,
  2006. end = range.endContainer,
  2007. startOffset = range.startOffset,
  2008. endOffset = range.endOffset,
  2009. doc = range.document,
  2010. frag = doc.createDocumentFragment(),
  2011. tmpStart, tmpEnd;
  2012. if ( start.nodeType == 1 ) {
  2013. start = start.childNodes[startOffset] || (tmpStart = start.appendChild( doc.createTextNode( '' ) ));
  2014. }
  2015. if ( end.nodeType == 1 ) {
  2016. end = end.childNodes[endOffset] || (tmpEnd = end.appendChild( doc.createTextNode( '' ) ));
  2017. }
  2018. if ( start === end && start.nodeType == 3 ) {
  2019. frag.appendChild( doc.createTextNode( start.substringData( startOffset, endOffset - startOffset ) ) );
  2020. //is not clone
  2021. if ( action ) {
  2022. start.deleteData( startOffset, endOffset - startOffset );
  2023. range.collapse( true );
  2024. }
  2025. return frag;
  2026. }
  2027. var current, currentLevel, clone = frag,
  2028. startParents = domUtils.findParents( start, true ), endParents = domUtils.findParents( end, true );
  2029. for ( var i = 0; startParents[i] == endParents[i]; ) {
  2030. i++;
  2031. }
  2032. for ( var j = i, si; si = startParents[j]; j++ ) {
  2033. current = si.nextSibling;
  2034. if ( si == start ) {
  2035. if ( !tmpStart ) {
  2036. if ( range.startContainer.nodeType == 3 ) {
  2037. clone.appendChild( doc.createTextNode( start.nodeValue.slice( startOffset ) ) );
  2038. //is not clone
  2039. if ( action ) {
  2040. start.deleteData( startOffset, start.nodeValue.length - startOffset );
  2041. }
  2042. } else {
  2043. clone.appendChild( !action ? start.cloneNode( true ) : start );
  2044. }
  2045. }
  2046. } else {
  2047. currentLevel = si.cloneNode( false );
  2048. clone.appendChild( currentLevel );
  2049. }
  2050. while ( current ) {
  2051. if ( current === end || current === endParents[j] ) {
  2052. break;
  2053. }
  2054. si = current.nextSibling;
  2055. clone.appendChild( !action ? current.cloneNode( true ) : current );
  2056. current = si;
  2057. }
  2058. clone = currentLevel;
  2059. }
  2060. clone = frag;
  2061. if ( !startParents[i] ) {
  2062. clone.appendChild( startParents[i - 1].cloneNode( false ) );
  2063. clone = clone.firstChild;
  2064. }
  2065. for ( var j = i, ei; ei = endParents[j]; j++ ) {
  2066. current = ei.previousSibling;
  2067. if ( ei == end ) {
  2068. if ( !tmpEnd && range.endContainer.nodeType == 3 ) {
  2069. clone.appendChild( doc.createTextNode( end.substringData( 0, endOffset ) ) );
  2070. //is not clone
  2071. if ( action ) {
  2072. end.deleteData( 0, endOffset );
  2073. }
  2074. }
  2075. } else {
  2076. currentLevel = ei.cloneNode( false );
  2077. clone.appendChild( currentLevel );
  2078. }
  2079. //如果两端同级,右边第一次已经被开始做了
  2080. if ( j != i || !startParents[i] ) {
  2081. while ( current ) {
  2082. if ( current === start ) {
  2083. break;
  2084. }
  2085. ei = current.previousSibling;
  2086. clone.insertBefore( !action ? current.cloneNode( true ) : current, clone.firstChild );
  2087. current = ei;
  2088. }
  2089. }
  2090. clone = currentLevel;
  2091. }
  2092. if ( action ) {
  2093. range.setStartBefore( !endParents[i] ? endParents[i - 1] : !startParents[i] ? startParents[i - 1] : endParents[i] ).collapse( true );
  2094. }
  2095. tmpStart && domUtils.remove( tmpStart );
  2096. tmpEnd && domUtils.remove( tmpEnd );
  2097. return frag;
  2098. }
  2099. /**
  2100. * Range类
  2101. * @param {Document} document 编辑器页面document对象
  2102. */
  2103. var Range = dom.Range = function ( document ) {
  2104. var me = this;
  2105. me.startContainer =
  2106. me.startOffset =
  2107. me.endContainer =
  2108. me.endOffset = null;
  2109. me.document = document;
  2110. me.collapsed = true;
  2111. };
  2112. /**
  2113. * 删除fillData
  2114. * @param doc
  2115. * @param excludeNode
  2116. */
  2117. function removeFillData( doc, excludeNode ) {
  2118. try {
  2119. if ( fillData && domUtils.inDoc( fillData, doc ) ) {
  2120. if ( !fillData.nodeValue.replace( fillCharReg, '' ).length ) {
  2121. var tmpNode = fillData.parentNode;
  2122. domUtils.remove( fillData );
  2123. while ( tmpNode && domUtils.isEmptyInlineElement( tmpNode ) && !tmpNode.contains( excludeNode ) ) {
  2124. fillData = tmpNode.parentNode;
  2125. domUtils.remove( tmpNode );
  2126. tmpNode = fillData;
  2127. }
  2128. } else {
  2129. fillData.nodeValue = fillData.nodeValue.replace( fillCharReg, '' );
  2130. }
  2131. }
  2132. } catch ( e ) {
  2133. }
  2134. }
  2135. /**
  2136. *
  2137. * @param node
  2138. * @param dir
  2139. */
  2140. function mergSibling( node, dir ) {
  2141. var tmpNode;
  2142. node = node[dir];
  2143. while ( node && domUtils.isFillChar( node ) ) {
  2144. tmpNode = node[dir];
  2145. domUtils.remove( node );
  2146. node = tmpNode;
  2147. }
  2148. }
  2149. Range.prototype = {
  2150. /**
  2151. * 克隆选中的内容到一个fragment里
  2152. * @public
  2153. * @function
  2154. * @name baidu.editor.dom.Range.cloneContents
  2155. * @return {Fragment} frag|null 返回选中内容的文本片段或者空
  2156. */
  2157. cloneContents:function () {
  2158. return this.collapsed ? null : execContentsAction( this, 0 );
  2159. },
  2160. /**
  2161. * 删除所选内容
  2162. * @public
  2163. * @function
  2164. * @name baidu.editor.dom.Range.deleteContents
  2165. * @return {Range} 删除选中内容后的Range
  2166. */
  2167. deleteContents:function () {
  2168. var txt;
  2169. if ( !this.collapsed ) {
  2170. execContentsAction( this, 1 );
  2171. }
  2172. if ( browser.webkit ) {
  2173. txt = this.startContainer;
  2174. if ( txt.nodeType == 3 && !txt.nodeValue.length ) {
  2175. this.setStartBefore( txt ).collapse( true );
  2176. domUtils.remove( txt );
  2177. }
  2178. }
  2179. return this;
  2180. },
  2181. /**
  2182. * 取出内容
  2183. * @public
  2184. * @function
  2185. * @name baidu.editor.dom.Range.extractContents
  2186. * @return {String} 获得Range选中的内容
  2187. */
  2188. extractContents:function () {
  2189. return this.collapsed ? null : execContentsAction( this, 2 );
  2190. },
  2191. /**
  2192. * 设置range的开始位置
  2193. * @public
  2194. * @function
  2195. * @name baidu.editor.dom.Range.setStart
  2196. * @param {Node} node range开始节点
  2197. * @param {Number} offset 偏移量
  2198. * @return {Range} 返回Range
  2199. */
  2200. setStart:function ( node, offset ) {
  2201. return setEndPoint( true, node, offset, this );
  2202. },
  2203. /**
  2204. * 设置range结束点的位置
  2205. * @public
  2206. * @function
  2207. * @name baidu.editor.dom.Range.setEnd
  2208. * @param {Node} node range结束节点
  2209. * @param {Number} offset 偏移量
  2210. * @return {Range} 返回Range
  2211. */
  2212. setEnd:function ( node, offset ) {
  2213. return setEndPoint( false, node, offset, this );
  2214. },
  2215. /**
  2216. * 将开始位置设置到node后
  2217. * @public
  2218. * @function
  2219. * @name baidu.editor.dom.Range.setStartAfter
  2220. * @param {Node} node 节点
  2221. * @return {Range} 返回Range
  2222. */
  2223. setStartAfter:function ( node ) {
  2224. return this.setStart( node.parentNode, domUtils.getNodeIndex( node ) + 1 );
  2225. },
  2226. /**
  2227. * 将开始位置设置到node前
  2228. * @public
  2229. * @function
  2230. * @name baidu.editor.dom.Range.setStartBefore
  2231. * @param {Node} node 节点
  2232. * @return {Range} 返回Range
  2233. */
  2234. setStartBefore:function ( node ) {
  2235. return this.setStart( node.parentNode, domUtils.getNodeIndex( node ) );
  2236. },
  2237. /**
  2238. * 将结束点位置设置到node后
  2239. * @public
  2240. * @function
  2241. * @name baidu.editor.dom.Range.setEndAfter
  2242. * @param {Node} node 节点
  2243. * @return {Range} 返回Range
  2244. */
  2245. setEndAfter:function ( node ) {
  2246. return this.setEnd( node.parentNode, domUtils.getNodeIndex( node ) + 1 );
  2247. },
  2248. /**
  2249. * 将开始设置到node的最开始位置 <element>^text</element>
  2250. * @public
  2251. * @function
  2252. * @name baidu.editor.dom.Range.setEndAfter
  2253. * @param {Node} node 节点
  2254. * @return {Range} 返回Range
  2255. */
  2256. setStartAtFirst:function ( node ) {
  2257. return this.setStart( node, 0 );
  2258. },
  2259. /**
  2260. * 将开始设置到node的最开始位置 <element>text^</element>
  2261. * @public
  2262. * @function
  2263. * @name baidu.editor.dom.Range.setEndAfter
  2264. * @param {Node} node 节点
  2265. * @return {Range} 返回Range
  2266. */
  2267. setStartAtLast:function ( node ) {
  2268. return this.setStart( node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length );
  2269. },
  2270. /**
  2271. * 将结束设置到node的最开始位置 <element>^text</element>
  2272. * @public
  2273. * @function
  2274. * @name baidu.editor.dom.Range.setEndAfter
  2275. * @param {Node} node 节点
  2276. * @return {Range} 返回Range
  2277. */
  2278. setEndAtFirst:function ( node ) {
  2279. return this.setEnd( node, 0 );
  2280. },
  2281. /**
  2282. * 将结束设置到node的最开始位置 <element>text^</element>
  2283. * @public
  2284. * @function
  2285. * @name baidu.editor.dom.Range.setEndAfter
  2286. * @param {Node} node 节点
  2287. * @return {Range} 返回Range
  2288. */
  2289. setEndAtLast:function ( node ) {
  2290. return this.setEnd( node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length );
  2291. },
  2292. /**
  2293. * 将结束点位置设置到node前
  2294. * @public
  2295. * @function
  2296. * @name baidu.editor.dom.Range.setEndBefore
  2297. * @param {Node} node 节点
  2298. * @return {Range} 返回Range
  2299. */
  2300. setEndBefore:function ( node ) {
  2301. return this.setEnd( node.parentNode, domUtils.getNodeIndex( node ) );
  2302. },
  2303. /**
  2304. * 选中指定节点
  2305. * @public
  2306. * @function
  2307. * @name baidu.editor.dom.Range.selectNode
  2308. * @param {Node} node 节点
  2309. * @return {Range} 返回Range
  2310. */
  2311. selectNode:function ( node ) {
  2312. return this.setStartBefore( node ).setEndAfter( node );
  2313. },
  2314. /**
  2315. * 选中node下的所有节点
  2316. * @public
  2317. * @function
  2318. * @name baidu.editor.dom.Range.selectNodeContents
  2319. * @param {Element} node 要设置的节点
  2320. * @return {Range} 返回Range
  2321. */
  2322. selectNodeContents:function ( node ) {
  2323. return this.setStart( node, 0 ).setEnd( node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length );
  2324. },
  2325. /**
  2326. * 克隆range
  2327. * @public
  2328. * @function
  2329. * @name baidu.editor.dom.Range.cloneRange
  2330. * @return {Range} 克隆的range对象
  2331. */
  2332. cloneRange:function () {
  2333. var me = this, range = new Range( me.document );
  2334. return range.setStart( me.startContainer, me.startOffset ).setEnd( me.endContainer, me.endOffset );
  2335. },
  2336. /**
  2337. * 让选区闭合
  2338. * @public
  2339. * @function
  2340. * @name baidu.editor.dom.Range.collapse
  2341. * @param {Boolean} toStart 是否在选区开始位置闭合选区,true在开始位置闭合,false反之
  2342. * @return {Range} range对象
  2343. */
  2344. collapse:function ( toStart ) {
  2345. var me = this;
  2346. if ( toStart ) {
  2347. me.endContainer = me.startContainer;
  2348. me.endOffset = me.startOffset;
  2349. }
  2350. else {
  2351. me.startContainer = me.endContainer;
  2352. me.startOffset = me.endOffset;
  2353. }
  2354. me.collapsed = true;
  2355. return me;
  2356. },
  2357. /**
  2358. * 调整range的边界,“缩”到合适的位置
  2359. * @public
  2360. * @function
  2361. * @name baidu.editor.dom.Range.shrinkBoundary
  2362. * @param {Boolean} ignoreEnd 是否考虑前面的元素
  2363. */
  2364. shrinkBoundary:function ( ignoreEnd ) {
  2365. var me = this, child,
  2366. collapsed = me.collapsed;
  2367. while ( me.startContainer.nodeType == 1 //是element
  2368. && (child = me.startContainer.childNodes[me.startOffset]) //子节点也是element
  2369. && child.nodeType == 1 && !domUtils.isBookmarkNode( child )
  2370. && !dtd.$empty[child.tagName] && !dtd.$nonChild[child.tagName] ) {
  2371. me.setStart( child, 0 );
  2372. }
  2373. if ( collapsed ) {
  2374. return me.collapse( true );
  2375. }
  2376. if ( !ignoreEnd ) {
  2377. while ( me.endContainer.nodeType == 1//是element
  2378. && me.endOffset > 0 //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
  2379. && (child = me.endContainer.childNodes[me.endOffset - 1]) //子节点也是element
  2380. && child.nodeType == 1 && !domUtils.isBookmarkNode( child )
  2381. && !dtd.$empty[child.tagName] && !dtd.$nonChild[child.tagName] ) {
  2382. me.setEnd( child, child.childNodes.length );
  2383. }
  2384. }
  2385. return me;
  2386. },
  2387. /**
  2388. * 找到startContainer和endContainer的公共祖先节点
  2389. * @public
  2390. * @function
  2391. * @name baidu.editor.dom.Range.getCommonAncestor
  2392. * @param {Boolean} includeSelf 是否包含自身
  2393. * @param {Boolean} ignoreTextNode 是否忽略文本节点
  2394. * @return {Node} 祖先节点
  2395. */
  2396. getCommonAncestor:function ( includeSelf, ignoreTextNode ) {
  2397. var start = this.startContainer,
  2398. end = this.endContainer;
  2399. if ( start === end ) {
  2400. if ( includeSelf && start.nodeType == 1 && this.startOffset == this.endOffset - 1 ) {
  2401. return start.childNodes[this.startOffset];
  2402. }
  2403. //只有在上来就相等的情况下才会出现是文本的情况
  2404. return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start;
  2405. }
  2406. return domUtils.getCommonAncestor( start, end );
  2407. },
  2408. /**
  2409. * 切割文本节点,将边界扩大到element
  2410. * @public
  2411. * @function
  2412. * @name baidu.editor.dom.Range.trimBoundary
  2413. * @param {Boolean} ignoreEnd 为真就不处理结束边界
  2414. * @return {Range} range对象
  2415. * @example <b>|xxx</b>
  2416. * startContainer = xxx; startOffset = 0
  2417. * 执行后
  2418. * startContainer = <b>; startOffset = 0
  2419. * @example <b>xx|x</b>
  2420. * startContainer = xxx; startOffset = 2
  2421. * 执行后
  2422. * startContainer = <b>; startOffset = 1 因为将xxx切割成2个节点了
  2423. */
  2424. trimBoundary:function ( ignoreEnd ) {
  2425. this.txtToElmBoundary();
  2426. var start = this.startContainer,
  2427. offset = this.startOffset,
  2428. collapsed = this.collapsed,
  2429. end = this.endContainer;
  2430. if ( start.nodeType == 3 ) {
  2431. if ( offset == 0 ) {
  2432. this.setStartBefore( start );
  2433. } else {
  2434. if ( offset >= start.nodeValue.length ) {
  2435. this.setStartAfter( start );
  2436. } else {
  2437. var textNode = domUtils.split( start, offset );
  2438. //跟新结束边界
  2439. if ( start === end ) {
  2440. this.setEnd( textNode, this.endOffset - offset );
  2441. } else if ( start.parentNode === end ) {
  2442. this.endOffset += 1;
  2443. }
  2444. this.setStartBefore( textNode );
  2445. }
  2446. }
  2447. if ( collapsed ) {
  2448. return this.collapse( true );
  2449. }
  2450. }
  2451. if ( !ignoreEnd ) {
  2452. offset = this.endOffset;
  2453. end = this.endContainer;
  2454. if ( end.nodeType == 3 ) {
  2455. if ( offset == 0 ) {
  2456. this.setEndBefore( end );
  2457. } else {
  2458. if ( offset >= end.nodeValue.length ) {
  2459. this.setEndAfter( end );
  2460. } else {
  2461. domUtils.split( end, offset );
  2462. this.setEndAfter( end );
  2463. }
  2464. }
  2465. }
  2466. }
  2467. return this;
  2468. },
  2469. /**
  2470. * 如果选区在文本的边界上,就扩展选区到文本的父节点上
  2471. * @public
  2472. * @function
  2473. * @name baidu.editor.dom.Range.txtToElmBoundary
  2474. * @return {Range} range对象
  2475. * @example <b> |xxx</b>
  2476. * startContainer = xxx; startOffset = 0
  2477. * 执行后
  2478. * startContainer = <b>; startOffset = 0
  2479. * @example <b> xxx| </b>
  2480. * startContainer = xxx; startOffset = 3
  2481. * 执行后
  2482. * startContainer = <b>; startOffset = 1
  2483. */
  2484. txtToElmBoundary:function () {
  2485. function adjust( r, c ) {
  2486. var container = r[c + 'Container'],
  2487. offset = r[c + 'Offset'];
  2488. if ( container.nodeType == 3 ) {
  2489. if ( !offset ) {
  2490. r['set' + c.replace( /(\w)/, function ( a ) {
  2491. return a.toUpperCase();
  2492. } ) + 'Before']( container );
  2493. } else if ( offset >= container.nodeValue.length ) {
  2494. r['set' + c.replace( /(\w)/, function ( a ) {
  2495. return a.toUpperCase();
  2496. } ) + 'After' ]( container );
  2497. }
  2498. }
  2499. }
  2500. if ( !this.collapsed ) {
  2501. adjust( this, 'start' );
  2502. adjust( this, 'end' );
  2503. }
  2504. return this;
  2505. },
  2506. /**
  2507. * 在当前选区的开始位置前插入一个节点或者fragment
  2508. * @public
  2509. * @function
  2510. * @name baidu.editor.dom.Range.insertNode
  2511. * @param {Node/DocumentFragment} node 要插入的节点或fragment
  2512. * @return {Range} 返回range对象
  2513. */
  2514. insertNode:function ( node ) {
  2515. var first = node, length = 1;
  2516. if ( node.nodeType == 11 ) {
  2517. first = node.firstChild;
  2518. length = node.childNodes.length;
  2519. }
  2520. this.trimBoundary( true );
  2521. var start = this.startContainer,
  2522. offset = this.startOffset;
  2523. var nextNode = start.childNodes[ offset ];
  2524. if ( nextNode ) {
  2525. start.insertBefore( node, nextNode );
  2526. } else {
  2527. start.appendChild( node );
  2528. }
  2529. if ( first.parentNode === this.endContainer ) {
  2530. this.endOffset = this.endOffset + length;
  2531. }
  2532. return this.setStartBefore( first );
  2533. },
  2534. /**
  2535. * 设置光标位置
  2536. * @public
  2537. * @function
  2538. * @name baidu.editor.dom.Range.setCursor
  2539. * @param {Boolean} toEnd true为闭合到选区的结束位置后,false为闭合到选区的开始位置前
  2540. * @return {Range} 返回range对象
  2541. */
  2542. setCursor:function ( toEnd, notFillData ) {
  2543. return this.collapse( !toEnd ).select( notFillData );
  2544. },
  2545. /**
  2546. * 创建书签
  2547. * @public
  2548. * @function
  2549. * @name baidu.editor.dom.Range.createBookmark
  2550. * @param {Boolean} serialize true:为true则返回对象中用id来分别表示书签的开始和结束节点
  2551. * @param {Boolean} same true:是否采用唯一的id,false将会为每一个标签产生一个唯一的id
  2552. * @returns {Object} bookmark对象
  2553. */
  2554. createBookmark:function ( serialize, same ) {
  2555. var endNode,
  2556. startNode = this.document.createElement( 'span' );
  2557. startNode.style.cssText = 'display:none;line-height:0px;';
  2558. startNode.appendChild( this.document.createTextNode( '\uFEFF' ) );
  2559. startNode.id = '_baidu_bookmark_start_' + (same ? '' : guid++);
  2560. if ( !this.collapsed ) {
  2561. endNode = startNode.cloneNode( true );
  2562. endNode.id = '_baidu_bookmark_end_' + (same ? '' : guid++);
  2563. }
  2564. this.insertNode( startNode );
  2565. if ( endNode ) {
  2566. this.collapse( false ).insertNode( endNode );
  2567. this.setEndBefore( endNode );
  2568. }
  2569. this.setStartAfter( startNode );
  2570. return {
  2571. start:serialize ? startNode.id : startNode,
  2572. end:endNode ? serialize ? endNode.id : endNode : null,
  2573. id:serialize
  2574. }
  2575. },
  2576. /**
  2577. * 移动边界到书签,并删除书签
  2578. * @public
  2579. * @function
  2580. * @name baidu.editor.dom.Range.moveToBookmark
  2581. * @params {Object} bookmark对象
  2582. * @returns {Range} Range对象
  2583. */
  2584. moveToBookmark:function ( bookmark ) {
  2585. var start = bookmark.id ? this.document.getElementById( bookmark.start ) : bookmark.start,
  2586. end = bookmark.end && bookmark.id ? this.document.getElementById( bookmark.end ) : bookmark.end;
  2587. this.setStartBefore( start );
  2588. domUtils.remove( start );
  2589. if ( end ) {
  2590. this.setEndBefore( end );
  2591. domUtils.remove( end );
  2592. } else {
  2593. this.collapse( true );
  2594. }
  2595. return this;
  2596. },
  2597. /**
  2598. * 调整边界到一个block元素上,或者移动到最大的位置
  2599. * @public
  2600. * @function
  2601. * @name baidu.editor.dom.Range.enlarge
  2602. * @params {Boolean} toBlock 扩展到block元素
  2603. * @params {Function} stopFn 停止函数,若返回true,则不再扩展
  2604. * @return {Range} Range对象
  2605. */
  2606. enlarge:function ( toBlock, stopFn ) {
  2607. var isBody = domUtils.isBody,
  2608. pre, node, tmp = this.document.createTextNode( '' );
  2609. if ( toBlock ) {
  2610. node = this.startContainer;
  2611. if ( node.nodeType == 1 ) {
  2612. if ( node.childNodes[this.startOffset] ) {
  2613. pre = node = node.childNodes[this.startOffset]
  2614. } else {
  2615. node.appendChild( tmp );
  2616. pre = node = tmp;
  2617. }
  2618. } else {
  2619. pre = node;
  2620. }
  2621. while ( 1 ) {
  2622. if ( domUtils.isBlockElm( node ) ) {
  2623. node = pre;
  2624. while ( (pre = node.previousSibling) && !domUtils.isBlockElm( pre ) ) {
  2625. node = pre;
  2626. }
  2627. this.setStartBefore( node );
  2628. break;
  2629. }
  2630. pre = node;
  2631. node = node.parentNode;
  2632. }
  2633. node = this.endContainer;
  2634. if ( node.nodeType == 1 ) {
  2635. if ( pre = node.childNodes[this.endOffset] ) {
  2636. node.insertBefore( tmp, pre );
  2637. } else {
  2638. node.appendChild( tmp );
  2639. }
  2640. pre = node = tmp;
  2641. } else {
  2642. pre = node;
  2643. }
  2644. while ( 1 ) {
  2645. if ( domUtils.isBlockElm( node ) ) {
  2646. node = pre;
  2647. while ( (pre = node.nextSibling) && !domUtils.isBlockElm( pre ) ) {
  2648. node = pre;
  2649. }
  2650. this.setEndAfter( node );
  2651. break;
  2652. }
  2653. pre = node;
  2654. node = node.parentNode;
  2655. }
  2656. if ( tmp.parentNode === this.endContainer ) {
  2657. this.endOffset--;
  2658. }
  2659. domUtils.remove( tmp );
  2660. }
  2661. // 扩展边界到最大
  2662. if ( !this.collapsed ) {
  2663. while ( this.startOffset == 0 ) {
  2664. if ( stopFn && stopFn( this.startContainer ) ) {
  2665. break;
  2666. }
  2667. if ( isBody( this.startContainer ) ) {
  2668. break;
  2669. }
  2670. this.setStartBefore( this.startContainer );
  2671. }
  2672. while ( this.endOffset == (this.endContainer.nodeType == 1 ? this.endContainer.childNodes.length : this.endContainer.nodeValue.length) ) {
  2673. if ( stopFn && stopFn( this.endContainer ) ) {
  2674. break;
  2675. }
  2676. if ( isBody( this.endContainer ) ) {
  2677. break;
  2678. }
  2679. this.setEndAfter( this.endContainer );
  2680. }
  2681. }
  2682. return this;
  2683. },
  2684. /**
  2685. * 调整边界
  2686. * @public
  2687. * @function
  2688. * @name baidu.editor.dom.Range.adjustmentBoundary
  2689. * @return {Range} Range对象
  2690. * @example
  2691. * <b>xx[</b>xxxxx] ==> <b>xx</b>[xxxxx]
  2692. * <b>[xx</b><i>]xxx</i> ==> <b>[xx</b>]<i>xxx</i>
  2693. *
  2694. */
  2695. adjustmentBoundary:function () {
  2696. if ( !this.collapsed ) {
  2697. while ( !domUtils.isBody( this.startContainer ) &&
  2698. this.startOffset == this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  2699. ) {
  2700. this.setStartAfter( this.startContainer );
  2701. }
  2702. while ( !domUtils.isBody( this.endContainer ) && !this.endOffset ) {
  2703. this.setEndBefore( this.endContainer );
  2704. }
  2705. }
  2706. return this;
  2707. },
  2708. /**
  2709. * 给选区中的内容加上inline样式
  2710. * @public
  2711. * @function
  2712. * @name baidu.editor.dom.Range.applyInlineStyle
  2713. * @param {String} tagName 标签名称
  2714. * @param {Object} attrObj 属性
  2715. * @return {Range} Range对象
  2716. */
  2717. applyInlineStyle:function ( tagName, attrs, list ) {
  2718. if ( this.collapsed )return this;
  2719. this.trimBoundary().enlarge( false,
  2720. function ( node ) {
  2721. return node.nodeType == 1 && domUtils.isBlockElm( node )
  2722. } ).adjustmentBoundary();
  2723. var bookmark = this.createBookmark(),
  2724. end = bookmark.end,
  2725. filterFn = function ( node ) {
  2726. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace( node );
  2727. },
  2728. current = domUtils.getNextDomNode( bookmark.start, false, filterFn ),
  2729. node,
  2730. pre,
  2731. range = this.cloneRange();
  2732. while ( current && (domUtils.getPosition( current, end ) & domUtils.POSITION_PRECEDING) ) {
  2733. if ( current.nodeType == 3 || dtd[tagName][current.tagName] ) {
  2734. range.setStartBefore( current );
  2735. node = current;
  2736. while ( node && (node.nodeType == 3 || dtd[tagName][node.tagName]) && node !== end ) {
  2737. pre = node;
  2738. node = domUtils.getNextDomNode( node, node.nodeType == 1, null, function ( parent ) {
  2739. return dtd[tagName][parent.tagName];
  2740. } );
  2741. }
  2742. var frag = range.setEndAfter( pre ).extractContents(), elm;
  2743. if ( list && list.length > 0 ) {
  2744. var level, top;
  2745. top = level = list[0].cloneNode( false );
  2746. for ( var i = 1, ci; ci = list[i++]; ) {
  2747. level.appendChild( ci.cloneNode( false ) );
  2748. level = level.firstChild;
  2749. }
  2750. elm = level;
  2751. } else {
  2752. elm = range.document.createElement( tagName );
  2753. }
  2754. if ( attrs ) {
  2755. domUtils.setAttributes( elm, attrs );
  2756. }
  2757. elm.appendChild( frag );
  2758. range.insertNode( list ? top : elm );
  2759. //处理下滑线在a上的情况
  2760. var aNode;
  2761. if ( tagName == 'span' && attrs.style && /text\-decoration/.test( attrs.style ) && (aNode = domUtils.findParentByTagName( elm, 'a', true )) ) {
  2762. domUtils.setAttributes( aNode, attrs );
  2763. domUtils.remove( elm, true );
  2764. elm = aNode;
  2765. } else {
  2766. domUtils.mergSibling( elm );
  2767. domUtils.clearEmptySibling( elm );
  2768. }
  2769. //去除子节点相同的
  2770. domUtils.mergChild( elm, tagName, attrs );
  2771. current = domUtils.getNextDomNode( elm, false, filterFn );
  2772. domUtils.mergToParent( elm );
  2773. if ( node === end ) {
  2774. break;
  2775. }
  2776. } else {
  2777. current = domUtils.getNextDomNode( current, true, filterFn );
  2778. }
  2779. }
  2780. return this.moveToBookmark( bookmark );
  2781. },
  2782. /**
  2783. * 去掉inline样式
  2784. * @public
  2785. * @function
  2786. * @name baidu.editor.dom.Range.removeInlineStyle
  2787. * @param {String/Array} tagName 要去掉的标签名
  2788. * @return {Range} Range对象
  2789. */
  2790. removeInlineStyle:function ( tagName ) {
  2791. if ( this.collapsed )return this;
  2792. tagName = utils.isArray( tagName ) ? tagName : [tagName];
  2793. this.shrinkBoundary().adjustmentBoundary();
  2794. var start = this.startContainer, end = this.endContainer;
  2795. while ( 1 ) {
  2796. if ( start.nodeType == 1 ) {
  2797. if ( utils.indexOf( tagName, start.tagName.toLowerCase() ) > -1 ) {
  2798. break;
  2799. }
  2800. if ( start.tagName.toLowerCase() == 'body' ) {
  2801. start = null;
  2802. break;
  2803. }
  2804. }
  2805. start = start.parentNode;
  2806. }
  2807. while ( 1 ) {
  2808. if ( end.nodeType == 1 ) {
  2809. if ( utils.indexOf( tagName, end.tagName.toLowerCase() ) > -1 ) {
  2810. break;
  2811. }
  2812. if ( end.tagName.toLowerCase() == 'body' ) {
  2813. end = null;
  2814. break;
  2815. }
  2816. }
  2817. end = end.parentNode;
  2818. }
  2819. var bookmark = this.createBookmark(),
  2820. frag,
  2821. tmpRange;
  2822. if ( start ) {
  2823. tmpRange = this.cloneRange().setEndBefore( bookmark.start ).setStartBefore( start );
  2824. frag = tmpRange.extractContents();
  2825. tmpRange.insertNode( frag );
  2826. domUtils.clearEmptySibling( start, true );
  2827. start.parentNode.insertBefore( bookmark.start, start );
  2828. }
  2829. if ( end ) {
  2830. tmpRange = this.cloneRange().setStartAfter( bookmark.end ).setEndAfter( end );
  2831. frag = tmpRange.extractContents();
  2832. tmpRange.insertNode( frag );
  2833. domUtils.clearEmptySibling( end, false, true );
  2834. end.parentNode.insertBefore( bookmark.end, end.nextSibling );
  2835. }
  2836. var current = domUtils.getNextDomNode( bookmark.start, false, function ( node ) {
  2837. return node.nodeType == 1;
  2838. } ), next;
  2839. while ( current && current !== bookmark.end ) {
  2840. next = domUtils.getNextDomNode( current, true, function ( node ) {
  2841. return node.nodeType == 1;
  2842. } );
  2843. if ( utils.indexOf( tagName, current.tagName.toLowerCase() ) > -1 ) {
  2844. domUtils.remove( current, true );
  2845. }
  2846. current = next;
  2847. }
  2848. return this.moveToBookmark( bookmark );
  2849. },
  2850. /**
  2851. * 得到一个自闭合的节点
  2852. * @public
  2853. * @function
  2854. * @name baidu.editor.dom.Range.getClosedNode
  2855. * @return {Node} 闭合节点
  2856. * @example
  2857. * <img />,<br />
  2858. */
  2859. getClosedNode:function () {
  2860. var node;
  2861. if ( !this.collapsed ) {
  2862. var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
  2863. if ( range.startContainer.nodeType == 1 && range.startContainer === range.endContainer && range.endOffset - range.startOffset == 1 ) {
  2864. var child = range.startContainer.childNodes[range.startOffset];
  2865. if ( child && child.nodeType == 1 && (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName]) ) {
  2866. node = child;
  2867. }
  2868. }
  2869. }
  2870. return node;
  2871. },
  2872. /**
  2873. * 根据range选中元素
  2874. * @public
  2875. * @function
  2876. * @name baidu.editor.dom.Range.select
  2877. * @param {Boolean} notInsertFillData true为不加占位符
  2878. */
  2879. select:browser.ie ? function ( notInsertFillData, textRange ) {
  2880. var nativeRange;
  2881. if ( !this.collapsed )
  2882. this.shrinkBoundary();
  2883. var node = this.getClosedNode();
  2884. if ( node && !textRange ) {
  2885. try {
  2886. nativeRange = this.document.body.createControlRange();
  2887. nativeRange.addElement( node );
  2888. nativeRange.select();
  2889. } catch ( e ) {}
  2890. return this;
  2891. }
  2892. var bookmark = this.createBookmark(),
  2893. start = bookmark.start,
  2894. end;
  2895. nativeRange = this.document.body.createTextRange();
  2896. nativeRange.moveToElementText( start );
  2897. nativeRange.moveStart( 'character', 1 );
  2898. if ( !this.collapsed ) {
  2899. var nativeRangeEnd = this.document.body.createTextRange();
  2900. end = bookmark.end;
  2901. nativeRangeEnd.moveToElementText( end );
  2902. nativeRange.setEndPoint( 'EndToEnd', nativeRangeEnd );
  2903. } else {
  2904. if ( !notInsertFillData && this.startContainer.nodeType != 3 ) {
  2905. //使用<span>|x<span>固定住光标
  2906. var tmpText = this.document.createTextNode( fillChar ),
  2907. tmp = this.document.createElement( 'span' );
  2908. tmp.appendChild( this.document.createTextNode( fillChar ) );
  2909. start.parentNode.insertBefore( tmp, start );
  2910. start.parentNode.insertBefore( tmpText, start );
  2911. //当点b,i,u时,不能清除i上边的b
  2912. removeFillData( this.document, tmpText );
  2913. fillData = tmpText;
  2914. mergSibling( tmp, 'previousSibling' );
  2915. mergSibling( start, 'nextSibling' );
  2916. nativeRange.moveStart( 'character', -1 );
  2917. nativeRange.collapse( true );
  2918. }
  2919. }
  2920. this.moveToBookmark( bookmark );
  2921. tmp && domUtils.remove( tmp );
  2922. //IE在隐藏状态下不支持range操作,catch一下
  2923. try{
  2924. nativeRange.select();
  2925. }catch(e){}
  2926. return this;
  2927. } : function ( notInsertFillData ) {
  2928. var win = domUtils.getWindow( this.document ),
  2929. sel = win.getSelection(),
  2930. txtNode;
  2931. //FF下关闭自动长高时滚动条在关闭dialog时会跳
  2932. //ff下如果不body.focus将不能定位闭合光标到编辑器内
  2933. browser.gecko ? this.document.body.focus() : win.focus();
  2934. if ( sel ) {
  2935. sel.removeAllRanges();
  2936. // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
  2937. // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
  2938. if ( this.collapsed ) {
  2939. //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
  2940. if ( notInsertFillData && browser.opera && !domUtils.isBody( this.startContainer ) && this.startContainer.nodeType == 1 ) {
  2941. var tmp = this.document.createTextNode( '' );
  2942. this.insertNode( tmp ).setStart( tmp, 0 ).collapse( true );
  2943. }
  2944. if ( !notInsertFillData ) {
  2945. txtNode = this.document.createTextNode( fillChar );
  2946. //跟着前边走
  2947. this.insertNode( txtNode );
  2948. removeFillData( this.document, txtNode );
  2949. mergSibling( txtNode, 'previousSibling' );
  2950. mergSibling( txtNode, 'nextSibling' );
  2951. fillData = txtNode;
  2952. this.setStart( txtNode, browser.webkit ? 1 : 0 ).collapse( true );
  2953. }
  2954. }
  2955. var nativeRange = this.document.createRange();
  2956. nativeRange.setStart( this.startContainer, this.startOffset );
  2957. nativeRange.setEnd( this.endContainer, this.endOffset );
  2958. sel.addRange( nativeRange );
  2959. }
  2960. return this;
  2961. },
  2962. /**
  2963. * 滚动到可视范围
  2964. * @public
  2965. * @function
  2966. * @name baidu.editor.dom.Range.scrollToView
  2967. * @param {Boolean} win 操作的window对象,若为空,则使用当前的window对象
  2968. * @param {Number} offset 滚动的偏移量
  2969. * @return {Range} Range对象
  2970. */
  2971. scrollToView:function ( win, offset ) {
  2972. win = win ? window : domUtils.getWindow( this.document );
  2973. var span = this.document.createElement( 'span' );
  2974. //trace:717
  2975. span.innerHTML = '&nbsp;';
  2976. var tmpRange = this.cloneRange();
  2977. tmpRange.insertNode( span );
  2978. domUtils.scrollToView( span, win, offset );
  2979. domUtils.remove( span );
  2980. return this;
  2981. }
  2982. };
  2983. })();
  2984. ///import editor.js
  2985. ///import core/browser.js
  2986. ///import core/dom/dom.js
  2987. ///import core/dom/dtd.js
  2988. ///import core/dom/domUtils.js
  2989. ///import core/dom/Range.js
  2990. /**
  2991. * @class baidu.editor.dom.Selection Selection类
  2992. */
  2993. (function () {
  2994. function getBoundaryInformation( range, start ) {
  2995. var getIndex = domUtils.getNodeIndex;
  2996. range = range.duplicate();
  2997. range.collapse( start );
  2998. var parent = range.parentElement();
  2999. //如果节点里没有子节点,直接退出
  3000. if ( !parent.hasChildNodes() ) {
  3001. return {container:parent, offset:0};
  3002. }
  3003. var siblings = parent.children,
  3004. child,
  3005. testRange = range.duplicate(),
  3006. startIndex = 0, endIndex = siblings.length - 1, index = -1,
  3007. distance;
  3008. while ( startIndex <= endIndex ) {
  3009. index = Math.floor( (startIndex + endIndex) / 2 );
  3010. child = siblings[index];
  3011. testRange.moveToElementText( child );
  3012. var position = testRange.compareEndPoints( 'StartToStart', range );
  3013. if ( position > 0 ) {
  3014. endIndex = index - 1;
  3015. } else if ( position < 0 ) {
  3016. startIndex = index + 1;
  3017. } else {
  3018. //trace:1043
  3019. return {container:parent, offset:getIndex( child )};
  3020. }
  3021. }
  3022. if ( index == -1 ) {
  3023. testRange.moveToElementText( parent );
  3024. testRange.setEndPoint( 'StartToStart', range );
  3025. distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
  3026. siblings = parent.childNodes;
  3027. if ( !distance ) {
  3028. child = siblings[siblings.length - 1];
  3029. return {container:child, offset:child.nodeValue.length};
  3030. }
  3031. var i = siblings.length;
  3032. while ( distance > 0 ){
  3033. distance -= siblings[ --i ].nodeValue.length;
  3034. }
  3035. return {container:siblings[i], offset:-distance};
  3036. }
  3037. testRange.collapse( position > 0 );
  3038. testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range );
  3039. distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
  3040. if ( !distance ) {
  3041. return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ?
  3042. {container:parent, offset:getIndex( child ) + (position > 0 ? 0 : 1)} :
  3043. {container:child, offset:position > 0 ? 0 : child.childNodes.length}
  3044. }
  3045. while ( distance > 0 ) {
  3046. try {
  3047. var pre = child;
  3048. child = child[position > 0 ? 'previousSibling' : 'nextSibling'];
  3049. distance -= child.nodeValue.length;
  3050. } catch ( e ) {
  3051. return {container:parent, offset:getIndex( pre )};
  3052. }
  3053. }
  3054. return {container:child, offset:position > 0 ? -distance : child.nodeValue.length + distance}
  3055. }
  3056. /**
  3057. * 将ieRange转换为Range对象
  3058. * @param {Range} ieRange ieRange对象
  3059. * @param {Range} range Range对象
  3060. * @return {Range} range 返回转换后的Range对象
  3061. */
  3062. function transformIERangeToRange( ieRange, range ) {
  3063. if ( ieRange.item ) {
  3064. range.selectNode( ieRange.item( 0 ) );
  3065. } else {
  3066. var bi = getBoundaryInformation( ieRange, true );
  3067. range.setStart( bi.container, bi.offset );
  3068. if ( ieRange.compareEndPoints( 'StartToEnd', ieRange ) != 0 ) {
  3069. bi = getBoundaryInformation( ieRange, false );
  3070. range.setEnd( bi.container, bi.offset );
  3071. }
  3072. }
  3073. return range;
  3074. }
  3075. /**
  3076. * 获得ieRange
  3077. * @param {Selection} sel Selection对象
  3078. * @return {ieRange} 得到ieRange
  3079. */
  3080. function _getIERange( sel ) {
  3081. var ieRange;
  3082. //ie下有可能报错
  3083. try {
  3084. ieRange = sel.getNative().createRange();
  3085. } catch ( e ) {
  3086. return null;
  3087. }
  3088. var el = ieRange.item ? ieRange.item( 0 ) : ieRange.parentElement();
  3089. if ( ( el.ownerDocument || el ) === sel.document ) {
  3090. return ieRange;
  3091. }
  3092. return null;
  3093. }
  3094. var Selection = dom.Selection = function ( doc ) {
  3095. var me = this, iframe;
  3096. me.document = doc;
  3097. if ( ie ) {
  3098. iframe = domUtils.getWindow( doc ).frameElement;
  3099. domUtils.on( iframe, 'beforedeactivate', function () {
  3100. me._bakIERange = me.getIERange();
  3101. } );
  3102. domUtils.on( iframe, 'activate', function () {
  3103. try {
  3104. if ( !_getIERange( me ) && me._bakIERange ) {
  3105. me._bakIERange.select();
  3106. }
  3107. } catch ( ex ) {
  3108. }
  3109. me._bakIERange = null;
  3110. } );
  3111. }
  3112. iframe = doc = null;
  3113. };
  3114. Selection.prototype = {
  3115. /**
  3116. * 获取原生seleciton对象
  3117. * @public
  3118. * @function
  3119. * @name baidu.editor.dom.Selection.getNative
  3120. * @return {Selection} 获得selection对象
  3121. */
  3122. getNative:function () {
  3123. var doc = this.document;
  3124. try {
  3125. return !doc ? null : ie ? doc.selection : domUtils.getWindow( doc ).getSelection();
  3126. } catch ( e ) {
  3127. return null;
  3128. }
  3129. },
  3130. /**
  3131. * 获得ieRange
  3132. * @public
  3133. * @function
  3134. * @name baidu.editor.dom.Selection.getIERange
  3135. * @return {ieRange} 返回ie原生的Range
  3136. */
  3137. getIERange:function () {
  3138. var ieRange = _getIERange( this );
  3139. if ( !ieRange ) {
  3140. if ( this._bakIERange ) {
  3141. return this._bakIERange;
  3142. }
  3143. }
  3144. return ieRange;
  3145. },
  3146. /**
  3147. * 缓存当前选区的range和选区的开始节点
  3148. * @public
  3149. * @function
  3150. * @name baidu.editor.dom.Selection.cache
  3151. */
  3152. cache:function () {
  3153. this.clear();
  3154. this._cachedRange = this.getRange();
  3155. this._cachedStartElement = this.getStart();
  3156. this._cachedStartElementPath = this.getStartElementPath();
  3157. },
  3158. getStartElementPath:function () {
  3159. if ( this._cachedStartElementPath ) {
  3160. return this._cachedStartElementPath;
  3161. }
  3162. var start = this.getStart();
  3163. if ( start ) {
  3164. return domUtils.findParents( start, true, null, true )
  3165. }
  3166. return [];
  3167. },
  3168. /**
  3169. * 清空缓存
  3170. * @public
  3171. * @function
  3172. * @name baidu.editor.dom.Selection.clear
  3173. */
  3174. clear:function () {
  3175. this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null;
  3176. },
  3177. /**
  3178. * 编辑器是否得到了选区
  3179. */
  3180. isFocus:function () {
  3181. try {
  3182. return browser.ie && _getIERange( this ) || !browser.ie && this.getNative().rangeCount ? true : false;
  3183. } catch ( e ) {
  3184. return false;
  3185. }
  3186. },
  3187. /**
  3188. * 获取选区对应的Range
  3189. * @public
  3190. * @function
  3191. * @name baidu.editor.dom.Selection.getRange
  3192. * @returns {baidu.editor.dom.Range} 得到Range对象
  3193. */
  3194. getRange:function () {
  3195. var me = this;
  3196. function optimze( range ) {
  3197. var child = me.document.body.firstChild,
  3198. collapsed = range.collapsed;
  3199. while ( child && child.firstChild ) {
  3200. range.setStart( child, 0 );
  3201. child = child.firstChild;
  3202. }
  3203. if ( !range.startContainer ) {
  3204. range.setStart( me.document.body, 0 )
  3205. }
  3206. if ( collapsed ) {
  3207. range.collapse( true );
  3208. }
  3209. }
  3210. if ( me._cachedRange != null ) {
  3211. return this._cachedRange;
  3212. }
  3213. var range = new baidu.editor.dom.Range( me.document );
  3214. if ( ie ) {
  3215. var nativeRange = me.getIERange();
  3216. if ( nativeRange ) {
  3217. transformIERangeToRange( nativeRange, range );
  3218. } else {
  3219. optimze( range );
  3220. }
  3221. } else {
  3222. var sel = me.getNative();
  3223. if ( sel && sel.rangeCount ) {
  3224. var firstRange = sel.getRangeAt( 0 );
  3225. var lastRange = sel.getRangeAt( sel.rangeCount - 1 );
  3226. range.setStart( firstRange.startContainer, firstRange.startOffset ).setEnd( lastRange.endContainer, lastRange.endOffset );
  3227. if ( range.collapsed && domUtils.isBody( range.startContainer ) && !range.startOffset ) {
  3228. optimze( range );
  3229. }
  3230. } else {
  3231. //trace:1734 有可能已经不在dom树上了,标识的节点
  3232. if ( this._bakRange && domUtils.inDoc( this._bakRange.startContainer, this.document ) ){
  3233. return this._bakRange;
  3234. }
  3235. optimze( range );
  3236. }
  3237. }
  3238. return this._bakRange = range;
  3239. },
  3240. /**
  3241. * 获取开始元素,用于状态反射
  3242. * @public
  3243. * @function
  3244. * @name baidu.editor.dom.Selection.getStart
  3245. * @return {Element} 获得开始元素
  3246. */
  3247. getStart:function () {
  3248. if ( this._cachedStartElement ) {
  3249. return this._cachedStartElement;
  3250. }
  3251. var range = ie ? this.getIERange() : this.getRange(),
  3252. tmpRange,
  3253. start, tmp, parent;
  3254. if ( ie ) {
  3255. if ( !range ) {
  3256. //todo 给第一个值可能会有问题
  3257. return this.document.body.firstChild;
  3258. }
  3259. //control元素
  3260. if ( range.item ){
  3261. return range.item( 0 );
  3262. }
  3263. tmpRange = range.duplicate();
  3264. //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
  3265. tmpRange.text.length > 0 && tmpRange.moveStart( 'character', 1 );
  3266. tmpRange.collapse( 1 );
  3267. start = tmpRange.parentElement();
  3268. parent = tmp = range.parentElement();
  3269. while ( tmp = tmp.parentNode ) {
  3270. if ( tmp == start ) {
  3271. start = parent;
  3272. break;
  3273. }
  3274. }
  3275. } else {
  3276. range.shrinkBoundary();
  3277. start = range.startContainer;
  3278. if ( start.nodeType == 1 && start.hasChildNodes() ){
  3279. start = start.childNodes[Math.min( start.childNodes.length - 1, range.startOffset )];
  3280. }
  3281. if ( start.nodeType == 3 ){
  3282. return start.parentNode;
  3283. }
  3284. }
  3285. return start;
  3286. },
  3287. /**
  3288. * 得到选区中的文本
  3289. * @public
  3290. * @function
  3291. * @name baidu.editor.dom.Selection.getText
  3292. * @return {String} 选区中包含的文本
  3293. */
  3294. getText:function () {
  3295. var nativeSel, nativeRange;
  3296. if ( this.isFocus() && (nativeSel = this.getNative()) ) {
  3297. nativeRange = browser.ie ? nativeSel.createRange() : nativeSel.getRangeAt( 0 );
  3298. return browser.ie ? nativeRange.text : nativeRange.toString();
  3299. }
  3300. return '';
  3301. }
  3302. };
  3303. })();
  3304. ///import editor.js
  3305. ///import core/utils.js
  3306. ///import core/EventBase.js
  3307. ///import core/browser.js
  3308. ///import core/dom/dom.js
  3309. ///import core/dom/domUtils.js
  3310. ///import core/dom/Selection.js
  3311. ///import core/dom/dtd.js
  3312. (function () {
  3313. var uid = 0,
  3314. _selectionChangeTimer;
  3315. function replaceSrc( div ) {
  3316. var imgs = div.getElementsByTagName( "img" ),
  3317. orgSrc;
  3318. for ( var i = 0, img; img = imgs[i++]; ) {
  3319. if ( orgSrc = img.getAttribute( "orgSrc" ) ) {
  3320. img.src = orgSrc;
  3321. img.removeAttribute( "orgSrc" );
  3322. }
  3323. }
  3324. var as = div.getElementsByTagName( "a" );
  3325. for ( var i = 0, ai; ai = as[i++]; i++ ) {
  3326. if ( ai.getAttribute( 'data_ue_src' ) ) {
  3327. ai.setAttribute( 'href', ai.getAttribute( 'data_ue_src' ) )
  3328. }
  3329. }
  3330. }
  3331. function setValue( form, editor ) {
  3332. var textarea;
  3333. if ( editor.textarea ) {
  3334. if ( utils.isString( editor.textarea ) ) {
  3335. for ( var i = 0, ti, tis = domUtils.getElementsByTagName( form, 'textarea' ); ti = tis[i++]; ) {
  3336. if ( ti.id == 'ueditor_textarea_' + editor.options.textarea ) {
  3337. textarea = ti;
  3338. break;
  3339. }
  3340. }
  3341. } else {
  3342. textarea = editor.textarea;
  3343. }
  3344. }
  3345. if ( !textarea ) {
  3346. form.appendChild( textarea = domUtils.creElm( document, 'textarea', {
  3347. 'name':editor.options.textarea,
  3348. 'id':'ueditor_textarea_' + editor.options.textarea,
  3349. 'style':"display:none"
  3350. } ) );
  3351. }
  3352. textarea.value = editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null,null,true)
  3353. }
  3354. /**
  3355. * 编辑器类
  3356. * @public
  3357. * @class
  3358. * @extends baidu.editor.EventBase
  3359. * @name baidu.editor.Editor
  3360. * @param {Object} options
  3361. */
  3362. var Editor = UE.Editor = function ( options ) {
  3363. var me = this;
  3364. me.uid = uid++;
  3365. EventBase.call( me );
  3366. me.commands = {};
  3367. me.options = utils.extend( options || {},UEDITOR_CONFIG, true );
  3368. //设置默认的常用属性
  3369. me.setOpt( {
  3370. isShow:true,
  3371. initialContent:'欢迎使用ueditor!',
  3372. autoClearinitialContent:false,
  3373. iframeCssUrl:me.options.UEDITOR_HOME_URL + '/themes/default/iframe.css',
  3374. textarea:'editorValue',
  3375. focus:false,
  3376. minFrameHeight:320,
  3377. autoClearEmptyNode:true,
  3378. fullscreen:false,
  3379. readonly:false,
  3380. zIndex:999,
  3381. imagePopup:true,
  3382. enterTag:'p',
  3383. pageBreakTag:'_baidu_page_break_tag_',
  3384. customDomain:false,
  3385. lang:'zh-cn',
  3386. langPath:me.options.UEDITOR_HOME_URL + 'lang/',
  3387. allHtmlEnabled:false
  3388. } );
  3389. utils.loadFile( document, {
  3390. src:me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
  3391. tag:"script",
  3392. type:"text/javascript",
  3393. defer:"defer"
  3394. }, function () {
  3395. //初始化插件
  3396. for ( var pi in UE.plugins ) {
  3397. UE.plugins[pi].call( me )
  3398. }
  3399. me.langIsReady = true;
  3400. me.fireEvent( "langReady" );
  3401. } );
  3402. UE.instants['ueditorInstant' + me.uid] = me;
  3403. };
  3404. Editor.prototype = /**@lends baidu.editor.Editor.prototype*/{
  3405. /**
  3406. * 当编辑器ready后执行传入的fn,如果编辑器已经ready好了,就马上执行fn,fn的中的this是编辑器实例
  3407. * @param {function} fn 需要执行的函数
  3408. */
  3409. ready:function ( fn ) {
  3410. var me = this;
  3411. if ( fn )
  3412. me.isReady ? fn.apply( me ) : me.addListener( 'ready', fn );
  3413. },
  3414. setOpt:function ( key, val ) {
  3415. var obj = {};
  3416. if ( utils.isString( key ) ) {
  3417. obj[key] = val
  3418. } else {
  3419. obj = key;
  3420. }
  3421. utils.extend( this.options, obj, true );
  3422. },
  3423. destroy:function () {
  3424. var me = this;
  3425. me.fireEvent( 'destroy' );
  3426. me.container.innerHTML = '';
  3427. domUtils.remove( me.container );
  3428. //trace:2004
  3429. for ( var p in me ) {
  3430. if ( me.hasOwnProperty( p ) ) {
  3431. delete this[p];
  3432. }
  3433. }
  3434. },
  3435. /**
  3436. * 渲染编辑器的DOM到指定容器,必须且只能调用一次
  3437. * @public
  3438. * @function
  3439. * @param {Element|String} container
  3440. */
  3441. render:function ( container ) {
  3442. var me = this, options = me.options;
  3443. if ( container.constructor === String ) {
  3444. container = document.getElementById( container );
  3445. }
  3446. if ( container ) {
  3447. var useBodyAsViewport = ie && browser.version < 9,
  3448. html = ( ie && browser.version < 9 ? '' : '<!DOCTYPE html>') +
  3449. '<html xmlns=\'http://www.w3.org/1999/xhtml\'' + (!useBodyAsViewport ? ' class=\'view\'' : '') + '><head>' +
  3450. ( options.iframeCssUrl ? '<link rel=\'stylesheet\' type=\'text/css\' href=\'' + utils.unhtml( options.iframeCssUrl ) + '\'/>' : '' ) +
  3451. '<style type=\'text/css\'>' +
  3452. //这些默认属性不能够让用户改变
  3453. //选中的td上的样式
  3454. '.selectTdClass{background-color:#3399FF !important;}' +
  3455. 'table.noBorderTable td{border:1px dashed #ddd !important}' +
  3456. //插入的表格的默认样式
  3457. 'table{clear:both;margin-bottom:10px;border-collapse:collapse;word-break:break-all;}' +
  3458. //分页符的样式
  3459. '.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}' +
  3460. //锚点的样式,注意这里背景图的路径
  3461. '.anchorclass{background: url(\'' + me.options.UEDITOR_HOME_URL + 'themes/default/images/anchor.gif\') no-repeat scroll left center transparent;border: 1px dotted #0000FF;cursor: auto;display: inline-block;height: 16px;width: 15px;}' +
  3462. //设置四周的留边
  3463. '.view{padding:0;word-wrap:break-word;cursor:text;height:100%;}\n' +
  3464. //设置默认字体和字号
  3465. 'body{margin:8px;font-family:\'宋体\';font-size:16px;}' +
  3466. //针对li的处理
  3467. 'li{clear:both}' +
  3468. //设置段落间距
  3469. 'p{margin:5px 0;}'
  3470. + ( options.initialStyle || '' ) +
  3471. '</style></head><body' + (useBodyAsViewport ? ' class=\'view\'' : '') + '></body>';
  3472. if ( options.customDomain && document.domain != location.hostname ) {
  3473. html += '<script>window.parent.UE.instants[\'ueditorInstant' + me.uid + '\']._setup(document);</script></html>';
  3474. container.appendChild( domUtils.creElm( document, 'iframe', {
  3475. id:'baidu_editor_' + me.uid,
  3476. width:"100%",
  3477. height:"100%",
  3478. frameborder:"0",
  3479. src:'javascript:void(function(){document.open();document.domain="' + document.domain + '";' +
  3480. 'document.write("' + html + '");document.close();}())'
  3481. } ) );
  3482. } else {
  3483. container.innerHTML = '<iframe id="' + 'baidu_editor_' + this.uid + '"' + 'width="100%" height="100%" scroll="no" frameborder="0" ></iframe>';
  3484. var doc = container.firstChild.contentWindow.document;
  3485. !browser.webkit && doc.open();
  3486. doc.write( html + '</html>' );
  3487. !browser.webkit && doc.close();
  3488. me._setup( doc );
  3489. }
  3490. container.style.overflow = 'hidden';
  3491. }
  3492. },
  3493. _setup:function ( doc ) {
  3494. var me = this,
  3495. options = me.options;
  3496. if ( ie ) {
  3497. doc.body.disabled = true;
  3498. doc.body.contentEditable = true;
  3499. doc.body.disabled = false;
  3500. } else {
  3501. doc.body.contentEditable = true;
  3502. doc.body.spellcheck = false;
  3503. }
  3504. me.document = doc;
  3505. me.window = doc.defaultView || doc.parentWindow;
  3506. me.iframe = me.window.frameElement;
  3507. me.body = doc.body;
  3508. //设置编辑器最小高度
  3509. me.setHeight( options.minFrameHeight );
  3510. me.selection = new dom.Selection( doc );
  3511. //gecko初始化就能得到range,无法判断isFocus了
  3512. var geckoSel;
  3513. if ( browser.gecko && (geckoSel = this.selection.getNative()) ) {
  3514. geckoSel.removeAllRanges();
  3515. }
  3516. this._initEvents();
  3517. if ( options.initialContent ) {
  3518. if ( options.autoClearinitialContent ) {
  3519. var oldExecCommand = me.execCommand;
  3520. me.execCommand = function () {
  3521. me.fireEvent( 'firstBeforeExecCommand' );
  3522. oldExecCommand.apply( me, arguments );
  3523. };
  3524. this.setDefaultContent( options.initialContent );
  3525. } else
  3526. this.setContent( options.initialContent, true );
  3527. }
  3528. //为form提交提供一个隐藏的textarea
  3529. for ( var form = this.iframe.parentNode; !domUtils.isBody( form ); form = form.parentNode ) {
  3530. if ( form.tagName == 'FORM' ) {
  3531. domUtils.on( form, 'submit', function () {
  3532. setValue( this, me );
  3533. } );
  3534. break;
  3535. }
  3536. }
  3537. //编辑器不能为空内容
  3538. if ( domUtils.isEmptyNode( me.body ) ) {
  3539. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  3540. }
  3541. //如果要求focus, 就把光标定位到内容开始
  3542. if ( options.focus ) {
  3543. setTimeout( function () {
  3544. me.focus();
  3545. //如果自动清除开着,就不需要做selectionchange;
  3546. !me.options.autoClearinitialContent && me._selectionChange();
  3547. } );
  3548. }
  3549. if ( !me.container ) {
  3550. me.container = this.iframe.parentNode;
  3551. }
  3552. if ( options.fullscreen && me.ui ) {
  3553. me.ui.setFullScreen( true );
  3554. }
  3555. me.isReady = 1;
  3556. me.fireEvent( 'ready' );
  3557. if ( !browser.ie ) {
  3558. domUtils.on( me.window, ['blur', 'focus'], function ( e ) {
  3559. //chrome下会出现alt+tab切换时,导致选区位置不对
  3560. if ( e.type == 'blur' ) {
  3561. me._bakRange = me.selection.getRange();
  3562. try{
  3563. me.selection.getNative().removeAllRanges();
  3564. }catch(e){}
  3565. } else {
  3566. try {
  3567. me._bakRange && me._bakRange.select();
  3568. } catch ( e ) {
  3569. }
  3570. }
  3571. } );
  3572. }
  3573. //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
  3574. if ( browser.gecko && browser.version <= 10902 ) {
  3575. //修复ff3.6初始化进来,不能点击获得焦点
  3576. me.body.contentEditable = false;
  3577. setTimeout( function () {
  3578. me.body.contentEditable = true;
  3579. }, 100 );
  3580. setInterval( function () {
  3581. me.body.style.height = me.iframe.offsetHeight - 20 + 'px'
  3582. }, 100 )
  3583. }
  3584. !options.isShow && me.setHide();
  3585. options.readonly && me.setDisabled();
  3586. },
  3587. /**
  3588. * 创建textarea,同步编辑的内容到textarea,为后台获取内容做准备
  3589. * @param formId 制定在那个form下添加
  3590. * @public
  3591. * @function
  3592. */
  3593. sync:function ( formId ) {
  3594. var me = this,
  3595. form = formId ? document.getElementById( formId ) :
  3596. domUtils.findParent( me.iframe.parentNode, function ( node ) {
  3597. return node.tagName == 'FORM'
  3598. }, true );
  3599. form && setValue( form, me );
  3600. },
  3601. /**
  3602. * 设置编辑器高度
  3603. * @public
  3604. * @function
  3605. * @param {Number} height 高度
  3606. */
  3607. setHeight:function ( height ) {
  3608. if ( height !== parseInt( this.iframe.parentNode.style.height ) ) {
  3609. this.iframe.parentNode.style.height = height + 'px';
  3610. }
  3611. this.document.body.style.height = height - 20 + 'px';
  3612. },
  3613. /**
  3614. * 获取编辑器内容
  3615. * @public
  3616. * @function
  3617. * @returns {String}
  3618. */
  3619. getContent:function ( cmd, fn, isPreview ) {
  3620. var me = this;
  3621. if ( cmd && utils.isFunction( cmd ) ) {
  3622. fn = cmd;
  3623. cmd = '';
  3624. }
  3625. if ( fn ? !fn() : !this.hasContents() ) {
  3626. return '';
  3627. }
  3628. me.fireEvent( 'beforegetcontent', cmd );
  3629. var reg = new RegExp( domUtils.fillChar, 'g' ),
  3630. //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
  3631. html = me.body.innerHTML.replace( reg, '' ).replace( />[\t\r\n]*?</g, '><' );
  3632. me.fireEvent( 'aftergetcontent', cmd );
  3633. if ( me.serialize ) {
  3634. var node = me.serialize.parseHTML( html );
  3635. node = me.serialize.transformOutput( node );
  3636. html = me.serialize.toHTML( node );
  3637. }
  3638. if ( ie && isPreview ) {
  3639. //trace:2471
  3640. //两个br会导致空行,所以这里先注视掉
  3641. html = html//.replace(/<\s*br\s*\/?\s*>/gi,'<br/><br/>')
  3642. .replace( /<p>\s*?<\/p>/g, '<p>&nbsp;</p>' );
  3643. } else {
  3644. //多个&nbsp;要转换成空格加&nbsp;的形式,要不预览时会所成一个
  3645. html = html.replace( /(&nbsp;)+/g, function ( s ) {
  3646. for ( var i = 0, str = [], l = s.split( ';' ).length - 1; i < l; i++ ) {
  3647. str.push( i % 2 == 0 ? ' ' : '&nbsp;' );
  3648. }
  3649. return str.join( '' );
  3650. } );
  3651. }
  3652. return html;
  3653. },
  3654. getAllHtml:function () {
  3655. var me = this,
  3656. headHtml = {html:''},
  3657. html = '';
  3658. me.fireEvent( 'getAllHtml', headHtml );
  3659. return '<html><head>' + (me.options.charset ? '<meta http-equiv="Content-Type" content="text/html; charset=' + me.options.charset + '"/>' : '') + me.document.getElementsByTagName( 'head' )[0].innerHTML + headHtml.html + '</head>'
  3660. + '<body ' + (ie && browser.version < 9 ? 'class="view"' : '') + '>' + me.getContent( null, null, true ) + '</body></html>';
  3661. },
  3662. /**
  3663. * 得到编辑器的纯文本内容,但会保留段落格式
  3664. * @public
  3665. * @function
  3666. * @returns {String}
  3667. */
  3668. getPlainTxt:function () {
  3669. var reg = new RegExp( domUtils.fillChar, 'g' ),
  3670. html = this.body.innerHTML.replace( /[\n\r]/g, '' );//ie要先去了\n在处理
  3671. html = html.replace( /<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, '\n' )
  3672. .replace( /<br\/?>/gi, '\n' )
  3673. .replace( /<[^>/]+>/g, '' )
  3674. .replace( /(\n)?<\/([^>]+)>/g, function ( a, b, c ) {
  3675. return dtd.$block[c] ? '\n' : b ? b : '';
  3676. } );
  3677. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  3678. return html.replace( reg, '' ).replace( /\u00a0/g, ' ' ).replace( /&nbsp;/g, ' ' );
  3679. },
  3680. /**
  3681. * 获取编辑器中的文本内容
  3682. * @public
  3683. * @function
  3684. * @returns {String}
  3685. */
  3686. getContentTxt:function () {
  3687. var reg = new RegExp( domUtils.fillChar, 'g' );
  3688. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  3689. return this.body[browser.ie ? 'innerText' : 'textContent'].replace( reg, '' ).replace( /\u00a0/g, ' ' );
  3690. },
  3691. /**
  3692. * 设置编辑器内容
  3693. * @public
  3694. * @function
  3695. * @param {String} html
  3696. */
  3697. setContent:function ( html, notFireSelectionchange ) {
  3698. var me = this,
  3699. inline = utils.extend( {a:1, A:1}, dtd.$inline, true ),
  3700. lastTagName;
  3701. html = html
  3702. .replace( /^[ \t\r\n]*?</, '<' )
  3703. .replace( />[ \t\r\n]*?$/, '>' )
  3704. .replace( />[\t\r\n]*?</g, '><' )//代码高量的\n不能去除
  3705. .replace( /[\s\/]?(\w+)?>[ \t\r\n]*?<\/?(\w+)/gi, function ( a, b, c ) {
  3706. if ( b ) {
  3707. lastTagName = c;
  3708. } else {
  3709. b = lastTagName;
  3710. }
  3711. return !inline[b] && !inline[c] ? a.replace( />[ \t\r\n]*?</, '><' ) : a;
  3712. } );
  3713. me.fireEvent( 'beforesetcontent' );
  3714. var serialize = this.serialize;
  3715. if ( serialize ) {
  3716. var node = serialize.parseHTML( html );
  3717. node = serialize.transformInput( node );
  3718. node = serialize.filter( node );
  3719. html = serialize.toHTML( node );
  3720. }
  3721. //html.replace(new RegExp('[\t\n\r' + domUtils.fillChar + ']*','g'),'');
  3722. //去掉了\t\n\r 如果有插入的代码,在源码切换所见即所得模式时,换行都丢掉了
  3723. //\r在ie下的不可见字符,在源码切换时会变成多个&nbsp;
  3724. //trace:1559
  3725. this.body.innerHTML = html.replace( new RegExp( '[\r' + domUtils.fillChar + ']*', 'g' ), '' );
  3726. //处理ie6下innerHTML自动将相对路径转化成绝对路径的问题
  3727. if ( browser.ie && browser.version < 7 ) {
  3728. replaceSrc( this.document.body );
  3729. }
  3730. //给文本或者inline节点套p标签
  3731. if ( me.options.enterTag == 'p' ) {
  3732. var child = this.body.firstChild, tmpNode;
  3733. if ( !child || child.nodeType == 1 &&
  3734. (dtd.$cdata[child.tagName] ||
  3735. domUtils.isCustomeNode( child )
  3736. )
  3737. && child === this.body.lastChild ) {
  3738. this.body.innerHTML = '<p>' + (browser.ie ? '&nbsp;' : '<br/>') + '</p>' + this.body.innerHTML;
  3739. } else {
  3740. var p = me.document.createElement( 'p' );
  3741. while ( child ) {
  3742. while ( child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child.tagName] && !dtd.$cdata[child.tagName]) ) {
  3743. tmpNode = child.nextSibling;
  3744. p.appendChild( child );
  3745. child = tmpNode;
  3746. }
  3747. if ( p.firstChild ) {
  3748. if ( !child ) {
  3749. me.body.appendChild( p );
  3750. break;
  3751. } else {
  3752. me.body.insertBefore( p, child );
  3753. p = me.document.createElement( 'p' );
  3754. }
  3755. }
  3756. child = child.nextSibling;
  3757. }
  3758. }
  3759. }
  3760. me.adjustTable && me.adjustTable( me.body );
  3761. me.fireEvent( 'aftersetcontent' );
  3762. me.fireEvent( 'contentchange' );
  3763. !notFireSelectionchange && me._selectionChange();
  3764. //清除保存的选区
  3765. me._bakRange = me._bakIERange = null;
  3766. //trace:1742 setContent后gecko能得到焦点问题
  3767. var geckoSel;
  3768. if ( browser.gecko && (geckoSel = this.selection.getNative()) ) {
  3769. geckoSel.removeAllRanges();
  3770. }
  3771. },
  3772. /**
  3773. * 让编辑器获得焦点
  3774. * @public
  3775. * @function
  3776. * @param{boolean}toEnd 默认是到头部,true到尾部
  3777. */
  3778. focus:function ( toEnd ) {
  3779. try {
  3780. var me = this,
  3781. rng = me.selection.getRange();
  3782. if ( toEnd ) {
  3783. rng.setStartAtLast( me.body.lastChild ).setCursor( false, true );
  3784. } else {
  3785. rng.select( true );
  3786. }
  3787. } catch ( e ) {
  3788. }
  3789. },
  3790. /**
  3791. * 初始化事件,绑定selectionchange
  3792. * @private
  3793. * @function
  3794. */
  3795. _initEvents:function () {
  3796. var me = this,
  3797. doc = me.document,
  3798. win = me.window;
  3799. me._proxyDomEvent = utils.bind( me._proxyDomEvent, me );
  3800. domUtils.on( doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent );
  3801. domUtils.on( win, ['focus', 'blur'], me._proxyDomEvent );
  3802. domUtils.on( doc, ['mouseup', 'keydown'], function ( evt ) {
  3803. //特殊键不触发selectionchange
  3804. if ( evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey) ) {
  3805. return;
  3806. }
  3807. if ( evt.button == 2 )return;
  3808. me._selectionChange( 250, evt );
  3809. } );
  3810. //处理拖拽
  3811. //ie ff不能从外边拖入
  3812. //chrome只针对从外边拖入的内容过滤
  3813. var innerDrag = 0, source = browser.ie ? me.body : me.document, dragoverHandler;
  3814. domUtils.on( source, 'dragstart', function () {
  3815. innerDrag = 1;
  3816. } );
  3817. domUtils.on( source, browser.webkit ? 'dragover' : 'drop', function () {
  3818. return browser.webkit ?
  3819. function () {
  3820. clearTimeout( dragoverHandler );
  3821. dragoverHandler = setTimeout( function () {
  3822. if ( !innerDrag ) {
  3823. var sel = me.selection,
  3824. range = sel.getRange();
  3825. if ( range ) {
  3826. var common = range.getCommonAncestor();
  3827. if ( common && me.serialize ) {
  3828. var f = me.serialize,
  3829. node =
  3830. f.filter(
  3831. f.transformInput(
  3832. f.parseHTML(
  3833. f.word( common.innerHTML )
  3834. )
  3835. )
  3836. );
  3837. common.innerHTML = f.toHTML( node );
  3838. }
  3839. }
  3840. }
  3841. innerDrag = 0;
  3842. }, 200 );
  3843. } :
  3844. function ( e ) {
  3845. if ( !innerDrag ) {
  3846. e.preventDefault ? e.preventDefault() : (e.returnValue = false);
  3847. }
  3848. innerDrag = 0;
  3849. }
  3850. }() );
  3851. },
  3852. _proxyDomEvent:function ( evt ) {
  3853. return this.fireEvent( evt.type.replace( /^on/, '' ), evt );
  3854. },
  3855. _selectionChange:function ( delay, evt ) {
  3856. var me = this;
  3857. //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
  3858. // if ( !me.selection.isFocus() ){
  3859. // return;
  3860. // }
  3861. var hackForMouseUp = false;
  3862. var mouseX, mouseY;
  3863. if ( browser.ie && browser.version < 9 && evt && evt.type == 'mouseup' ) {
  3864. var range = this.selection.getRange();
  3865. if ( !range.collapsed ) {
  3866. hackForMouseUp = true;
  3867. mouseX = evt.clientX;
  3868. mouseY = evt.clientY;
  3869. }
  3870. }
  3871. clearTimeout( _selectionChangeTimer );
  3872. _selectionChangeTimer = setTimeout( function () {
  3873. if ( !me.selection.getNative() ) {
  3874. return;
  3875. }
  3876. //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
  3877. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
  3878. var ieRange;
  3879. if ( hackForMouseUp && me.selection.getNative().type == 'None' ) {
  3880. ieRange = me.document.body.createTextRange();
  3881. try {
  3882. ieRange.moveToPoint( mouseX, mouseY );
  3883. } catch ( ex ) {
  3884. ieRange = null;
  3885. }
  3886. }
  3887. var bakGetIERange;
  3888. if ( ieRange ) {
  3889. bakGetIERange = me.selection.getIERange;
  3890. me.selection.getIERange = function () {
  3891. return ieRange;
  3892. };
  3893. }
  3894. me.selection.cache();
  3895. if ( bakGetIERange ) {
  3896. me.selection.getIERange = bakGetIERange;
  3897. }
  3898. if ( me.selection._cachedRange && me.selection._cachedStartElement ) {
  3899. me.fireEvent( 'beforeselectionchange' );
  3900. // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
  3901. me.fireEvent( 'selectionchange', !!evt );
  3902. me.fireEvent( 'afterselectionchange' );
  3903. me.selection.clear();
  3904. }
  3905. }, delay || 50 );
  3906. },
  3907. _callCmdFn:function ( fnName, args ) {
  3908. var cmdName = args[0].toLowerCase(),
  3909. cmd, cmdFn;
  3910. cmd = this.commands[cmdName] || UE.commands[cmdName];
  3911. cmdFn = cmd && cmd[fnName];
  3912. //没有querycommandstate或者没有command的都默认返回0
  3913. if ( (!cmd || !cmdFn) && fnName == 'queryCommandState' ) {
  3914. return 0;
  3915. } else if ( cmdFn ) {
  3916. return cmdFn.apply( this, args );
  3917. }
  3918. },
  3919. /**
  3920. * 执行命令
  3921. * @public
  3922. * @function
  3923. * @param {String} cmdName 执行的命令名
  3924. *
  3925. */
  3926. execCommand:function ( cmdName ) {
  3927. cmdName = cmdName.toLowerCase();
  3928. var me = this,
  3929. result,
  3930. cmd = me.commands[cmdName] || UE.commands[cmdName];
  3931. if ( !cmd || !cmd.execCommand ) {
  3932. return;
  3933. }
  3934. if ( !cmd.notNeedUndo && !me.__hasEnterExecCommand ) {
  3935. me.__hasEnterExecCommand = true;
  3936. if ( me.queryCommandState( cmdName ) != -1 ) {
  3937. me.fireEvent( 'beforeexeccommand', cmdName );
  3938. result = this._callCmdFn( 'execCommand', arguments );
  3939. me.fireEvent( 'afterexeccommand', cmdName );
  3940. }
  3941. me.__hasEnterExecCommand = false;
  3942. } else {
  3943. result = this._callCmdFn( 'execCommand', arguments );
  3944. }
  3945. me._selectionChange();
  3946. return result;
  3947. },
  3948. /**
  3949. * 查询命令的状态
  3950. * @public
  3951. * @function
  3952. * @param {String} cmdName 执行的命令名
  3953. * @returns {Number|*} -1 : disabled, false : normal, true : enabled.
  3954. *
  3955. */
  3956. queryCommandState:function ( cmdName ) {
  3957. return this._callCmdFn( 'queryCommandState', arguments );
  3958. },
  3959. /**
  3960. * 查询命令的值
  3961. * @public
  3962. * @function
  3963. * @param {String} cmdName 执行的命令名
  3964. * @returns {*}
  3965. */
  3966. queryCommandValue:function ( cmdName ) {
  3967. return this._callCmdFn( 'queryCommandValue', arguments );
  3968. },
  3969. /**
  3970. * 检查编辑区域中是否有内容
  3971. * @public
  3972. * @params{Array} 自定义的标签
  3973. * @function
  3974. * @returns {Boolean} true 有,false 没有
  3975. */
  3976. hasContents:function ( tags ) {
  3977. if ( tags ) {
  3978. for ( var i = 0, ci; ci = tags[i++]; ) {
  3979. if ( this.document.getElementsByTagName( ci ).length > 0 ) {
  3980. return true;
  3981. }
  3982. }
  3983. }
  3984. if ( !domUtils.isEmptyBlock( this.body ) ) {
  3985. return true
  3986. }
  3987. //随时添加,定义的特殊标签如果存在,不能认为是空
  3988. tags = ['div'];
  3989. for ( i = 0; ci = tags[i++]; ) {
  3990. var nodes = domUtils.getElementsByTagName( this.document, ci );
  3991. for ( var n = 0, cn; cn = nodes[n++]; ) {
  3992. if ( domUtils.isCustomeNode( cn ) ) {
  3993. return true;
  3994. }
  3995. }
  3996. }
  3997. return false;
  3998. },
  3999. /**
  4000. * 从新设置
  4001. * @public
  4002. * @function
  4003. */
  4004. reset:function () {
  4005. this.fireEvent( 'reset' );
  4006. },
  4007. /**
  4008. * 设置编辑区域可以编辑
  4009. */
  4010. setEnabled:function () {
  4011. var me = this, range;
  4012. if ( me.body.contentEditable == 'false' ) {
  4013. me.body.contentEditable = true;
  4014. range = me.selection.getRange();
  4015. //有可能内容丢失了
  4016. try {
  4017. range.moveToBookmark( me.lastBk );
  4018. delete me.lastBk
  4019. } catch ( e ) {
  4020. range.setStartAtFirst( me.body ).collapse( true )
  4021. }
  4022. range.select( true );
  4023. if ( me.bkqueryCommandState ) {
  4024. me.queryCommandState = me.bkqueryCommandState;
  4025. delete me.bkqueryCommandState;
  4026. }
  4027. me.fireEvent( 'selectionchange' );
  4028. }
  4029. },
  4030. /**
  4031. * 设置编辑区域不可以编辑
  4032. */
  4033. setDisabled:function ( exclude ) {
  4034. var me = this;
  4035. exclude = exclude ? utils.isArray( exclude ) ? exclude : [exclude] : [];
  4036. if ( me.body.contentEditable == 'true' ) {
  4037. if ( !me.lastBk ) {
  4038. me.lastBk = me.selection.getRange().createBookmark( true );
  4039. }
  4040. me.body.contentEditable = false;
  4041. me.bkqueryCommandState = me.queryCommandState;
  4042. me.queryCommandState = function ( type ) {
  4043. if ( utils.indexOf( exclude, type ) != -1 ) {
  4044. return me.bkqueryCommandState.apply( me, arguments );
  4045. }
  4046. return -1;
  4047. };
  4048. me.fireEvent( 'selectionchange' );
  4049. }
  4050. },
  4051. /**
  4052. * 设置默认内容
  4053. * @function
  4054. * @param {String} cont 要存入的内容
  4055. */
  4056. setDefaultContent:function () {
  4057. function clear() {
  4058. var me = this;
  4059. if ( me.document.getElementById( 'initContent' ) ) {
  4060. me.document.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>';
  4061. var range = me.selection.getRange();
  4062. me.removeListener( 'firstBeforeExecCommand', clear );
  4063. me.removeListener( 'focus', clear );
  4064. setTimeout( function () {
  4065. range.setStart( me.document.body.firstChild, 0 ).collapse( true ).select( true );
  4066. me._selectionChange();
  4067. } )
  4068. }
  4069. }
  4070. return function ( cont ) {
  4071. var me = this;
  4072. me.document.body.innerHTML = '<p id="initContent">' + cont + '</p>';
  4073. if ( browser.ie && browser.version < 7 ) {
  4074. replaceSrc( me.document.body );
  4075. }
  4076. me.addListener( 'firstBeforeExecCommand', clear );
  4077. me.addListener( 'focus', clear );
  4078. }
  4079. }(),
  4080. /**
  4081. * 设置编辑器显示
  4082. * @function
  4083. */
  4084. setShow:function () {
  4085. var me = this,
  4086. range = me.selection.getRange();
  4087. if ( me.container.style.display == 'none' ) {
  4088. //有可能内容丢失了
  4089. try {
  4090. range.moveToBookmark( me.lastBk );
  4091. delete me.lastBk
  4092. } catch ( e ) {
  4093. range.setStartAtFirst( me.body ).collapse( true )
  4094. }
  4095. range.select( true );
  4096. me.container.style.display = '';
  4097. }
  4098. },
  4099. /**
  4100. * 设置编辑器隐藏
  4101. * @function
  4102. */
  4103. setHide:function () {
  4104. var me = this;
  4105. if ( !me.lastBk ) {
  4106. me.lastBk = me.selection.getRange().createBookmark( true );
  4107. }
  4108. me.container.style.display = 'none'
  4109. },
  4110. getLang:function ( path ) {
  4111. var lang = UE.I18N[this.options.lang];
  4112. path = (path || "").split( "." );
  4113. for ( var i = 0, ci; ci = path[i++]; ) {
  4114. lang = lang[ci];
  4115. if ( !lang )break;
  4116. }
  4117. return lang;
  4118. }
  4119. };
  4120. utils.inherits( Editor, EventBase );
  4121. })();
  4122. /**
  4123. * Created by .
  4124. * User: taoqili
  4125. * Date: 11-8-18
  4126. * Time: 下午3:18
  4127. * To change this template use File | Settings | File Templates.
  4128. */
  4129. /**
  4130. * ajax工具类
  4131. */
  4132. UE.ajax = function() {
  4133. return {
  4134. /**
  4135. * 向url发送ajax请求
  4136. * @param url
  4137. * @param ajaxOptions
  4138. */
  4139. request:function(url, ajaxOptions) {
  4140. var ajaxRequest = creatAjaxRequest(),
  4141. //是否超时
  4142. timeIsOut = false,
  4143. //默认参数
  4144. defaultAjaxOptions = {
  4145. method:"POST",
  4146. timeout:5000,
  4147. async:true,
  4148. data:{},//需要传递对象的话只能覆盖
  4149. onsuccess:function() {
  4150. },
  4151. onerror:function() {
  4152. }
  4153. };
  4154. if (typeof url === "object") {
  4155. ajaxOptions = url;
  4156. url = ajaxOptions.url;
  4157. }
  4158. if (!ajaxRequest || !url) return;
  4159. var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions,ajaxOptions) : defaultAjaxOptions;
  4160. var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  4161. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  4162. if (!utils.isEmptyObject(ajaxOpts.data)){
  4163. submitStr += (submitStr? "&":"") + json2str(ajaxOpts.data);
  4164. }
  4165. //超时检测
  4166. var timerID = setTimeout(function() {
  4167. if (ajaxRequest.readyState != 4) {
  4168. timeIsOut = true;
  4169. ajaxRequest.abort();
  4170. clearTimeout(timerID);
  4171. }
  4172. }, ajaxOpts.timeout);
  4173. var method = ajaxOpts.method.toUpperCase();
  4174. var str = url + (url.indexOf("?")==-1?"?":"&") + (method=="POST"?"":submitStr+ "&noCache=" + +new Date);
  4175. ajaxRequest.open(method, str, ajaxOpts.async);
  4176. ajaxRequest.onreadystatechange = function() {
  4177. if (ajaxRequest.readyState == 4) {
  4178. if (!timeIsOut && ajaxRequest.status == 200) {
  4179. ajaxOpts.onsuccess(ajaxRequest);
  4180. } else {
  4181. ajaxOpts.onerror(ajaxRequest);
  4182. }
  4183. }
  4184. };
  4185. if (method == "POST") {
  4186. ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  4187. ajaxRequest.send(submitStr);
  4188. } else {
  4189. ajaxRequest.send(null);
  4190. }
  4191. }
  4192. };
  4193. /**
  4194. * 将json参数转化成适合ajax提交的参数列表
  4195. * @param json
  4196. */
  4197. function json2str(json) {
  4198. var strArr = [];
  4199. for (var i in json) {
  4200. //忽略默认的几个参数
  4201. if(i=="method" || i=="timeout" || i=="async") continue;
  4202. //传递过来的对象和函数不在提交之列
  4203. if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) {
  4204. strArr.push( encodeURIComponent(i) + "="+encodeURIComponent(json[i]) );
  4205. }
  4206. }
  4207. return strArr.join("&");
  4208. }
  4209. /**
  4210. * 创建一个ajaxRequest对象
  4211. */
  4212. function creatAjaxRequest() {
  4213. var xmlHttp = null;
  4214. if (window.XMLHttpRequest) {
  4215. xmlHttp = new XMLHttpRequest();
  4216. } else {
  4217. try {
  4218. xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
  4219. } catch (e) {
  4220. try {
  4221. xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  4222. } catch (e) {
  4223. }
  4224. }
  4225. }
  4226. return xmlHttp;
  4227. }
  4228. }();
  4229. ///import core
  4230. /**
  4231. * @description 插入内容
  4232. * @name baidu.editor.execCommand
  4233. * @param {String} cmdName inserthtml插入内容的命令
  4234. * @param {String} html 要插入的内容
  4235. * @author zhanyi
  4236. */
  4237. UE.commands['inserthtml'] = {
  4238. execCommand: function (command,html,notSerialize){
  4239. var me = this,
  4240. range,
  4241. div,
  4242. tds = me.currentSelectedArr;
  4243. range = me.selection.getRange();
  4244. div = range.document.createElement( 'div' );
  4245. div.style.display = 'inline';
  4246. var serialize = me.serialize;
  4247. if (!notSerialize && serialize) {
  4248. var node = serialize.parseHTML(html);
  4249. node = serialize.transformInput(node);
  4250. node = serialize.filter(node);
  4251. html = serialize.toHTML(node);
  4252. }
  4253. div.innerHTML = utils.trim( html );
  4254. try{
  4255. me.adjustTable && me.adjustTable(div);
  4256. }catch(e){}
  4257. if(tds && tds.length){
  4258. for(var i=0,ti;ti=tds[i++];){
  4259. ti.className = '';
  4260. }
  4261. tds[0].innerHTML = '';
  4262. range.setStart(tds[0],0).collapse(true);
  4263. me.currentSelectedArr = [];
  4264. }
  4265. if ( !range.collapsed ) {
  4266. range.deleteContents();
  4267. if(range.startContainer.nodeType == 1){
  4268. var child = range.startContainer.childNodes[range.startOffset],pre;
  4269. if(child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)){
  4270. range.setEnd(pre,pre.childNodes.length).collapse();
  4271. while(child.firstChild){
  4272. pre.appendChild(child.firstChild);
  4273. }
  4274. domUtils.remove(child);
  4275. }
  4276. }
  4277. }
  4278. var child,parent,pre,tmp,hadBreak = 0;
  4279. while ( child = div.firstChild ) {
  4280. range.insertNode( child );
  4281. if ( !hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm( child ) ){
  4282. parent = domUtils.findParent( child,function ( node ){ return domUtils.isBlockElm( node ); } );
  4283. if ( parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)){
  4284. if(!dtd[parent.tagName][child.nodeName]){
  4285. pre = parent;
  4286. }else{
  4287. tmp = child.parentNode;
  4288. while (tmp !== parent){
  4289. pre = tmp;
  4290. tmp = tmp.parentNode;
  4291. }
  4292. }
  4293. domUtils.breakParent( child, pre || tmp );
  4294. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  4295. var pre = child.previousSibling;
  4296. domUtils.trimWhiteTextNode(pre);
  4297. if(!pre.childNodes.length){
  4298. domUtils.remove(pre);
  4299. }
  4300. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  4301. if(!browser.ie &&
  4302. (next = child.nextSibling) &&
  4303. domUtils.isBlockElm(next) &&
  4304. next.lastChild &&
  4305. !domUtils.isBr(next.lastChild)){
  4306. next.appendChild(me.document.createElement('br'));
  4307. }
  4308. hadBreak = 1;
  4309. }
  4310. }
  4311. var next = child.nextSibling;
  4312. if(!div.firstChild && next && domUtils.isBlockElm(next)){
  4313. range.setStart(next,0).collapse(true);
  4314. break;
  4315. }
  4316. range.setEndAfter( child ).collapse();
  4317. }
  4318. child = range.startContainer;
  4319. //用chrome可能有空白展位符
  4320. if(domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)){
  4321. child.innerHTML = browser.ie ? '' : '<br/>';
  4322. }
  4323. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  4324. range.select(true);
  4325. setTimeout(function(){
  4326. range = me.selection.getRange();
  4327. range.scrollToView(me.autoHeightEnabled,me.autoHeightEnabled ? domUtils.getXY(me.iframe).y:0);
  4328. },200);
  4329. }
  4330. };
  4331. ///import core
  4332. ///commands 自动排版
  4333. ///commandsName autotypeset
  4334. ///commandsTitle 自动排版
  4335. /**
  4336. * 自动排版
  4337. * @function
  4338. * @name baidu.editor.execCommands
  4339. */
  4340. UE.plugins['autotypeset'] = function(){
  4341. this.setOpt({'autotypeset':{
  4342. mergeEmptyline : true, //合并空行
  4343. removeClass : true, //去掉冗余的class
  4344. removeEmptyline : false, //去掉空行
  4345. textAlign : "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  4346. imageBlockLine : 'center', //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  4347. pasteFilter : false, //根据规则过滤没事粘贴进来的内容
  4348. clearFontSize : false, //去掉所有的内嵌字号,使用编辑器默认的字号
  4349. clearFontFamily : false, //去掉所有的内嵌字体,使用编辑器默认的字体
  4350. removeEmptyNode : false, // 去掉空节点
  4351. //可以去掉的标签
  4352. removeTagNames : utils.extend({div:1},dtd.$removeEmpty),
  4353. indent : false, // 行首缩进
  4354. indentValue : '2em' //行首缩进的大小
  4355. }});
  4356. var me = this,
  4357. opt = me.options.autotypeset,
  4358. remainClass = {
  4359. 'selectTdClass':1,
  4360. 'pagebreak':1,
  4361. 'anchorclass':1
  4362. },
  4363. remainTag = {
  4364. 'li':1
  4365. },
  4366. tags = {
  4367. div:1,
  4368. p:1,
  4369. //trace:2183 这些也认为是行
  4370. blockquote:1,center:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1
  4371. },
  4372. highlightCont;
  4373. //升级了版本,但配置项目里没有autotypeset
  4374. if(!opt){
  4375. return;
  4376. }
  4377. function isLine(node,notEmpty){
  4378. if(node && node.parentNode && tags[node.tagName.toLowerCase()]){
  4379. if(highlightCont && highlightCont.contains(node)
  4380. ||
  4381. node.getAttribute('pagebreak')
  4382. ){
  4383. return 0;
  4384. }
  4385. return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node);
  4386. }
  4387. }
  4388. function removeNotAttributeSpan(node){
  4389. if(!node.style.cssText){
  4390. domUtils.removeAttributes(node,['style']);
  4391. if(node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)){
  4392. domUtils.remove(node,true);
  4393. }
  4394. }
  4395. }
  4396. function autotype(type,html){
  4397. var cont;
  4398. if(html){
  4399. if(!opt.pasteFilter){
  4400. return;
  4401. }
  4402. cont = me.document.createElement('div');
  4403. cont.innerHTML = html.html;
  4404. }else{
  4405. cont = me.document.body;
  4406. }
  4407. var nodes = domUtils.getElementsByTagName(cont,'*');
  4408. // 行首缩进,段落方向,段间距,段内间距
  4409. for(var i=0,ci;ci=nodes[i++];){
  4410. if(!highlightCont && ci.tagName == 'DIV' && ci.getAttribute('highlighter')){
  4411. highlightCont = ci;
  4412. }
  4413. //font-size
  4414. if(opt.clearFontSize && ci.style.fontSize){
  4415. ci.style.fontSize = '';
  4416. removeNotAttributeSpan(ci);
  4417. }
  4418. //font-family
  4419. if(opt.clearFontFamily && ci.style.fontFamily){
  4420. ci.style.fontFamily = '';
  4421. removeNotAttributeSpan(ci);
  4422. }
  4423. if(isLine(ci)){
  4424. //合并空行
  4425. if(opt.mergeEmptyline ){
  4426. var next = ci.nextSibling,tmpNode;
  4427. while(isLine(next)){
  4428. tmpNode = next;
  4429. next = tmpNode.nextSibling;
  4430. domUtils.remove(tmpNode);
  4431. }
  4432. }
  4433. //去掉空行,保留占位的空行
  4434. if(opt.removeEmptyline && domUtils.inDoc(ci,cont) && !remainTag[ci.parentNode.tagName.toLowerCase()] ){
  4435. domUtils.remove(ci);
  4436. continue;
  4437. }
  4438. }
  4439. if(isLine(ci,true) ){
  4440. if(opt.indent){
  4441. ci.style.textIndent = opt.indentValue;
  4442. }
  4443. if(opt.textAlign){
  4444. ci.style.textAlign = opt.textAlign;
  4445. }
  4446. // if(opt.lineHeight)
  4447. // ci.style.lineHeight = opt.lineHeight + 'cm';
  4448. }
  4449. //去掉class,保留的class不去掉
  4450. if(opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]){
  4451. if(highlightCont && highlightCont.contains(ci)){
  4452. continue;
  4453. }
  4454. domUtils.removeAttributes(ci,['class']);
  4455. }
  4456. //表情不处理
  4457. if(opt.imageBlockLine && ci.tagName.toLowerCase() == 'img' && !ci.getAttribute('emotion')){
  4458. if(html){
  4459. var img = ci;
  4460. switch (opt.imageBlockLine){
  4461. case 'left':
  4462. case 'right':
  4463. case 'none':
  4464. var pN = img.parentNode,tmpNode,pre,next;
  4465. while(dtd.$inline[pN.tagName] || pN.tagName == 'A'){
  4466. pN = pN.parentNode;
  4467. }
  4468. tmpNode = pN;
  4469. if(tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode,'text-align') == 'center'){
  4470. if(!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode,function(node){return !domUtils.isBr(node) && !domUtils.isWhitespace(node)}) == 1){
  4471. pre = tmpNode.previousSibling;
  4472. next = tmpNode.nextSibling;
  4473. if(pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)){
  4474. pre.appendChild(tmpNode.firstChild);
  4475. while(next.firstChild){
  4476. pre.appendChild(next.firstChild);
  4477. }
  4478. domUtils.remove(tmpNode);
  4479. domUtils.remove(next);
  4480. }else{
  4481. domUtils.setStyle(tmpNode,'text-align','');
  4482. }
  4483. }
  4484. }
  4485. domUtils.setStyle(img,'float',opt.imageBlockLine);
  4486. break;
  4487. case 'center':
  4488. if(me.queryCommandValue('imagefloat') != 'center'){
  4489. pN = img.parentNode;
  4490. domUtils.setStyle(img,'float','none');
  4491. tmpNode = img;
  4492. while(pN && domUtils.getChildCount(pN,function(node){return !domUtils.isBr(node) && !domUtils.isWhitespace(node)}) == 1
  4493. && (dtd.$inline[pN.tagName] || pN.tagName == 'A')){
  4494. tmpNode = pN;
  4495. pN = pN.parentNode;
  4496. }
  4497. var pNode = me.document.createElement('p');
  4498. domUtils.setAttributes(pNode,{
  4499. style:'text-align:center'
  4500. });
  4501. tmpNode.parentNode.insertBefore(pNode,tmpNode);
  4502. pNode.appendChild(tmpNode);
  4503. domUtils.setStyle(tmpNode,'float','');
  4504. }
  4505. }
  4506. }else{
  4507. var range = me.selection.getRange();
  4508. range.selectNode(ci).select();
  4509. me.execCommand('imagefloat',opt.imageBlockLine);
  4510. }
  4511. }
  4512. //去掉冗余的标签
  4513. if(opt.removeEmptyNode){
  4514. if(opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils.isEmptyBlock(ci)){
  4515. domUtils.remove(ci);
  4516. }
  4517. }
  4518. }
  4519. if(html){
  4520. html.html = cont.innerHTML;
  4521. }
  4522. }
  4523. if(opt.pasteFilter){
  4524. me.addListener('beforepaste',autotype);
  4525. }
  4526. me.commands['autotypeset'] = {
  4527. execCommand:function () {
  4528. me.removeListener('beforepaste',autotype);
  4529. if(opt.pasteFilter){
  4530. me.addListener('beforepaste',autotype);
  4531. }
  4532. autotype();
  4533. }
  4534. };
  4535. };
  4536. UE.commands['autosubmit'] = {
  4537. execCommand:function () {
  4538. var me=this,
  4539. form = domUtils.findParentByTagName(me.iframe,"form", false);
  4540. if (form) {
  4541. if(me.fireEvent("beforesubmit")===false){
  4542. return;
  4543. }
  4544. me.sync();
  4545. form.submit();
  4546. }
  4547. }
  4548. };
  4549. (function() {
  4550. UE.plugins['background'] = function(){
  4551. var me = this;
  4552. UE.commands['background'] = {
  4553. queryCommandState : function(){
  4554. return this.highlight ? -1 : 0;
  4555. }
  4556. };
  4557. me.addListener("getAllHtml",function(type,headHtml){
  4558. var body = this.body,
  4559. su = domUtils.getComputedStyle(body,"background-image"),
  4560. url="";
  4561. if(su.indexOf(me.options.imagePath)>0){
  4562. url = su.substring(su.indexOf(me.options.imagePath),su.length-1).replace(/"|\(|\)/ig,"");
  4563. }else{
  4564. url = su!="none" ? su.replace(/url\("?|"?\)/ig,""):"";
  4565. }
  4566. headHtml.html = '<style type="text/css">body{';
  4567. var bgObj = {
  4568. "background-color" : domUtils.getComputedStyle(body,"background-color")||"#ffffff",
  4569. 'background-image' : url ? 'url('+url+')' : '',
  4570. 'background-repeat':domUtils.getComputedStyle(body,"background-repeat")||"",
  4571. 'background-position': browser.ie?(domUtils.getComputedStyle(body,"background-position-x")+" "+domUtils.getComputedStyle(body,"background-position-y")):domUtils.getComputedStyle(body,"background-position"),
  4572. 'height':domUtils.getComputedStyle(body,"height")
  4573. };
  4574. for ( var name in bgObj ) {
  4575. if ( bgObj.hasOwnProperty( name ) ) {
  4576. headHtml.html += name+":"+bgObj[name]+";";
  4577. }
  4578. }
  4579. headHtml.html += '}</style> ';
  4580. });
  4581. }
  4582. })();
  4583. ///import core
  4584. ///import plugins\inserthtml.js
  4585. ///import plugins\catchremoteimage.js
  4586. ///commands 插入图片,操作图片的对齐方式
  4587. ///commandsName InsertImage,ImageNone,ImageLeft,ImageRight,ImageCenter
  4588. ///commandsTitle 图片,默认,居左,居右,居中
  4589. ///commandsDialog dialogs\image\image.html
  4590. /**
  4591. * Created by .
  4592. * User: zhanyi
  4593. * for image
  4594. */
  4595. UE.commands['imagefloat'] = {
  4596. execCommand:function ( cmd, align ) {
  4597. var me = this,
  4598. range = me.selection.getRange();
  4599. if ( !range.collapsed ) {
  4600. var img = range.getClosedNode();
  4601. if ( img && img.tagName == 'IMG' ) {
  4602. switch ( align ) {
  4603. case 'left':
  4604. case 'right':
  4605. case 'none':
  4606. var pN = img.parentNode, tmpNode, pre, next;
  4607. while ( dtd.$inline[pN.tagName] || pN.tagName == 'A' ) {
  4608. pN = pN.parentNode;
  4609. }
  4610. tmpNode = pN;
  4611. if ( tmpNode.tagName == 'P' && domUtils.getStyle( tmpNode, 'text-align' ) == 'center' ) {
  4612. if ( !domUtils.isBody( tmpNode ) && domUtils.getChildCount( tmpNode, function ( node ) {
  4613. return !domUtils.isBr( node ) && !domUtils.isWhitespace( node );
  4614. } ) == 1 ) {
  4615. pre = tmpNode.previousSibling;
  4616. next = tmpNode.nextSibling;
  4617. if ( pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm( pre ) ) {
  4618. pre.appendChild( tmpNode.firstChild );
  4619. while ( next.firstChild ) {
  4620. pre.appendChild( next.firstChild );
  4621. }
  4622. domUtils.remove( tmpNode );
  4623. domUtils.remove( next );
  4624. } else {
  4625. domUtils.setStyle( tmpNode, 'text-align', '' );
  4626. }
  4627. }
  4628. range.selectNode( img ).select();
  4629. }
  4630. domUtils.setStyle( img, 'float', align );
  4631. break;
  4632. case 'center':
  4633. if ( me.queryCommandValue( 'imagefloat' ) != 'center' ) {
  4634. pN = img.parentNode;
  4635. domUtils.setStyle( img, 'float', 'none' );
  4636. tmpNode = img;
  4637. while ( pN && domUtils.getChildCount( pN, function ( node ) {
  4638. return !domUtils.isBr( node ) && !domUtils.isWhitespace( node );
  4639. } ) == 1
  4640. && (dtd.$inline[pN.tagName] || pN.tagName == 'A') ) {
  4641. tmpNode = pN;
  4642. pN = pN.parentNode;
  4643. }
  4644. range.setStartBefore( tmpNode ).setCursor( false );
  4645. pN = me.document.createElement( 'div' );
  4646. pN.appendChild( tmpNode );
  4647. domUtils.setStyle( tmpNode, 'float', '' );
  4648. me.execCommand( 'insertHtml', '<p id="_img_parent_tmp" style="text-align:center">' + pN.innerHTML + '</p>' );
  4649. tmpNode = me.document.getElementById( '_img_parent_tmp' );
  4650. tmpNode.removeAttribute( 'id' );
  4651. tmpNode = tmpNode.firstChild;
  4652. range.selectNode( tmpNode ).select();
  4653. //去掉后边多余的元素
  4654. next = tmpNode.parentNode.nextSibling;
  4655. if ( next && domUtils.isEmptyNode( next ) ) {
  4656. domUtils.remove( next );
  4657. }
  4658. }
  4659. break;
  4660. }
  4661. }
  4662. }
  4663. },
  4664. queryCommandValue:function () {
  4665. var range = this.selection.getRange(),
  4666. startNode, floatStyle;
  4667. if ( range.collapsed ) {
  4668. return 'none';
  4669. }
  4670. startNode = range.getClosedNode();
  4671. if ( startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG' ) {
  4672. floatStyle = domUtils.getComputedStyle( startNode, 'float' );
  4673. if ( floatStyle == 'none' ) {
  4674. floatStyle = domUtils.getComputedStyle( startNode.parentNode, 'text-align' ) == 'center' ? 'center' : floatStyle;
  4675. }
  4676. return {
  4677. left:1,
  4678. right:1,
  4679. center:1
  4680. }[floatStyle] ? floatStyle : 'none';
  4681. }
  4682. return 'none';
  4683. },
  4684. queryCommandState:function () {
  4685. if ( this.highlight ) {
  4686. return -1;
  4687. }
  4688. var range = this.selection.getRange(),
  4689. startNode;
  4690. if ( range.collapsed ) {
  4691. return -1;
  4692. }
  4693. startNode = range.getClosedNode();
  4694. if ( startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG' ) {
  4695. return 0;
  4696. }
  4697. return -1;
  4698. }
  4699. };
  4700. UE.commands['insertimage'] = {
  4701. execCommand:function ( cmd, opt ) {
  4702. opt = utils.isArray( opt ) ? opt : [opt];
  4703. if ( !opt.length ) {
  4704. return;
  4705. }
  4706. var me = this,
  4707. range = me.selection.getRange(),
  4708. img = range.getClosedNode();
  4709. if ( img && /img/i.test( img.tagName ) && img.className != "edui-faked-video" && !img.getAttribute( "word_img" ) ) {
  4710. var first = opt.shift();
  4711. var floatStyle = first['floatStyle'];
  4712. delete first['floatStyle'];
  4713. //// img.style.border = (first.border||0) +"px solid #000";
  4714. //// img.style.margin = (first.margin||0) +"px";
  4715. // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
  4716. domUtils.setAttributes( img, first );
  4717. me.execCommand( 'imagefloat', floatStyle );
  4718. if ( opt.length > 0 ) {
  4719. range.setStartAfter( img ).setCursor( false, true );
  4720. me.execCommand( 'insertimage', opt );
  4721. }
  4722. } else {
  4723. var html = [], str = '', ci;
  4724. ci = opt[0];
  4725. if ( opt.length == 1 ) {
  4726. str = '<img src="' + ci.src + '" ' + (ci.data_ue_src ? ' data_ue_src="' + ci.data_ue_src + '" ' : '') +
  4727. (ci.width ? 'width="' + ci.width + '" ' : '') +
  4728. (ci.height ? ' height="' + ci.height + '" ' : '') +
  4729. (ci['floatStyle'] == 'left' || ci['floatStyle'] == 'right' ? ' style="float:' + ci['floatStyle'] + ';"' : '') +
  4730. (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : '') +
  4731. (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : '') +
  4732. (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : '') +
  4733. (ci.hspace && ci.hspace != "0" ? ' hspace = "' + ci.hspace + '"' : '') +
  4734. (ci.vspace && ci.vspace != "0" ? ' vspace = "' + ci.vspace + '"' : '') + '/>';
  4735. if ( ci['floatStyle'] == 'center' ) {
  4736. str = '<p style="text-align: center">' + str + '</p>';
  4737. }
  4738. html.push( str );
  4739. } else {
  4740. for ( var i = 0; ci = opt[i++]; ) {
  4741. str = '<p ' + (ci['floatStyle'] == 'center' ? 'style="text-align: center" ' : '') + '><img src="' + ci.src + '" ' +
  4742. (ci.width ? 'width="' + ci.width + '" ' : '') + (ci.data_ue_src ? ' data_ue_src="' + ci.data_ue_src + '" ' : '') +
  4743. (ci.height ? ' height="' + ci.height + '" ' : '') +
  4744. ' style="' + (ci['floatStyle'] && ci['floatStyle'] != 'center' ? 'float:' + ci['floatStyle'] + ';' : '') +
  4745. (ci.border || '') + '" ' +
  4746. (ci.title ? ' title="' + ci.title + '"' : '') + ' /></p>';
  4747. html.push( str );
  4748. }
  4749. }
  4750. me.execCommand( 'insertHtml', html.join( '' ) );
  4751. }
  4752. },
  4753. queryCommandState:function () {
  4754. return this.highlight ? -1 : 0;
  4755. }
  4756. };
  4757. ///import core
  4758. ///commands 段落格式,居左,居右,居中,两端对齐
  4759. ///commandsName JustifyLeft,JustifyCenter,JustifyRight,JustifyJustify
  4760. ///commandsTitle 居左对齐,居中对齐,居右对齐,两端对齐
  4761. /**
  4762. * @description 居左右中
  4763. * @name baidu.editor.execCommand
  4764. * @param {String} cmdName justify执行对齐方式的命令
  4765. * @param {String} align 对齐方式:left居左,right居右,center居中,justify两端对齐
  4766. * @author zhanyi
  4767. */
  4768. (function(){
  4769. var block = domUtils.isBlockElm,
  4770. defaultValue = {
  4771. left : 1,
  4772. right : 1,
  4773. center : 1,
  4774. justify : 1
  4775. },
  4776. doJustify = function(range,style){
  4777. var bookmark = range.createBookmark(),
  4778. filterFn = function( node ) {
  4779. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace( node );
  4780. };
  4781. range.enlarge(true);
  4782. var bookmark2 = range.createBookmark(),
  4783. current = domUtils.getNextDomNode(bookmark2.start,false,filterFn),
  4784. tmpRange = range.cloneRange(),
  4785. tmpNode;
  4786. while(current && !(domUtils.getPosition(current,bookmark2.end)&domUtils.POSITION_FOLLOWING)){
  4787. if(current.nodeType == 3 || !block(current)){
  4788. tmpRange.setStartBefore(current);
  4789. while(current && current!==bookmark2.end && !block(current)){
  4790. tmpNode = current;
  4791. current = domUtils.getNextDomNode(current,false,null,function(node){
  4792. return !block(node);
  4793. });
  4794. }
  4795. tmpRange.setEndAfter(tmpNode);
  4796. var common = tmpRange.getCommonAncestor();
  4797. if( !domUtils.isBody(common) && block(common)){
  4798. domUtils.setStyles(common,utils.isString(style) ? {'text-align':style} : style);
  4799. current = common;
  4800. }else{
  4801. var p = range.document.createElement('p');
  4802. domUtils.setStyles(p,utils.isString(style) ? {'text-align':style} : style);
  4803. var frag = tmpRange.extractContents();
  4804. p.appendChild(frag);
  4805. tmpRange.insertNode(p);
  4806. current = p;
  4807. }
  4808. current = domUtils.getNextDomNode(current,false,filterFn);
  4809. }else{
  4810. current = domUtils.getNextDomNode(current,true,filterFn);
  4811. }
  4812. }
  4813. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  4814. };
  4815. UE.commands['justify'] = {
  4816. execCommand : function( cmdName,align ) {
  4817. var range = this.selection.getRange(),
  4818. txt;
  4819. if(this.currentSelectedArr && this.currentSelectedArr.length > 0){
  4820. for(var i=0,ti;ti=this.currentSelectedArr[i++];){
  4821. if(domUtils.isEmptyNode(ti)){
  4822. txt = this.document.createTextNode('p');
  4823. range.setStart(ti,0).collapse(true).insertNode(txt).selectNode(txt);
  4824. }else{
  4825. range.selectNodeContents(ti);
  4826. }
  4827. doJustify(range,align.toLowerCase());
  4828. txt && domUtils.remove(txt);
  4829. }
  4830. range.selectNode(this.currentSelectedArr[0]).select();
  4831. }else{
  4832. //闭合时单独处理
  4833. if(range.collapsed){
  4834. txt = this.document.createTextNode('p');
  4835. range.insertNode(txt);
  4836. }
  4837. doJustify(range,align);
  4838. if(txt){
  4839. range.setStartBefore(txt).collapse(true);
  4840. domUtils.remove(txt);
  4841. }
  4842. range.select();
  4843. }
  4844. return true;
  4845. },
  4846. queryCommandValue : function() {
  4847. var startNode = this.selection.getStart(),
  4848. value = domUtils.getComputedStyle(startNode,'text-align');
  4849. return defaultValue[value] ? value : 'left';
  4850. },
  4851. queryCommandState : function(){
  4852. return this.highlight ? -1 : 0;
  4853. }
  4854. };
  4855. })();
  4856. ///import core
  4857. ///import plugins\removeformat.js
  4858. ///commands 字体颜色,背景色,字号,字体,下划线,删除线
  4859. ///commandsName ForeColor,BackColor,FontSize,FontFamily,Underline,StrikeThrough
  4860. ///commandsTitle 字体颜色,背景色,字号,字体,下划线,删除线
  4861. /**
  4862. * @description 字体
  4863. * @name baidu.editor.execCommand
  4864. * @param {String} cmdName 执行的功能名称
  4865. * @param {String} value 传入的值
  4866. */
  4867. UE.plugins['font'] = function() {
  4868. var me = this,
  4869. fonts = {
  4870. 'forecolor':'color',
  4871. 'backcolor':'background-color',
  4872. 'fontsize':'font-size',
  4873. 'fontfamily':'font-family',
  4874. 'underline':'text-decoration',
  4875. 'strikethrough':'text-decoration'
  4876. };
  4877. me.setOpt({
  4878. 'fontfamily':[
  4879. { name:'songti',val:'宋体,SimSun'},
  4880. { name:'yahei',val:'微软雅黑,Microsoft YaHei'},
  4881. { name:'kaiti',val:'楷体,楷体_GB2312, SimKai'},
  4882. { name:'heiti',val:'黑体, SimHei'},
  4883. { name:'lishu',val:'隶书, SimLi'},
  4884. { name:'andaleMono',val:'andale mono'},
  4885. { name:'arial',val:'arial, helvetica,sans-serif'},
  4886. { name:'arialBlack',val:'arial black,avant garde'},
  4887. { name:'comicSansMs',val:'comic sans ms'},
  4888. { name:'impact',val:'impact,chicago'},
  4889. { name:'timesNewRoman',val:'times new roman'}
  4890. ],
  4891. 'fontsize':[10, 11, 12, 14, 16, 18, 20, 24, 36]
  4892. });
  4893. for ( var p in fonts ) {
  4894. (function( cmd, style ) {
  4895. UE.commands[cmd] = {
  4896. execCommand : function( cmdName, value ) {
  4897. value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' : 'line-through');
  4898. var me = this,
  4899. range = this.selection.getRange(),
  4900. text;
  4901. if ( value == 'default' ) {
  4902. if(range.collapsed){
  4903. text = me.document.createTextNode('font');
  4904. range.insertNode(text).select();
  4905. }
  4906. me.execCommand( 'removeFormat', 'span,a', style);
  4907. if(text){
  4908. range.setStartBefore(text).setCursor();
  4909. domUtils.remove(text);
  4910. }
  4911. } else {
  4912. if(me.currentSelectedArr && me.currentSelectedArr.length > 0){
  4913. for(var i=0,ci;ci=me.currentSelectedArr[i++];){
  4914. range.selectNodeContents(ci);
  4915. range.applyInlineStyle( 'span', {'style':style + ':' + value} );
  4916. }
  4917. range.selectNodeContents(this.currentSelectedArr[0]).select();
  4918. }else{
  4919. if ( !range.collapsed ) {
  4920. if((cmd == 'underline'||cmd=='strikethrough') && me.queryCommandValue(cmd)){
  4921. me.execCommand( 'removeFormat', 'span,a', style );
  4922. }
  4923. range = me.selection.getRange();
  4924. range.applyInlineStyle( 'span', {'style':style + ':' + value} ).select();
  4925. } else {
  4926. var span = domUtils.findParentByTagName(range.startContainer,'span',true);
  4927. text = me.document.createTextNode('font');
  4928. if(span && !span.children.length && !span[browser.ie ? 'innerText':'textContent'].replace(fillCharReg,'').length){
  4929. //for ie hack when enter
  4930. range.insertNode(text);
  4931. if(cmd == 'underline'||cmd=='strikethrough'){
  4932. range.selectNode(text).select();
  4933. me.execCommand( 'removeFormat','span,a', style, null );
  4934. span = domUtils.findParentByTagName(text,'span',true);
  4935. range.setStartBefore(text);
  4936. }
  4937. span.style.cssText += ';' + style + ':' + value;
  4938. range.collapse(true).select();
  4939. }else{
  4940. range.insertNode(text);
  4941. range.selectNode(text).select();
  4942. span = range.document.createElement( 'span' );
  4943. if(cmd == 'underline'||cmd=='strikethrough'){
  4944. //a标签内的不处理跳过
  4945. if(domUtils.findParentByTagName(text,'a',true)){
  4946. range.setStartBefore(text).setCursor();
  4947. domUtils.remove(text);
  4948. return;
  4949. }
  4950. me.execCommand( 'removeFormat','span,a', style );
  4951. }
  4952. span.style.cssText = style + ':' + value;
  4953. text.parentNode.insertBefore(span,text);
  4954. //修复,span套span 但样式不继承的问题
  4955. if(!browser.ie || browser.ie && browser.version == 9){
  4956. var spanParent = span.parentNode;
  4957. while(!domUtils.isBlockElm(spanParent)){
  4958. if(spanParent.tagName == 'SPAN'){
  4959. //opera合并style不会加入";"
  4960. span.style.cssText = spanParent.style.cssText + ";" + span.style.cssText;
  4961. }
  4962. spanParent = spanParent.parentNode;
  4963. }
  4964. }
  4965. if(opera){
  4966. setTimeout(function(){
  4967. range.setStart(span,0).setCursor();
  4968. });
  4969. }else{
  4970. range.setStart(span,0).setCursor();
  4971. }
  4972. //trace:981
  4973. //domUtils.mergToParent(span)
  4974. }
  4975. domUtils.remove(text);
  4976. }
  4977. }
  4978. }
  4979. return true;
  4980. },
  4981. queryCommandValue : function (cmdName) {
  4982. var startNode = this.selection.getStart();
  4983. //trace:946
  4984. if(cmdName == 'underline'||cmdName=='strikethrough' ){
  4985. var tmpNode = startNode,value;
  4986. while(tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)){
  4987. if(tmpNode.nodeType == 1){
  4988. value = domUtils.getComputedStyle( tmpNode, style );
  4989. if(value != 'none'){
  4990. return value;
  4991. }
  4992. }
  4993. tmpNode = tmpNode.parentNode;
  4994. }
  4995. return 'none';
  4996. }
  4997. return domUtils.getComputedStyle( startNode, style );
  4998. },
  4999. queryCommandState : function(cmdName){
  5000. if(this.highlight){
  5001. return -1;
  5002. }
  5003. if(!(cmdName == 'underline'||cmdName=='strikethrough')){
  5004. return 0;
  5005. }
  5006. return this.queryCommandValue(cmdName) == (cmdName == 'underline' ? 'underline' : 'line-through');
  5007. }
  5008. };
  5009. })( p, fonts[p] );
  5010. }
  5011. };
  5012. ///import core
  5013. ///commands 超链接,取消链接
  5014. ///commandsName Link,Unlink
  5015. ///commandsTitle 超链接,取消链接
  5016. ///commandsDialog dialogs\link\link.html
  5017. /**
  5018. * 超链接
  5019. * @function
  5020. * @name baidu.editor.execCommand
  5021. * @param {String} cmdName link插入超链接
  5022. * @param {Object} options url地址,title标题,target是否打开新页
  5023. * @author zhanyi
  5024. */
  5025. /**
  5026. * 取消链接
  5027. * @function
  5028. * @name baidu.editor.execCommand
  5029. * @param {String} cmdName unlink取消链接
  5030. * @author zhanyi
  5031. */
  5032. (function() {
  5033. function optimize( range ) {
  5034. var start = range.startContainer,end = range.endContainer;
  5035. if ( start = domUtils.findParentByTagName( start, 'a', true ) ) {
  5036. range.setStartBefore( start );
  5037. }
  5038. if ( end = domUtils.findParentByTagName( end, 'a', true ) ) {
  5039. range.setEndAfter( end );
  5040. }
  5041. }
  5042. UE.commands['unlink'] = {
  5043. execCommand : function() {
  5044. var as,
  5045. range = new dom.Range(this.document),
  5046. tds = this.currentSelectedArr,
  5047. bookmark;
  5048. if(tds && tds.length >0){
  5049. for(var i=0,ti;ti=tds[i++];){
  5050. as = domUtils.getElementsByTagName(ti,'a');
  5051. for(var j=0,aj;aj=as[j++];){
  5052. domUtils.remove(aj,true);
  5053. }
  5054. }
  5055. if(domUtils.isEmptyNode(tds[0])){
  5056. range.setStart(tds[0],0).setCursor();
  5057. }else{
  5058. range.selectNodeContents(tds[0]).select();
  5059. }
  5060. }else{
  5061. range = this.selection.getRange();
  5062. if(range.collapsed && !domUtils.findParentByTagName( range.startContainer, 'a', true )){
  5063. return;
  5064. }
  5065. bookmark = range.createBookmark();
  5066. optimize( range );
  5067. range.removeInlineStyle( 'a' ).moveToBookmark( bookmark ).select();
  5068. }
  5069. },
  5070. queryCommandState : function(){
  5071. return !this.highlight && this.queryCommandValue('link') ? 0 : -1;
  5072. }
  5073. };
  5074. function doLink(range,opt){
  5075. optimize( range = range.adjustmentBoundary() );
  5076. var start = range.startContainer;
  5077. if(start.nodeType == 1){
  5078. start = start.childNodes[range.startOffset];
  5079. if(start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie?'innerText':'textContent'])){
  5080. start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue||opt.href);
  5081. }
  5082. }
  5083. range.removeInlineStyle( 'a' );
  5084. if ( range.collapsed ) {
  5085. var a = range.document.createElement( 'a'),
  5086. text = '';
  5087. if(opt.textValue){
  5088. text = utils.html(opt.textValue);
  5089. delete opt.textValue;
  5090. }else{
  5091. text = utils.html(opt.href);
  5092. }
  5093. domUtils.setAttributes( a, opt );
  5094. range.insertNode( a );
  5095. a[browser.ie ? 'innerText' : 'textContent'] = text;
  5096. range.selectNode( a );
  5097. } else {
  5098. range.applyInlineStyle( 'a', opt );
  5099. }
  5100. }
  5101. UE.commands['link'] = {
  5102. queryCommandState : function(){
  5103. return this.highlight ? -1 :0;
  5104. },
  5105. execCommand : function( cmdName, opt ) {
  5106. var range = new dom.Range(this.document),
  5107. tds = this.currentSelectedArr;
  5108. opt.data_ue_src && (opt.data_ue_src = utils.unhtml(opt.data_ue_src,/[<">]/g));
  5109. opt.href && (opt.href = utils.unhtml(opt.href,/[<">]/g));
  5110. opt.textValue && (opt.textValue = utils.unhtml(opt.textValue,/[<">]/g));
  5111. if(tds && tds.length){
  5112. for(var i=0,ti;ti=tds[i++];){
  5113. if(domUtils.isEmptyNode(ti)){
  5114. ti[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue || opt.href);
  5115. }
  5116. doLink(range.selectNodeContents(ti),opt);
  5117. }
  5118. range.selectNodeContents(tds[0]).select();
  5119. }else{
  5120. doLink(range=this.selection.getRange(),opt);
  5121. //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
  5122. range.collapse().select(true);
  5123. }
  5124. },
  5125. queryCommandValue : function() {
  5126. var range = new dom.Range(this.document),
  5127. tds = this.currentSelectedArr,
  5128. as,
  5129. node;
  5130. if(tds && tds.length){
  5131. for(var i=0,ti;ti=tds[i++];){
  5132. as = ti.getElementsByTagName('a');
  5133. if(as[0]){
  5134. return as[0];
  5135. }
  5136. }
  5137. }else{
  5138. range = this.selection.getRange();
  5139. if ( range.collapsed ) {
  5140. node = this.selection.getStart();
  5141. if ( node && (node = domUtils.findParentByTagName( node, 'a', true )) ) {
  5142. return node;
  5143. }
  5144. } else {
  5145. //trace:1111 如果是<p><a>xx</a></p> startContainer是p就会找不到a
  5146. range.shrinkBoundary();
  5147. var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset],
  5148. end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset-1],
  5149. common = range.getCommonAncestor();
  5150. node = domUtils.findParentByTagName( common, 'a', true );
  5151. if ( !node && common.nodeType == 1){
  5152. var as = common.getElementsByTagName( 'a' ),
  5153. ps,pe;
  5154. for ( var i = 0,ci; ci = as[i++]; ) {
  5155. ps = domUtils.getPosition( ci, start ),pe = domUtils.getPosition( ci,end);
  5156. if ( (ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS)
  5157. &&
  5158. (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
  5159. ) {
  5160. node = ci;
  5161. break;
  5162. }
  5163. }
  5164. }
  5165. return node;
  5166. }
  5167. }
  5168. }
  5169. };
  5170. })();
  5171. ///import core
  5172. ///import plugins\inserthtml.js
  5173. ///commands 地图
  5174. ///commandsName Map,GMap
  5175. ///commandsTitle Baidu地图,Google地图
  5176. ///commandsDialog dialogs\map\map.html,dialogs\gmap\gmap.html
  5177. UE.commands['gmap'] =
  5178. UE.commands['map'] = {
  5179. queryCommandState : function(){
  5180. return this.highlight ? -1 :0;
  5181. }
  5182. };
  5183. ///import core
  5184. ///import plugins\inserthtml.js
  5185. ///commands 插入框架
  5186. ///commandsName InsertFrame
  5187. ///commandsTitle 插入Iframe
  5188. ///commandsDialog dialogs\insertframe\insertframe.html
  5189. UE.plugins['insertframe'] = function() {
  5190. var me =this;
  5191. function deleteIframe(){
  5192. me._iframe && delete me._iframe;
  5193. }
  5194. me.addListener("selectionchange",function(){
  5195. deleteIframe();
  5196. });
  5197. me.commands["insertframe"] = {
  5198. queryCommandState : function(){
  5199. return this.highlight ? -1 :0;
  5200. }
  5201. };
  5202. };
  5203. /**
  5204. * Created with JetBrains PhpStorm.
  5205. * User: xuheng
  5206. * Date: 12-7-2
  5207. * Time: 下午5:22
  5208. * To change this template use File | Settings | File Templates.
  5209. */
  5210. UE.commands['scrawl'] = {
  5211. queryCommandState : function(){
  5212. return this.highlight|| ( browser.ie && browser.version <= 8 ) ? -1 :0;
  5213. }
  5214. };
  5215. ///import core
  5216. ///commands 清除格式
  5217. ///commandsName RemoveFormat
  5218. ///commandsTitle 清除格式
  5219. /**
  5220. * @description 清除格式
  5221. * @name baidu.editor.execCommand
  5222. * @param {String} cmdName removeformat清除格式命令
  5223. * @param {String} tags 以逗号隔开的标签。如:span,a
  5224. * @param {String} style 样式
  5225. * @param {String} attrs 属性
  5226. * @param {String} notIncluedA 是否把a标签切开
  5227. * @author zhanyi
  5228. */
  5229. UE.plugins['removeformat'] = function(){
  5230. var me = this;
  5231. me.setOpt({
  5232. 'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var',
  5233. 'removeFormatAttributes':'class,style,lang,width,height,align,hspace,valign'
  5234. });
  5235. me.commands['removeformat'] = {
  5236. execCommand : function( cmdName, tags, style, attrs,notIncludeA ) {
  5237. var tagReg = new RegExp( '^(?:' + (tags || this.options.removeFormatTags).replace( /,/g, '|' ) + ')$', 'i' ) ,
  5238. removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split( ',' ),
  5239. range = new dom.Range( this.document ),
  5240. bookmark,node,parent,
  5241. filter = function( node ) {
  5242. return node.nodeType == 1;
  5243. };
  5244. function isRedundantSpan (node) {
  5245. if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span'){
  5246. return 0;
  5247. }
  5248. if (browser.ie) {
  5249. //ie 下判断实效,所以只能简单用style来判断
  5250. //return node.style.cssText == '' ? 1 : 0;
  5251. var attrs = node.attributes;
  5252. if ( attrs.length ) {
  5253. for ( var i = 0,l = attrs.length; i<l; i++ ) {
  5254. if ( attrs[i].specified ) {
  5255. return 0;
  5256. }
  5257. }
  5258. return 1;
  5259. }
  5260. }
  5261. return !node.attributes.length;
  5262. }
  5263. function doRemove( range ) {
  5264. var bookmark1 = range.createBookmark();
  5265. if ( range.collapsed ) {
  5266. range.enlarge( true );
  5267. }
  5268. //不能把a标签切了
  5269. if(!notIncludeA){
  5270. var aNode = domUtils.findParentByTagName(range.startContainer,'a',true);
  5271. if(aNode){
  5272. range.setStartBefore(aNode);
  5273. }
  5274. aNode = domUtils.findParentByTagName(range.endContainer,'a',true);
  5275. if(aNode){
  5276. range.setEndAfter(aNode);
  5277. }
  5278. }
  5279. bookmark = range.createBookmark();
  5280. node = bookmark.start;
  5281. //切开始
  5282. while ( (parent = node.parentNode) && !domUtils.isBlockElm( parent ) ) {
  5283. domUtils.breakParent( node, parent );
  5284. domUtils.clearEmptySibling( node );
  5285. }
  5286. if ( bookmark.end ) {
  5287. //切结束
  5288. node = bookmark.end;
  5289. while ( (parent = node.parentNode) && !domUtils.isBlockElm( parent ) ) {
  5290. domUtils.breakParent( node, parent );
  5291. domUtils.clearEmptySibling( node );
  5292. }
  5293. //开始去除样式
  5294. var current = domUtils.getNextDomNode( bookmark.start, false, filter ),
  5295. next;
  5296. while ( current ) {
  5297. if ( current == bookmark.end ) {
  5298. break;
  5299. }
  5300. next = domUtils.getNextDomNode( current, true, filter );
  5301. if ( !dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode( current ) ) {
  5302. if ( tagReg.test( current.tagName ) ) {
  5303. if ( style ) {
  5304. domUtils.removeStyle( current, style );
  5305. if ( isRedundantSpan( current ) && style != 'text-decoration'){
  5306. domUtils.remove( current, true );
  5307. }
  5308. } else {
  5309. domUtils.remove( current, true );
  5310. }
  5311. } else {
  5312. //trace:939 不能把list上的样式去掉
  5313. if(!dtd.$tableContent[current.tagName] && !dtd.$list[current.tagName]){
  5314. domUtils.removeAttributes( current, removeFormatAttributes );
  5315. if ( isRedundantSpan( current ) ){
  5316. domUtils.remove( current, true );
  5317. }
  5318. }
  5319. }
  5320. }
  5321. current = next;
  5322. }
  5323. }
  5324. //trace:1035
  5325. //trace:1096 不能把td上的样式去掉,比如边框
  5326. var pN = bookmark.start.parentNode;
  5327. if(domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]){
  5328. domUtils.removeAttributes( pN,removeFormatAttributes );
  5329. }
  5330. pN = bookmark.end.parentNode;
  5331. if(bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName]&& !dtd.$list[pN.tagName]){
  5332. domUtils.removeAttributes( pN,removeFormatAttributes );
  5333. }
  5334. range.moveToBookmark( bookmark ).moveToBookmark(bookmark1);
  5335. //清除冗余的代码 <b><bookmark></b>
  5336. var node = range.startContainer,
  5337. tmp,
  5338. collapsed = range.collapsed;
  5339. while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]){
  5340. tmp = node.parentNode;
  5341. range.setStartBefore(node);
  5342. //trace:937
  5343. //更新结束边界
  5344. if(range.startContainer === range.endContainer){
  5345. range.endOffset--;
  5346. }
  5347. domUtils.remove(node);
  5348. node = tmp;
  5349. }
  5350. if(!collapsed){
  5351. node = range.endContainer;
  5352. while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]){
  5353. tmp = node.parentNode;
  5354. range.setEndBefore(node);
  5355. domUtils.remove(node);
  5356. node = tmp;
  5357. }
  5358. }
  5359. }
  5360. if ( this.currentSelectedArr && this.currentSelectedArr.length ) {
  5361. for ( var i = 0,ci; ci = this.currentSelectedArr[i++]; ) {
  5362. range.selectNodeContents( ci );
  5363. doRemove( range );
  5364. }
  5365. range.selectNodeContents( this.currentSelectedArr[0] ).select();
  5366. } else {
  5367. range = this.selection.getRange();
  5368. doRemove( range );
  5369. range.select();
  5370. }
  5371. },
  5372. queryCommandState : function(){
  5373. return this.highlight ? -1 :0;
  5374. }
  5375. };
  5376. };
  5377. ///import core
  5378. ///commands 引用
  5379. ///commandsName BlockQuote
  5380. ///commandsTitle 引用
  5381. /**
  5382. *
  5383. * 引用模块实现
  5384. * @function
  5385. * @name baidu.editor.execCommand
  5386. * @param {String} cmdName blockquote引用
  5387. */
  5388. (function() {
  5389. var getObj = function(editor){
  5390. // var startNode = editor.selection.getStart();
  5391. // return domUtils.findParentByTagName( startNode, 'blockquote', true )
  5392. return utils.findNode(editor.selection.getStartElementPath(),['blockquote']);
  5393. };
  5394. UE.commands['blockquote'] = {
  5395. execCommand : function( cmdName, attrs ) {
  5396. var range = this.selection.getRange(),
  5397. obj = getObj(this),
  5398. blockquote = dtd.blockquote,
  5399. bookmark = range.createBookmark(),
  5400. tds = this.currentSelectedArr;
  5401. if ( obj ) {
  5402. if(tds && tds.length){
  5403. domUtils.remove(obj,true);
  5404. }else{
  5405. var start = range.startContainer,
  5406. startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start,function(node){return domUtils.isBlockElm(node)}),
  5407. end = range.endContainer,
  5408. endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end,function(node){return domUtils.isBlockElm(node)});
  5409. //处理一下li
  5410. startBlock = domUtils.findParentByTagName(startBlock,'li',true) || startBlock;
  5411. endBlock = domUtils.findParentByTagName(endBlock,'li',true) || endBlock;
  5412. if(startBlock.tagName == 'LI' || startBlock.tagName == 'TD' || startBlock === obj){
  5413. domUtils.remove(obj,true);
  5414. }else{
  5415. domUtils.breakParent(startBlock,obj);
  5416. }
  5417. if(startBlock !== endBlock){
  5418. obj = domUtils.findParentByTagName(endBlock,'blockquote');
  5419. if(obj){
  5420. if(endBlock.tagName == 'LI' || endBlock.tagName == 'TD'){
  5421. domUtils.remove(obj,true);
  5422. }else{
  5423. domUtils.breakParent(endBlock,obj);
  5424. }
  5425. }
  5426. }
  5427. var blockquotes = domUtils.getElementsByTagName(this.document,'blockquote');
  5428. for(var i=0,bi;bi=blockquotes[i++];){
  5429. if(!bi.childNodes.length){
  5430. domUtils.remove(bi);
  5431. }else if(domUtils.getPosition(bi,startBlock)&domUtils.POSITION_FOLLOWING && domUtils.getPosition(bi,endBlock)&domUtils.POSITION_PRECEDING){
  5432. domUtils.remove(bi,true);
  5433. }
  5434. }
  5435. }
  5436. } else {
  5437. var tmpRange = range.cloneRange(),
  5438. node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode,
  5439. preNode = node,
  5440. doEnd = 1;
  5441. //调整开始
  5442. while ( 1 ) {
  5443. if ( domUtils.isBody(node) ) {
  5444. if ( preNode !== node ) {
  5445. if ( range.collapsed ) {
  5446. tmpRange.selectNode( preNode );
  5447. doEnd = 0;
  5448. } else {
  5449. tmpRange.setStartBefore( preNode );
  5450. }
  5451. }else{
  5452. tmpRange.setStart(node,0);
  5453. }
  5454. break;
  5455. }
  5456. if ( !blockquote[node.tagName] ) {
  5457. if ( range.collapsed ) {
  5458. tmpRange.selectNode( preNode );
  5459. } else{
  5460. tmpRange.setStartBefore( preNode);
  5461. }
  5462. break;
  5463. }
  5464. preNode = node;
  5465. node = node.parentNode;
  5466. }
  5467. //调整结束
  5468. if ( doEnd ) {
  5469. preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode;
  5470. while ( 1 ) {
  5471. if ( domUtils.isBody( node ) ) {
  5472. if ( preNode !== node ) {
  5473. tmpRange.setEndAfter( preNode );
  5474. } else {
  5475. tmpRange.setEnd( node, node.childNodes.length );
  5476. }
  5477. break;
  5478. }
  5479. if ( !blockquote[node.tagName] ) {
  5480. tmpRange.setEndAfter( preNode );
  5481. break;
  5482. }
  5483. preNode = node;
  5484. node = node.parentNode;
  5485. }
  5486. }
  5487. node = range.document.createElement( 'blockquote' );
  5488. domUtils.setAttributes( node, attrs );
  5489. node.appendChild( tmpRange.extractContents() );
  5490. tmpRange.insertNode( node );
  5491. //去除重复的
  5492. var childs = domUtils.getElementsByTagName(node,'blockquote');
  5493. for(var i=0,ci;ci=childs[i++];){
  5494. if(ci.parentNode){
  5495. domUtils.remove(ci,true);
  5496. }
  5497. }
  5498. }
  5499. range.moveToBookmark( bookmark ).select();
  5500. },
  5501. queryCommandState : function() {
  5502. if(this.highlight){
  5503. return -1;
  5504. }
  5505. return getObj(this) ? 1 : 0;
  5506. }
  5507. };
  5508. })();
  5509. ///import core
  5510. ///commands 大小写转换
  5511. ///commandsName touppercase
  5512. ///commandsName tolowercase
  5513. ///commandsTitle 大小写转换
  5514. /**
  5515. * 大小写转换
  5516. * @function
  5517. * @name baidu.editor.execCommands
  5518. * @param {String} cmdName cmdName="convertcase"
  5519. */
  5520. UE.commands['touppercase'] =
  5521. UE.commands['tolowercase'] = {
  5522. execCommand:function (cmd) {
  5523. var me = this,rng = new dom.Range(me.document),
  5524. convertCase = function(){
  5525. var rng = me.selection.getRange();
  5526. if(rng.collapsed){
  5527. return rng;
  5528. }
  5529. var bk = rng.createBookmark(),
  5530. bkEnd = bk.end,
  5531. filterFn = function( node ) {
  5532. return !domUtils.isBr(node) && !domUtils.isWhitespace( node );
  5533. },
  5534. curNode = domUtils.getNextDomNode( bk.start, false, filterFn );
  5535. while ( curNode && (domUtils.getPosition( curNode, bkEnd ) & domUtils.POSITION_PRECEDING) ) {
  5536. if ( curNode.nodeType == 3 ) {
  5537. curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase']();
  5538. }
  5539. curNode = domUtils.getNextDomNode( curNode, true, filterFn );
  5540. if(curNode === bkEnd){
  5541. break;
  5542. }
  5543. }
  5544. return rng.moveToBookmark(bk);
  5545. };
  5546. //table的处理
  5547. if(me.currentSelectedArr && me.currentSelectedArr.length > 0){
  5548. for(var i=0,ci;ci=me.currentSelectedArr[i++];){
  5549. if(ci.style.display != 'none' && !domUtils.isEmptyBlock(ci)){
  5550. rng.selectNodeContents(ci).select();
  5551. convertCase();
  5552. }
  5553. }
  5554. rng.selectNodeContents(me.currentSelectedArr[0]).select();
  5555. }else{
  5556. convertCase().select();
  5557. }
  5558. },
  5559. queryCommandState:function () {
  5560. return this.highlight ? -1 : 0;
  5561. }
  5562. };
  5563. ///import core
  5564. ///import plugins\paragraph.js
  5565. ///commands 首行缩进
  5566. ///commandsName Outdent,Indent
  5567. ///commandsTitle 取消缩进,首行缩进
  5568. /**
  5569. * 首行缩进
  5570. * @function
  5571. * @name baidu.editor.execCommand
  5572. * @param {String} cmdName outdent取消缩进,indent缩进
  5573. */
  5574. UE.commands['indent'] = {
  5575. execCommand : function() {
  5576. var me = this,value = me.queryCommandState("indent") ? "0em" : (me.options.indentValue || '2em');
  5577. me.execCommand('Paragraph','p',{style:'text-indent:'+ value});
  5578. },
  5579. queryCommandState : function() {
  5580. if(this.highlight){return -1;}
  5581. var pN = utils.findNode(this.selection.getStartElementPath(),['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']);
  5582. return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
  5583. }
  5584. };
  5585. ///import core
  5586. ///commands 打印
  5587. ///commandsName Print
  5588. ///commandsTitle 打印
  5589. /**
  5590. * @description 打印
  5591. * @name baidu.editor.execCommand
  5592. * @param {String} cmdName print打印编辑器内容
  5593. * @author zhanyi
  5594. */
  5595. UE.commands['print'] = {
  5596. execCommand : function(){
  5597. this.window.print();
  5598. },
  5599. notNeedUndo : 1
  5600. };
  5601. ///import core
  5602. ///commands 预览
  5603. ///commandsName Preview
  5604. ///commandsTitle 预览
  5605. /**
  5606. * 预览
  5607. * @function
  5608. * @name baidu.editor.execCommand
  5609. * @param {String} cmdName preview预览编辑器内容
  5610. */
  5611. UE.commands['preview'] = {
  5612. execCommand : function(){
  5613. var w = window.open('', '_blank', ''),
  5614. d = w.document;
  5615. d.open();
  5616. d.write(this.getAllHtml());
  5617. d.close();
  5618. },
  5619. notNeedUndo : 1
  5620. };
  5621. ///import core
  5622. ///import plugins\inserthtml.js
  5623. ///commands 特殊字符
  5624. ///commandsName Spechars
  5625. ///commandsTitle 特殊字符
  5626. ///commandsDialog dialogs\spechars\spechars.html
  5627. UE.commands['spechars'] = {
  5628. queryCommandState : function(){
  5629. return this.highlight ? -1 :0;
  5630. }
  5631. };
  5632. ///import core
  5633. ///import plugins\image.js
  5634. ///commands 插入表情
  5635. ///commandsName Emotion
  5636. ///commandsTitle 表情
  5637. ///commandsDialog dialogs\emotion\emotion.html
  5638. UE.commands['emotion'] = {
  5639. queryCommandState : function(){
  5640. return this.highlight ? -1 :0;
  5641. }
  5642. };
  5643. ///import core
  5644. ///commands 全选
  5645. ///commandsName SelectAll
  5646. ///commandsTitle 全选
  5647. /**
  5648. * 选中所有
  5649. * @function
  5650. * @name baidu.editor.execCommand
  5651. * @param {String} cmdName selectall选中编辑器里的所有内容
  5652. * @author zhanyi
  5653. */
  5654. UE.plugins['selectall'] = function(){
  5655. var me = this;
  5656. me.commands['selectall'] = {
  5657. execCommand : function(){
  5658. //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
  5659. var me = this,body = me.body,
  5660. range = me.selection.getRange();
  5661. range.selectNodeContents(body);
  5662. if(domUtils.isEmptyBlock(body)){
  5663. //opera不能自动合并到元素的里边,要手动处理一下
  5664. if(browser.opera && body.firstChild && body.firstChild.nodeType == 1){
  5665. range.setStartAtFirst(body.firstChild);
  5666. }
  5667. range.collapse(true);
  5668. }
  5669. range.select(true);
  5670. this.selectAll = true;
  5671. },
  5672. notNeedUndo : 1
  5673. };
  5674. me.addListener('ready',function(){
  5675. domUtils.on(me.document,'click',function(evt){
  5676. me.selectAll = false;
  5677. });
  5678. });
  5679. };
  5680. ///import core
  5681. ///commands 格式
  5682. ///commandsName Paragraph
  5683. ///commandsTitle 段落格式
  5684. /**
  5685. * 段落样式
  5686. * @function
  5687. * @name baidu.editor.execCommand
  5688. * @param {String} cmdName paragraph插入段落执行命令
  5689. * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
  5690. * @param {String} attrs 标签的属性
  5691. * @author zhanyi
  5692. */
  5693. UE.plugins['paragraph'] = function() {
  5694. var me = this,
  5695. block = domUtils.isBlockElm,
  5696. notExchange = ['TD','LI','PRE'],
  5697. doParagraph = function(range,style,attrs,sourceCmdName){
  5698. var bookmark = range.createBookmark(),
  5699. filterFn = function( node ) {
  5700. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace( node );
  5701. },
  5702. para;
  5703. range.enlarge( true );
  5704. var bookmark2 = range.createBookmark(),
  5705. current = domUtils.getNextDomNode( bookmark2.start, false, filterFn ),
  5706. tmpRange = range.cloneRange(),
  5707. tmpNode;
  5708. while ( current && !(domUtils.getPosition( current, bookmark2.end ) & domUtils.POSITION_FOLLOWING) ) {
  5709. if ( current.nodeType == 3 || !block( current ) ) {
  5710. tmpRange.setStartBefore( current );
  5711. while ( current && current !== bookmark2.end && !block( current ) ) {
  5712. tmpNode = current;
  5713. current = domUtils.getNextDomNode( current, false, null, function( node ) {
  5714. return !block( node );
  5715. } );
  5716. }
  5717. tmpRange.setEndAfter( tmpNode );
  5718. para = range.document.createElement( style );
  5719. if(attrs){
  5720. domUtils.setAttributes(para,attrs);
  5721. if(sourceCmdName && sourceCmdName == 'customstyle' && attrs.style){
  5722. para.style.cssText = attrs.style;
  5723. }
  5724. }
  5725. para.appendChild( tmpRange.extractContents() );
  5726. //需要内容占位
  5727. if(domUtils.isEmptyNode(para)){
  5728. domUtils.fillChar(range.document,para);
  5729. }
  5730. tmpRange.insertNode( para );
  5731. var parent = para.parentNode;
  5732. //如果para上一级是一个block元素且不是body,td就删除它
  5733. if ( block( parent ) && !domUtils.isBody( para.parentNode ) && utils.indexOf(notExchange,parent.tagName)==-1) {
  5734. //存储dir,style
  5735. if(!(sourceCmdName && sourceCmdName == 'customstyle')){
  5736. parent.getAttribute('dir') && para.setAttribute('dir',parent.getAttribute('dir'));
  5737. //trace:1070
  5738. parent.style.cssText && (para.style.cssText = parent.style.cssText + ';' + para.style.cssText);
  5739. //trace:1030
  5740. parent.style.textAlign && !para.style.textAlign && (para.style.textAlign = parent.style.textAlign);
  5741. parent.style.textIndent && !para.style.textIndent && (para.style.textIndent = parent.style.textIndent);
  5742. parent.style.padding && !para.style.padding && (para.style.padding = parent.style.padding);
  5743. }
  5744. //trace:1706 选择的就是h1-6要删除
  5745. if(attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName) ){
  5746. domUtils.setAttributes(parent,attrs);
  5747. if(sourceCmdName && sourceCmdName == 'customstyle' && attrs.style){
  5748. parent.style.cssText = attrs.style;
  5749. }
  5750. domUtils.remove(para,true);
  5751. para = parent;
  5752. }else{
  5753. domUtils.remove( para.parentNode, true );
  5754. }
  5755. }
  5756. if( utils.indexOf(notExchange,parent.tagName)!=-1){
  5757. current = parent;
  5758. }else{
  5759. current = para;
  5760. }
  5761. current = domUtils.getNextDomNode( current, false, filterFn );
  5762. } else {
  5763. current = domUtils.getNextDomNode( current, true, filterFn );
  5764. }
  5765. }
  5766. return range.moveToBookmark( bookmark2 ).moveToBookmark( bookmark );
  5767. };
  5768. me.setOpt('paragraph',{'p':'', 'h1':'', 'h2':'', 'h3':'', 'h4':'', 'h5':'', 'h6':''});
  5769. me.commands['paragraph'] = {
  5770. execCommand : function( cmdName, style,attrs,sourceCmdName ) {
  5771. var range = new dom.Range(this.document);
  5772. if(this.currentSelectedArr && this.currentSelectedArr.length > 0){
  5773. for(var i=0,ti;ti=this.currentSelectedArr[i++];){
  5774. //trace:1079 不显示的不处理,插入文本,空的td也能加上相应的标签
  5775. if(ti.style.display == 'none'){
  5776. continue;
  5777. }
  5778. if(domUtils.isEmptyNode(ti)){
  5779. var tmpTxt = this.document.createTextNode('paragraph');
  5780. ti.innerHTML = '';
  5781. ti.appendChild(tmpTxt);
  5782. }
  5783. doParagraph(range.selectNodeContents(ti),style,attrs,sourceCmdName);
  5784. if(tmpTxt){
  5785. var pN = tmpTxt.parentNode;
  5786. domUtils.remove(tmpTxt);
  5787. if(domUtils.isEmptyNode(pN)){
  5788. domUtils.fillNode(this.document,pN);
  5789. }
  5790. }
  5791. }
  5792. var td = this.currentSelectedArr[0];
  5793. if(domUtils.isEmptyBlock(td)){
  5794. range.setStart(td,0).setCursor(false,true);
  5795. }else{
  5796. range.selectNode(td).select();
  5797. }
  5798. }else{
  5799. range = this.selection.getRange();
  5800. //闭合时单独处理
  5801. if(range.collapsed){
  5802. var txt = this.document.createTextNode('p');
  5803. range.insertNode(txt);
  5804. //去掉冗余的fillchar
  5805. if(browser.ie){
  5806. var node = txt.previousSibling;
  5807. if(node && domUtils.isWhitespace(node)){
  5808. domUtils.remove(node);
  5809. }
  5810. node = txt.nextSibling;
  5811. if(node && domUtils.isWhitespace(node)){
  5812. domUtils.remove(node);
  5813. }
  5814. }
  5815. }
  5816. range = doParagraph(range,style,attrs,sourceCmdName);
  5817. if(txt){
  5818. range.setStartBefore(txt).collapse(true);
  5819. pN = txt.parentNode;
  5820. domUtils.remove(txt);
  5821. if(domUtils.isBlockElm(pN)&&domUtils.isEmptyNode(pN)){
  5822. domUtils.fillNode(this.document,pN);
  5823. }
  5824. }
  5825. if(browser.gecko && range.collapsed && range.startContainer.nodeType == 1){
  5826. var child = range.startContainer.childNodes[range.startOffset];
  5827. if(child && child.nodeType == 1 && child.tagName.toLowerCase() == style){
  5828. range.setStart(child,0).collapse(true);
  5829. }
  5830. }
  5831. //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
  5832. range.select();
  5833. }
  5834. return true;
  5835. },
  5836. queryCommandValue : function() {
  5837. var node = utils.findNode(this.selection.getStartElementPath(),['p','h1','h2','h3','h4','h5','h6']);
  5838. return node ? node.tagName.toLowerCase() : '';
  5839. },
  5840. queryCommandState : function(){
  5841. return this.highlight ? -1 :0;
  5842. }
  5843. };
  5844. };
  5845. ///import core
  5846. ///commands 输入的方向
  5847. ///commandsName DirectionalityLtr,DirectionalityRtl
  5848. ///commandsTitle 从左向右输入,从右向左输入
  5849. /**
  5850. * 输入的方向
  5851. * @function
  5852. * @name baidu.editor.execCommand
  5853. * @param {String} cmdName directionality执行函数的参数
  5854. * @param {String} forward ltr从左向右输入,rtl从右向左输入
  5855. */
  5856. (function() {
  5857. var block = domUtils.isBlockElm ,
  5858. getObj = function(editor){
  5859. // var startNode = editor.selection.getStart(),
  5860. // parents;
  5861. // if ( startNode ) {
  5862. // //查找所有的是block的父亲节点
  5863. // parents = domUtils.findParents( startNode, true, block, true );
  5864. // for ( var i = 0,ci; ci = parents[i++]; ) {
  5865. // if ( ci.getAttribute( 'dir' ) ) {
  5866. // return ci;
  5867. // }
  5868. // }
  5869. // }
  5870. return utils.findNode(editor.selection.getStartElementPath(),null,function(n){return n.getAttribute('dir')});
  5871. },
  5872. doDirectionality = function(range,editor,forward){
  5873. var bookmark,
  5874. filterFn = function( node ) {
  5875. return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
  5876. },
  5877. obj = getObj( editor );
  5878. if ( obj && range.collapsed ) {
  5879. obj.setAttribute( 'dir', forward );
  5880. return range;
  5881. }
  5882. bookmark = range.createBookmark();
  5883. range.enlarge( true );
  5884. var bookmark2 = range.createBookmark(),
  5885. current = domUtils.getNextDomNode( bookmark2.start, false, filterFn ),
  5886. tmpRange = range.cloneRange(),
  5887. tmpNode;
  5888. while ( current && !(domUtils.getPosition( current, bookmark2.end ) & domUtils.POSITION_FOLLOWING) ) {
  5889. if ( current.nodeType == 3 || !block( current ) ) {
  5890. tmpRange.setStartBefore( current );
  5891. while ( current && current !== bookmark2.end && !block( current ) ) {
  5892. tmpNode = current;
  5893. current = domUtils.getNextDomNode( current, false, null, function( node ) {
  5894. return !block( node );
  5895. } );
  5896. }
  5897. tmpRange.setEndAfter( tmpNode );
  5898. var common = tmpRange.getCommonAncestor();
  5899. if ( !domUtils.isBody( common ) && block( common ) ) {
  5900. //遍历到了block节点
  5901. common.setAttribute( 'dir', forward );
  5902. current = common;
  5903. } else {
  5904. //没有遍历到,添加一个block节点
  5905. var p = range.document.createElement( 'p' );
  5906. p.setAttribute( 'dir', forward );
  5907. var frag = tmpRange.extractContents();
  5908. p.appendChild( frag );
  5909. tmpRange.insertNode( p );
  5910. current = p;
  5911. }
  5912. current = domUtils.getNextDomNode( current, false, filterFn );
  5913. } else {
  5914. current = domUtils.getNextDomNode( current, true, filterFn );
  5915. }
  5916. }
  5917. return range.moveToBookmark( bookmark2 ).moveToBookmark( bookmark );
  5918. };
  5919. UE.commands['directionality'] = {
  5920. execCommand : function( cmdName,forward ) {
  5921. var range = new dom.Range(this.document);
  5922. if(this.currentSelectedArr && this.currentSelectedArr.length > 0){
  5923. for(var i=0,ti;ti=this.currentSelectedArr[i++];){
  5924. if(ti.style.display != 'none'){
  5925. doDirectionality(range.selectNode(ti),this,forward);
  5926. }
  5927. }
  5928. range.selectNode(this.currentSelectedArr[0]).select();
  5929. }else{
  5930. range = this.selection.getRange();
  5931. //闭合时单独处理
  5932. if(range.collapsed){
  5933. var txt = this.document.createTextNode('d');
  5934. range.insertNode(txt);
  5935. }
  5936. doDirectionality(range,this,forward);
  5937. if(txt){
  5938. range.setStartBefore(txt).collapse(true);
  5939. domUtils.remove(txt);
  5940. }
  5941. range.select();
  5942. }
  5943. return true;
  5944. },
  5945. queryCommandValue : function() {
  5946. var node = getObj(this);
  5947. return node ? node.getAttribute('dir') : 'ltr';
  5948. },
  5949. queryCommandState : function(){
  5950. return this.highlight ? -1 :0;
  5951. }
  5952. };
  5953. })();
  5954. ///import core
  5955. ///import plugins\inserthtml.js
  5956. ///commands 分割线
  5957. ///commandsName Horizontal
  5958. ///commandsTitle 分隔线
  5959. /**
  5960. * 分割线
  5961. * @function
  5962. * @name baidu.editor.execCommand
  5963. * @param {String} cmdName horizontal插入分割线
  5964. */
  5965. UE.commands['horizontal'] = {
  5966. execCommand : function( cmdName ) {
  5967. var me = this;
  5968. if(me.queryCommandState(cmdName)!==-1){
  5969. me.execCommand('insertHtml','<hr>');
  5970. var range = me.selection.getRange(),
  5971. start = range.startContainer;
  5972. if(start.nodeType == 1 && !start.childNodes[range.startOffset] ){
  5973. var tmp;
  5974. if(tmp = start.childNodes[range.startOffset - 1]){
  5975. if(tmp.nodeType == 1 && tmp.tagName == 'HR'){
  5976. if(me.options.enterTag == 'p'){
  5977. tmp = me.document.createElement('p');
  5978. range.insertNode(tmp);
  5979. range.setStart(tmp,0).setCursor();
  5980. }else{
  5981. tmp = me.document.createElement('br');
  5982. range.insertNode(tmp);
  5983. range.setStartBefore(tmp).setCursor();
  5984. }
  5985. }
  5986. }
  5987. }
  5988. return true;
  5989. }
  5990. },
  5991. //边界在table里不能加分隔线
  5992. queryCommandState : function() {
  5993. return this.highlight || utils.findNode(this.selection.getStartElementPath(),['table']) ? -1 : 0;
  5994. }
  5995. };
  5996. ///import core
  5997. ///import plugins\inserthtml.js
  5998. ///commands 日期,时间
  5999. ///commandsName Date,Time
  6000. ///commandsTitle 日期,时间
  6001. /**
  6002. * 插入日期
  6003. * @function
  6004. * @name baidu.editor.execCommand
  6005. * @param {String} cmdName date插入日期
  6006. * @author zhuwenxuan
  6007. */
  6008. /**
  6009. * 插入时间
  6010. * @function
  6011. * @name baidu.editor.execCommand
  6012. * @param {String} cmdName time插入时间
  6013. * @author zhuwenxuan
  6014. */
  6015. UE.commands['time'] = UE.commands["date"] = {
  6016. execCommand : function(cmd){
  6017. var date = new Date;
  6018. this.execCommand('insertHtml',cmd == "time" ?
  6019. (date.getHours()+":"+ (date.getMinutes()<10 ? "0"+date.getMinutes() : date.getMinutes())+":"+(date.getSeconds()<10 ? "0"+date.getSeconds() : date.getSeconds())) :
  6020. (date.getFullYear()+"-"+((date.getMonth()+1)<10 ? "0"+(date.getMonth()+1) : date.getMonth()+1)+"-"+(date.getDate()<10?"0"+date.getDate():date.getDate())));
  6021. },
  6022. queryCommandState : function(){
  6023. return this.highlight ? -1 :0;
  6024. }
  6025. };
  6026. ///import core
  6027. ///import plugins\paragraph.js
  6028. ///commands 段间距
  6029. ///commandsName RowSpacingBottom,RowSpacingTop
  6030. ///commandsTitle 段间距
  6031. /**
  6032. * @description 设置段前距,段后距
  6033. * @name baidu.editor.execCommand
  6034. * @param {String} cmdName rowspacing设置段间距
  6035. * @param {String} value 值,以px为单位
  6036. * @param {String} dir top或bottom段前后段后
  6037. * @author zhanyi
  6038. */
  6039. UE.plugins['rowspacing'] = function(){
  6040. var me = this;
  6041. me.setOpt({
  6042. 'rowspacingtop':['5', '10', '15', '20', '25'],
  6043. 'rowspacingbottom':['5', '10', '15', '20', '25']
  6044. });
  6045. me.commands['rowspacing'] = {
  6046. execCommand : function( cmdName,value,dir ) {
  6047. this.execCommand('paragraph','p',{style:'margin-'+dir+':'+value + 'px'});
  6048. return true;
  6049. },
  6050. queryCommandValue : function(cmdName,dir) {
  6051. var pN = utils.findNode(this.selection.getStartElementPath(),null,function(node){return domUtils.isBlockElm(node) }),
  6052. value;
  6053. //trace:1026
  6054. if(pN){
  6055. value = domUtils.getComputedStyle(pN,'margin-'+dir).replace(/[^\d]/g,'');
  6056. return !value ? 0 : value;
  6057. }
  6058. return 0;
  6059. },
  6060. queryCommandState : function(){
  6061. return this.highlight ? -1 :0;
  6062. }
  6063. };
  6064. };
  6065. ///import core
  6066. ///import plugins\paragraph.js
  6067. ///commands 行间距
  6068. ///commandsName LineHeight
  6069. ///commandsTitle 行间距
  6070. /**
  6071. * @description 设置行内间距
  6072. * @name baidu.editor.execCommand
  6073. * @param {String} cmdName lineheight设置行内间距
  6074. * @param {String} value 值
  6075. * @author zhuwenxuan
  6076. */
  6077. UE.plugins['lineheight'] = function(){
  6078. var me = this;
  6079. me.setOpt({'lineheight':['1', '1.5','1.75','2', '3', '4', '5']});
  6080. me.commands['lineheight'] = {
  6081. execCommand : function( cmdName,value ) {
  6082. this.execCommand('paragraph','p',{style:'line-height:'+ (value == "1" ? "normal" : value + 'em') });
  6083. return true;
  6084. },
  6085. queryCommandValue : function() {
  6086. var pN = utils.findNode(this.selection.getStartElementPath(),null,function(node){return domUtils.isBlockElm(node)});
  6087. if(pN){
  6088. var value = domUtils.getComputedStyle(pN,'line-height');
  6089. return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig,"");
  6090. }
  6091. },
  6092. queryCommandState : function(){
  6093. return this.highlight ? -1 :0;
  6094. }
  6095. };
  6096. };
  6097. ///import core
  6098. ///commands 清空文档
  6099. ///commandsName ClearDoc
  6100. ///commandsTitle 清空文档
  6101. /**
  6102. *
  6103. * 清空文档
  6104. * @function
  6105. * @name baidu.editor.execCommand
  6106. * @param {String} cmdName cleardoc清空文档
  6107. */
  6108. UE.commands['cleardoc'] = {
  6109. execCommand : function( cmdName) {
  6110. var me = this,
  6111. enterTag = me.options.enterTag,
  6112. range = me.selection.getRange();
  6113. if(enterTag == "br"){
  6114. me.body.innerHTML = "<br/>";
  6115. range.setStart(me.body,0).setCursor();
  6116. }else{
  6117. me.body.innerHTML = "<p>"+(ie ? "" : "<br/>")+"</p>";
  6118. range.setStart(me.body.firstChild,0).setCursor(false,true);
  6119. }
  6120. }
  6121. };
  6122. ///import core
  6123. ///commands 锚点
  6124. ///commandsName Anchor
  6125. ///commandsTitle 锚点
  6126. ///commandsDialog dialogs\anchor\anchor.html
  6127. /**
  6128. * 锚点
  6129. * @function
  6130. * @name baidu.editor.execCommands
  6131. * @param {String} cmdName cmdName="anchor"插入锚点
  6132. */
  6133. UE.commands['anchor'] = {
  6134. execCommand:function (cmd, name) {
  6135. var range = this.selection.getRange(),img = range.getClosedNode();
  6136. if (img && img.getAttribute('anchorname')) {
  6137. if (name) {
  6138. img.setAttribute('anchorname', name);
  6139. } else {
  6140. range.setStartBefore(img).setCursor();
  6141. domUtils.remove(img);
  6142. }
  6143. } else {
  6144. if (name) {
  6145. //只在选区的开始插入
  6146. var anchor = this.document.createElement('img');
  6147. range.collapse(true);
  6148. domUtils.setAttributes(anchor,{
  6149. 'anchorname':name,
  6150. 'class':'anchorclass'
  6151. });
  6152. range.insertNode(anchor).setStartAfter(anchor).setCursor(false,true);
  6153. }
  6154. }
  6155. },
  6156. queryCommandState:function () {
  6157. return this.highlight ? -1 : 0;
  6158. }
  6159. };
  6160. ///import core
  6161. ///commands 删除
  6162. ///commandsName Delete
  6163. ///commandsTitle 删除
  6164. /**
  6165. * 删除
  6166. * @function
  6167. * @name baidu.editor.execCommand
  6168. * @param {String} cmdName delete删除
  6169. * @author zhanyi
  6170. */
  6171. UE.commands['delete'] = {
  6172. execCommand : function (){
  6173. var range = this.selection.getRange(),
  6174. mStart = 0,
  6175. mEnd = 0,
  6176. me = this;
  6177. if(this.selectAll ){
  6178. //trace:1633
  6179. me.body.innerHTML = '<p>'+(browser.ie ? '&nbsp;' : '<br/>')+'</p>';
  6180. range.setStart(me.body.firstChild,0).setCursor(false,true);
  6181. me.selectAll = false;
  6182. return;
  6183. }
  6184. if(me.currentSelectedArr && me.currentSelectedArr.length > 0){
  6185. for(var i=0,ci;ci=me.currentSelectedArr[i++];){
  6186. if(ci.style.display != 'none'){
  6187. ci.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
  6188. }
  6189. }
  6190. range.setStart(me.currentSelectedArr[0],0).setCursor();
  6191. return;
  6192. }
  6193. if(range.collapsed){
  6194. return;
  6195. }
  6196. range.txtToElmBoundary();
  6197. //&& !domUtils.isBlockElm(range.startContainer)
  6198. while(!range.startOffset && !domUtils.isBody(range.startContainer) && !dtd.$tableContent[range.startContainer.tagName] ){
  6199. mStart = 1;
  6200. range.setStartBefore(range.startContainer);
  6201. }
  6202. //&& !domUtils.isBlockElm(range.endContainer)
  6203. //不对文本节点进行操作
  6204. //trace:2428
  6205. while(range.endContainer.nodeType != 3 && !domUtils.isBody(range.endContainer)&& !dtd.$tableContent[range.endContainer.tagName] ){
  6206. var child,endContainer = range.endContainer,endOffset = range.endOffset;
  6207. // if(endContainer.nodeType == 3 && endOffset == endContainer.nodeValue.length){
  6208. // range.setEndAfter(endContainer);
  6209. // continue;
  6210. // }
  6211. child = endContainer.childNodes[endOffset];
  6212. if(!child || domUtils.isBr(child) && endContainer.lastChild === child){
  6213. range.setEndAfter(endContainer);
  6214. continue;
  6215. }
  6216. break;
  6217. }
  6218. if(mStart){
  6219. var start = me.document.createElement('span');
  6220. start.innerHTML = 'start';
  6221. start.id = '_baidu_cut_start';
  6222. range.insertNode(start).setStartBefore(start);
  6223. }
  6224. if(mEnd){
  6225. var end = me.document.createElement('span');
  6226. end.innerHTML = 'end';
  6227. end.id = '_baidu_cut_end';
  6228. range.cloneRange().collapse(false).insertNode(end);
  6229. range.setEndAfter(end);
  6230. }
  6231. range.deleteContents();
  6232. if(domUtils.isBody(range.startContainer) && domUtils.isEmptyBlock(me.body)){
  6233. me.body.innerHTML = '<p>'+(browser.ie?'':'<br/>')+'</p>';
  6234. range.setStart(me.body.firstChild,0).collapse(true);
  6235. }else if ( !browser.ie && domUtils.isEmptyBlock(range.startContainer)){
  6236. range.startContainer.innerHTML = '<br/>';
  6237. }
  6238. range.select(true);
  6239. },
  6240. queryCommandState : function(){
  6241. if(this.currentSelectedArr && this.currentSelectedArr.length > 0){
  6242. return 0;
  6243. }
  6244. return this.highlight || this.selection.getRange().collapsed ? -1 : 0;
  6245. }
  6246. };
  6247. ///import core
  6248. ///commands 字数统计
  6249. ///commandsName WordCount,wordCount
  6250. ///commandsTitle 字数统计
  6251. /**
  6252. * Created by JetBrains WebStorm.
  6253. * User: taoqili
  6254. * Date: 11-9-7
  6255. * Time: 下午8:18
  6256. * To change this template use File | Settings | File Templates.
  6257. */
  6258. UE.plugins['wordcount'] = function(){
  6259. var me = this;
  6260. me.setOpt({
  6261. wordCount:true,
  6262. maximumWords:10000,
  6263. wordCountMsg: me.options.wordCountMsg||me.getLang("wordCountMsg"),
  6264. wordOverFlowMsg:me.options.wordOverFlowMsg||me.getLang("wordOverFlowMsg")
  6265. });
  6266. var opt = me.options,
  6267. max = opt.maximumWords,
  6268. msg = opt.wordCountMsg ,
  6269. errMsg = opt.wordOverFlowMsg;
  6270. if(!opt.wordCount){
  6271. return;
  6272. }
  6273. me.commands["wordcount"]={
  6274. queryCommandValue:function(cmd,onlyCount){
  6275. var length,contentText,reg;
  6276. if(onlyCount){
  6277. reg = new RegExp("[\r\t\n]","g");
  6278. contentText = this.getContentTxt().replace(reg,"");
  6279. return contentText.length;
  6280. }
  6281. reg = new RegExp("[\r\t\n]","g");
  6282. contentText = this.getContentTxt().replace(reg,"");
  6283. length = contentText.length;
  6284. if(max-length<0){
  6285. me.fireEvent('wordcountoverflow');
  6286. return errMsg;
  6287. }
  6288. return msg.replace("{#leave}",max-length >= 0 ? max-length:0).replace("{#count}",length);
  6289. }
  6290. };
  6291. };
  6292. ///import core
  6293. ///commands 添加分页功能
  6294. ///commandsName PageBreak
  6295. ///commandsTitle 分页
  6296. /**
  6297. * @description 添加分页功能
  6298. * @author zhanyi
  6299. */
  6300. UE.plugins['pagebreak'] = function () {
  6301. var me = this,
  6302. notBreakTags = ['td'];
  6303. function fillNode(node){
  6304. if(domUtils.isEmptyBlock(node)){
  6305. var firstChild = node.firstChild,tmpNode;
  6306. while(firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)){
  6307. tmpNode = firstChild;
  6308. firstChild = firstChild.firstChild;
  6309. }
  6310. !tmpNode && (tmpNode = node);
  6311. domUtils.fillNode(me.document,tmpNode);
  6312. }
  6313. }
  6314. function isHr(node){
  6315. return node && node.nodeType == 1 && node.tagName == 'HR' && node.className == 'pagebreak';
  6316. }
  6317. me.commands['pagebreak'] = {
  6318. execCommand:function () {
  6319. var range = me.selection.getRange(),hr = me.document.createElement('hr');
  6320. domUtils.setAttributes(hr,{
  6321. 'class' : 'pagebreak',
  6322. noshade:"noshade",
  6323. size:"5"
  6324. });
  6325. domUtils.unselectable(hr);
  6326. //table单独处理
  6327. var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true),
  6328. parents = [], pN;
  6329. if (node) {
  6330. switch (node.tagName) {
  6331. case 'TD':
  6332. pN = node.parentNode;
  6333. if (!pN.previousSibling) {
  6334. var table = domUtils.findParentByTagName(pN, 'table');
  6335. // var tableWrapDiv = table.parentNode;
  6336. // if(tableWrapDiv && tableWrapDiv.nodeType == 1
  6337. // && tableWrapDiv.tagName == 'DIV'
  6338. // && tableWrapDiv.getAttribute('dropdrag')
  6339. // ){
  6340. // domUtils.remove(tableWrapDiv,true);
  6341. // }
  6342. table.parentNode.insertBefore(hr, table);
  6343. parents = domUtils.findParents(hr, true);
  6344. } else {
  6345. pN.parentNode.insertBefore(hr, pN);
  6346. parents = domUtils.findParents(hr);
  6347. }
  6348. pN = parents[1];
  6349. if (hr !== pN) {
  6350. domUtils.breakParent(hr, pN);
  6351. }
  6352. domUtils.clearSelectedArr(me.currentSelectedArr);
  6353. //table要重写绑定一下拖拽
  6354. me.fireEvent('afteradjusttable',me.document);
  6355. }
  6356. } else {
  6357. if (!range.collapsed) {
  6358. range.deleteContents();
  6359. var start = range.startContainer;
  6360. while ( !domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils.isEmptyNode(start)) {
  6361. range.setStartBefore(start).collapse(true);
  6362. domUtils.remove(start);
  6363. start = range.startContainer;
  6364. }
  6365. }
  6366. range.insertNode(hr);
  6367. var pN = hr.parentNode, nextNode;
  6368. while (!domUtils.isBody(pN)) {
  6369. domUtils.breakParent(hr, pN);
  6370. nextNode = hr.nextSibling;
  6371. if (nextNode && domUtils.isEmptyBlock(nextNode)) {
  6372. domUtils.remove(nextNode);
  6373. }
  6374. pN = hr.parentNode;
  6375. }
  6376. nextNode = hr.nextSibling;
  6377. var pre = hr.previousSibling;
  6378. if(isHr(pre)){
  6379. domUtils.remove(pre);
  6380. }else{
  6381. pre && fillNode(pre);
  6382. }
  6383. if(!nextNode){
  6384. var p = me.document.createElement('p');
  6385. hr.parentNode.appendChild(p);
  6386. domUtils.fillNode(me.document,p);
  6387. range.setStart(p,0).collapse(true);
  6388. }else{
  6389. if(isHr(nextNode)){
  6390. domUtils.remove(nextNode);
  6391. }else{
  6392. fillNode(nextNode);
  6393. }
  6394. range.setEndAfter(hr).collapse(false);
  6395. }
  6396. range.select(true);
  6397. }
  6398. },
  6399. queryCommandState:function () {
  6400. return this.highlight ? -1 : 0;
  6401. }
  6402. };
  6403. };
  6404. ///import core
  6405. ///commands 本地图片引导上传
  6406. ///commandsName WordImage
  6407. ///commandsTitle 本地图片引导上传
  6408. UE.plugins["wordimage"] = function(){
  6409. var me = this,
  6410. images;
  6411. me.commands['wordimage'] = {
  6412. execCommand : function() {
  6413. images = domUtils.getElementsByTagName(me.document.body,"img");
  6414. var urlList = [];
  6415. for(var i=0,ci;ci=images[i++];){
  6416. var url=ci.getAttribute("word_img");
  6417. url && urlList.push(url);
  6418. }
  6419. if(images.length){
  6420. this["word_img"] = urlList;
  6421. }
  6422. },
  6423. queryCommandState: function(){
  6424. images = domUtils.getElementsByTagName(me.document.body,"img");
  6425. for(var i=0,ci;ci =images[i++];){
  6426. if(ci.getAttribute("word_img")){
  6427. return 1;
  6428. }
  6429. }
  6430. return -1;
  6431. }
  6432. };
  6433. };
  6434. ///import core
  6435. ///commands 撤销和重做
  6436. ///commandsName Undo,Redo
  6437. ///commandsTitle 撤销,重做
  6438. /**
  6439. * @description 回退
  6440. * @author zhanyi
  6441. */
  6442. UE.plugins['undo'] = function() {
  6443. var me = this,
  6444. maxUndoCount = me.options.maxUndoCount || 20,
  6445. maxInputCount = me.options.maxInputCount || 20,
  6446. fillchar = new RegExp(domUtils.fillChar + '|<\/hr>','gi'),// ie会产生多余的</hr>
  6447. //在比较时,需要过滤掉这些属性
  6448. specialAttr = /\b(?:href|src|name)="[^"]*?"/gi;
  6449. //场景的range实例
  6450. function sceneRange(rng){
  6451. var me = this;
  6452. me.collapsed = rng.collapsed;
  6453. me.startAddr = getAddr(rng.startContainer,rng.startOffset);
  6454. me.endAddr = rng.collapsed ? me.startAddr : getAddr(rng.endContainer,rng.endOffset)
  6455. }
  6456. sceneRange.prototype ={
  6457. compare : function(obj){
  6458. if(me.collapsed !== obj.collapsed){
  6459. return 0;
  6460. }
  6461. if(!compareAddr(me.startAddr,obj.startAddr) || !compareAddr(me.endAddr,obj.endAddr)){
  6462. return 0;
  6463. }
  6464. return 1;
  6465. },
  6466. transformRange : function(rng){
  6467. var me = this;
  6468. rng.collapsed = me.collapsed;
  6469. setAddr(rng,'start',me.startAddr);
  6470. rng.collapsed ? rng.collapse(true) : setAddr(rng,'end',me.endAddr)
  6471. }
  6472. };
  6473. function getAddr(node,index){
  6474. for(var i= 0,parentsIndex = [index],ci,
  6475. parents = domUtils.findParents(node,true,function(node){return !domUtils.isBody(node)},true);
  6476. ci=parents[i++];){
  6477. //修正偏移位置
  6478. if(i == 1 && ci.nodeType == 3){
  6479. var tmpNode = ci;
  6480. while(tmpNode = tmpNode.previousSibling){
  6481. if(tmpNode.nodeType == 3){
  6482. // console.log(index)
  6483. index += tmpNode.nodeValue.replace(fillCharReg,'').length;
  6484. }else{
  6485. break;
  6486. }
  6487. }
  6488. parentsIndex[0] = index;
  6489. }
  6490. parentsIndex.push(domUtils.getNodeIndex(ci,true));
  6491. }
  6492. return parentsIndex.reverse();
  6493. }
  6494. function compareAddr(indexA,indexB){
  6495. if(indexA.length != indexB.length)
  6496. return 0;
  6497. for(var i= 0,l=indexA.length;i<l;i++){
  6498. if(indexA[i]!=indexB[i])
  6499. return 0
  6500. }
  6501. return 1;
  6502. }
  6503. function setAddr(range,boundary,addr){
  6504. node = range.document.body;
  6505. for(var i= 0,node,l = addr.length - 1;i<l;i++){
  6506. node = node.childNodes[addr[i]];
  6507. }
  6508. range[boundary+'Container'] = node;
  6509. range[boundary+'Offset'] = addr[addr.length-1];
  6510. }
  6511. function UndoManager() {
  6512. this.list = [];
  6513. this.index = 0;
  6514. this.hasUndo = false;
  6515. this.hasRedo = false;
  6516. this.undo = function() {
  6517. if ( this.hasUndo ) {
  6518. var currentScene = this.getScene(),
  6519. lastScene = this.list[this.index];
  6520. if ( lastScene.content.replace(specialAttr,'') != currentScene.content.replace(specialAttr,'') ) {
  6521. this.save();
  6522. }
  6523. if(!this.list[this.index - 1] && this.list.length == 1){
  6524. this.reset();
  6525. return;
  6526. }
  6527. while ( this.list[this.index].content == this.list[this.index - 1].content ) {
  6528. this.index--;
  6529. if ( this.index == 0 ) {
  6530. return this.restore( 0 );
  6531. }
  6532. }
  6533. this.restore( --this.index );
  6534. }
  6535. };
  6536. this.redo = function() {
  6537. if ( this.hasRedo ) {
  6538. while ( this.list[this.index].content == this.list[this.index + 1].content ) {
  6539. this.index++;
  6540. if ( this.index == this.list.length - 1 ) {
  6541. return this.restore( this.index );
  6542. }
  6543. }
  6544. this.restore( ++this.index );
  6545. }
  6546. };
  6547. this.restore = function() {
  6548. var scene = this.list[this.index];
  6549. //trace:873
  6550. //去掉展位符
  6551. me.document.body.innerHTML = scene.bookcontent.replace(fillchar,'');
  6552. //处理undo后空格不展位的问题
  6553. if(browser.ie){
  6554. for(var i=0,pi,ps = me.document.getElementsByTagName('p');pi = ps[i++];){
  6555. if(pi.innerHTML == ''){
  6556. domUtils.fillNode(me.document,pi);
  6557. }
  6558. }
  6559. }
  6560. var range = new dom.Range( me.document );
  6561. //有可能再save时没有bookmark
  6562. try{
  6563. if(browser.opera || browser.safari){
  6564. scene.senceRange.transformRange(range)
  6565. }else{
  6566. range.moveToBookmark( {
  6567. start : '_baidu_bookmark_start_',
  6568. end : '_baidu_bookmark_end_',
  6569. id : true
  6570. //去掉true 是为了<b>|</b>,回退后还能在b里
  6571. } );
  6572. }
  6573. //trace:1278 ie9block元素为空,将出现光标定位的问题,必须填充内容
  6574. if(browser.ie && browser.version == 9 && range.collapsed && domUtils.isBlockElm(range.startContainer) && domUtils.isEmptyNode(range.startContainer)){
  6575. domUtils.fillNode(range.document,range.startContainer);
  6576. }
  6577. range.select(!browser.gecko);
  6578. if(!(browser.opera || browser.safari)){
  6579. setTimeout(function(){
  6580. range.scrollToView(me.autoHeightEnabled,me.autoHeightEnabled ? domUtils.getXY(me.iframe).y:0);
  6581. },200);
  6582. }
  6583. }catch(e){}
  6584. this.update();
  6585. //table的单独处理
  6586. if(me.currentSelectedArr){
  6587. me.currentSelectedArr = [];
  6588. var tds = me.document.getElementsByTagName('td');
  6589. for(var i=0,td;td=tds[i++];){
  6590. if(td.className == me.options.selectedTdClass){
  6591. me.currentSelectedArr.push(td);
  6592. }
  6593. }
  6594. }
  6595. this.clearKey();
  6596. //不能把自己reset了
  6597. me.fireEvent('reset',true);
  6598. };
  6599. this.getScene = function() {
  6600. var range = me.selection.getRange(),
  6601. cont = me.body.innerHTML.replace(fillchar,'');
  6602. //有可能边界落到了<table>|<tbody>这样的位置,所以缩一下位置
  6603. range.shrinkBoundary();
  6604. browser.ie && (cont = cont.replace(/>&nbsp;</g,'><').replace(/\s*</g,'').replace(/>\s*/g,'>'));
  6605. if(browser.opera || browser.safari){
  6606. return {
  6607. senceRange : new sceneRange(range),
  6608. content : cont,
  6609. bookcontent : cont
  6610. }
  6611. }else{
  6612. var bookmark = range.createBookmark( true, true ),
  6613. bookCont = me.body.innerHTML.replace(fillchar,'');
  6614. bookmark && range.moveToBookmark( bookmark ).select( true );
  6615. return {
  6616. bookcontent : bookCont,
  6617. content : cont
  6618. };
  6619. }
  6620. };
  6621. this.save = function() {
  6622. var currentScene = this.getScene(),
  6623. lastScene = this.list[this.index];
  6624. //内容相同位置相同不存
  6625. if ( lastScene && lastScene.content == currentScene.content &&
  6626. ( (browser.opera || browser.safari) ? lastScene.senceRange.compare(currentScene.senceRange) : lastScene.bookcontent == currentScene.bookcontent)
  6627. ) {
  6628. return;
  6629. }
  6630. this.list = this.list.slice( 0, this.index + 1 );
  6631. this.list.push( currentScene );
  6632. //如果大于最大数量了,就把最前的剔除
  6633. if ( this.list.length > maxUndoCount ) {
  6634. this.list.shift();
  6635. }
  6636. this.index = this.list.length - 1;
  6637. this.clearKey();
  6638. //跟新undo/redo状态
  6639. this.update();
  6640. };
  6641. this.update = function() {
  6642. this.hasRedo = this.list[this.index + 1] ? true : false;
  6643. this.hasUndo = this.list[this.index - 1] || this.list.length == 1 ? true : false;
  6644. };
  6645. this.reset = function() {
  6646. this.list = [];
  6647. this.index = 0;
  6648. this.hasUndo = false;
  6649. this.hasRedo = false;
  6650. this.clearKey();
  6651. };
  6652. this.clearKey = function(){
  6653. keycont = 0;
  6654. lastKeyCode = null;
  6655. me.fireEvent('contentchange');
  6656. };
  6657. }
  6658. me.undoManger = new UndoManager();
  6659. function saveScene() {
  6660. this.undoManger.save();
  6661. }
  6662. me.addListener( 'beforeexeccommand', saveScene );
  6663. me.addListener( 'afterexeccommand', saveScene );
  6664. me.addListener('reset',function(type,exclude){
  6665. if(!exclude){
  6666. me.undoManger.reset();
  6667. }
  6668. });
  6669. me.commands['redo'] = me.commands['undo'] = {
  6670. execCommand : function( cmdName ) {
  6671. me.undoManger[cmdName]();
  6672. },
  6673. queryCommandState : function( cmdName ) {
  6674. return me.undoManger['has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')] ? 0 : -1;
  6675. },
  6676. notNeedUndo : 1
  6677. };
  6678. var keys = {
  6679. // /*Backspace*/ 8:1, /*Delete*/ 46:1,
  6680. /*Shift*/ 16:1, /*Ctrl*/ 17:1, /*Alt*/ 18:1,
  6681. 37:1, 38:1, 39:1, 40:1,
  6682. 13:1 /*enter*/
  6683. },
  6684. keycont = 0,
  6685. lastKeyCode;
  6686. me.addListener( 'keydown', function( type, evt ) {
  6687. var keyCode = evt.keyCode || evt.which;
  6688. if ( !keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey ) {
  6689. if ( me.undoManger.list.length == 0 || ((keyCode == 8 ||keyCode == 46) && lastKeyCode != keyCode) ) {
  6690. me.undoManger.save(true);
  6691. lastKeyCode = keyCode;
  6692. return;
  6693. }
  6694. //trace:856
  6695. //修正第一次输入后,回退,再输入要到keycont>maxInputCount才能在回退的问题
  6696. if(me.undoManger.list.length == 2 && me.undoManger.index == 0 && keycont == 0){
  6697. me.undoManger.list.splice(1,1);
  6698. me.undoManger.update();
  6699. }
  6700. lastKeyCode = keyCode;
  6701. keycont++;
  6702. if ( keycont >= maxInputCount ) {
  6703. if(me.selection.getRange().collapsed)
  6704. me.undoManger.save();
  6705. }
  6706. }
  6707. } );
  6708. };
  6709. ///import core
  6710. ///import plugins/inserthtml.js
  6711. ///import plugins/undo.js
  6712. ///import plugins/serialize.js
  6713. ///commands 粘贴
  6714. ///commandsName PastePlain
  6715. ///commandsTitle 纯文本粘贴模式
  6716. /*
  6717. ** @description 粘贴
  6718. * @author zhanyi
  6719. */
  6720. (function() {
  6721. function getClipboardData( callback ) {
  6722. var doc = this.document;
  6723. if ( doc.getElementById( 'baidu_pastebin' ) ) {
  6724. return;
  6725. }
  6726. var range = this.selection.getRange(),
  6727. bk = range.createBookmark(),
  6728. //创建剪贴的容器div
  6729. pastebin = doc.createElement( 'div' );
  6730. pastebin.id = 'baidu_pastebin';
  6731. // Safari 要求div必须有内容,才能粘贴内容进来
  6732. browser.webkit && pastebin.appendChild( doc.createTextNode( domUtils.fillChar + domUtils.fillChar ) );
  6733. doc.body.appendChild( pastebin );
  6734. //trace:717 隐藏的span不能得到top
  6735. //bk.start.innerHTML = '&nbsp;';
  6736. bk.start.style.display = '';
  6737. pastebin.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
  6738. //要在现在光标平行的位置加入,否则会出现跳动的问题
  6739. domUtils.getXY( bk.start ).y + 'px';
  6740. range.selectNodeContents( pastebin ).select( true );
  6741. setTimeout( function() {
  6742. if (browser.webkit) {
  6743. for(var i=0,pastebins = doc.querySelectorAll('#baidu_pastebin'),pi;pi=pastebins[i++];){
  6744. if(domUtils.isEmptyNode(pi)){
  6745. domUtils.remove(pi);
  6746. }else{
  6747. pastebin = pi;
  6748. break;
  6749. }
  6750. }
  6751. }
  6752. try{
  6753. pastebin.parentNode.removeChild(pastebin);
  6754. }catch(e){}
  6755. range.moveToBookmark( bk ).select(true);
  6756. callback( pastebin );
  6757. }, 0 );
  6758. }
  6759. UE.plugins['paste'] = function() {
  6760. var me = this;
  6761. var word_img_flag = {flag:""};
  6762. var pasteplain = me.options.pasteplain === true;
  6763. var modify_num = {flag:""};
  6764. me.commands['pasteplain'] = {
  6765. queryCommandState: function (){
  6766. return pasteplain;
  6767. },
  6768. execCommand: function (){
  6769. pasteplain = !pasteplain|0;
  6770. },
  6771. notNeedUndo : 1
  6772. };
  6773. function filter(div){
  6774. var html;
  6775. if ( div.firstChild ) {
  6776. //去掉cut中添加的边界值
  6777. var nodes = domUtils.getElementsByTagName(div,'span');
  6778. for(var i=0,ni;ni=nodes[i++];){
  6779. if(ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end'){
  6780. domUtils.remove(ni);
  6781. }
  6782. }
  6783. if(browser.webkit){
  6784. var brs = div.querySelectorAll('div br');
  6785. for(var i=0,bi;bi=brs[i++];){
  6786. var pN = bi.parentNode;
  6787. if(pN.tagName == 'DIV' && pN.childNodes.length ==1){
  6788. pN.innerHTML = '<p><br/></p>';
  6789. domUtils.remove(pN);
  6790. }
  6791. }
  6792. var divs = div.querySelectorAll('#baidu_pastebin');
  6793. for(var i=0,di;di=divs[i++];){
  6794. var tmpP = me.document.createElement('p');
  6795. di.parentNode.insertBefore(tmpP,di);
  6796. while(di.firstChild){
  6797. tmpP.appendChild(di.firstChild);
  6798. }
  6799. domUtils.remove(di);
  6800. }
  6801. var metas = div.querySelectorAll('meta');
  6802. for(var i=0,ci;ci=metas[i++];){
  6803. domUtils.remove(ci);
  6804. }
  6805. var brs = div.querySelectorAll('br');
  6806. for(i=0;ci=brs[i++];){
  6807. if(/^apple-/.test(ci)){
  6808. domUtils.remove(ci);
  6809. }
  6810. }
  6811. }
  6812. if(browser.gecko){
  6813. var dirtyNodes = div.querySelectorAll('[_moz_dirty]');
  6814. for(i=0;ci=dirtyNodes[i++];){
  6815. ci.removeAttribute( '_moz_dirty' );
  6816. }
  6817. }
  6818. if(!browser.ie ){
  6819. var spans = div.querySelectorAll('span.apple-style-span');
  6820. for(var i=0,ci;ci=spans[i++];){
  6821. domUtils.remove(ci,true);
  6822. }
  6823. }
  6824. html = div.innerHTML;
  6825. var f = me.serialize;
  6826. if(f){
  6827. //如果过滤出现问题,捕获它,直接插入内容,避免出现错误导致粘贴整个失败
  6828. try{
  6829. var node = f.transformInput(
  6830. f.parseHTML(
  6831. //todo: 暂时不走dtd的过滤
  6832. f.word(html)//, true
  6833. ),word_img_flag
  6834. );
  6835. //trace:924
  6836. //纯文本模式也要保留段落
  6837. node = f.filter(node,pasteplain ? {
  6838. whiteList: {
  6839. 'p': {'br':1,'BR':1,$:{}},
  6840. 'br':{'$':{}},
  6841. 'div':{'br':1,'BR':1,'$':{}},
  6842. 'li':{'$':{}},
  6843. 'tr':{'td':1,'$':{}},
  6844. 'td':{'$':{}}
  6845. },
  6846. blackList: {
  6847. 'style':1,
  6848. 'script':1,
  6849. 'object':1
  6850. }
  6851. } : null, !pasteplain ? modify_num : null);
  6852. if(browser.webkit){
  6853. var length = node.children.length,
  6854. child;
  6855. while((child = node.children[length-1]) && child.tag == 'br'){
  6856. node.children.splice(length-1,1);
  6857. length = node.children.length;
  6858. }
  6859. }
  6860. html = f.toHTML(node,pasteplain);
  6861. }catch(e){}
  6862. }
  6863. //自定义的处理
  6864. html = {'html':html};
  6865. me.fireEvent('beforepaste',html);
  6866. //不用在走过滤了
  6867. me.execCommand( 'insertHtml',html.html,true);
  6868. me.fireEvent("afterpaste");
  6869. }
  6870. }
  6871. me.addListener('ready',function(){
  6872. domUtils.on(me.body,'cut',function(){
  6873. var range = me.selection.getRange();
  6874. if(!range.collapsed && me.undoManger){
  6875. me.undoManger.save();
  6876. }
  6877. });
  6878. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  6879. domUtils.on(me.body, browser.ie || browser.opera ? 'keydown' : 'paste',function(e){
  6880. if((browser.ie || browser.opera) && (!e.ctrlKey || e.keyCode != '86')){
  6881. return;
  6882. }
  6883. getClipboardData.call( me, function( div ) {
  6884. filter(div);
  6885. } );
  6886. });
  6887. });
  6888. };
  6889. })();
  6890. ///import core
  6891. ///commands 有序列表,无序列表
  6892. ///commandsName InsertOrderedList,InsertUnorderedList
  6893. ///commandsTitle 有序列表,无序列表
  6894. /**
  6895. * 有序列表
  6896. * @function
  6897. * @name baidu.editor.execCommand
  6898. * @param {String} cmdName insertorderlist插入有序列表
  6899. * @param {String} style 值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman
  6900. * @author zhanyi
  6901. */
  6902. /**
  6903. * 无序链接
  6904. * @function
  6905. * @name baidu.editor.execCommand
  6906. * @param {String} cmdName insertunorderlist插入无序列表
  6907. * * @param {String} style 值为:circle,disc,square
  6908. * @author zhanyi
  6909. */
  6910. UE.plugins['list'] = function () {
  6911. var me = this,
  6912. notExchange = {
  6913. 'TD':1,
  6914. 'PRE':1,
  6915. 'BLOCKQUOTE':1
  6916. };
  6917. me.setOpt( {
  6918. 'insertorderedlist':{
  6919. 'decimal':'', //'1,2,3...'
  6920. 'lower-alpha':'', // 'a,b,c...'
  6921. 'lower-roman':'', //'i,ii,iii...'
  6922. 'upper-alpha':'', //'A,B,C'
  6923. 'upper-roman':'' //'I,II,III...'
  6924. },
  6925. 'insertunorderedlist':{
  6926. 'circle':'',
  6927. 'disc':'',
  6928. 'square':''
  6929. }
  6930. } );
  6931. function adjustList( list, tag, style ) {
  6932. var nextList = list.nextSibling;
  6933. if ( nextList && nextList.nodeType == 1 && nextList.tagName.toLowerCase() == tag && (domUtils.getStyle( nextList, 'list-style-type' ) || (tag == 'ol' ? 'decimal' : 'disc')) == style ) {
  6934. domUtils.moveChild( nextList, list );
  6935. if ( nextList.childNodes.length == 0 ) {
  6936. domUtils.remove( nextList );
  6937. }
  6938. }
  6939. var preList = list.previousSibling;
  6940. if ( preList && preList.nodeType == 1 && preList.tagName.toLowerCase() == tag && (domUtils.getStyle( preList, 'list-style-type' ) || (tag == 'ol' ? 'decimal' : 'disc')) == style ) {
  6941. domUtils.moveChild( list, preList );
  6942. }
  6943. if ( list.childNodes.length == 0 ) {
  6944. domUtils.remove( list );
  6945. }
  6946. }
  6947. me.addListener( 'keydown', function ( type, evt ) {
  6948. function preventAndSave() {
  6949. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  6950. me.undoManger && me.undoManger.save();
  6951. }
  6952. var keyCode = evt.keyCode || evt.which;
  6953. if ( keyCode == 13 ) {//回车
  6954. var range = me.selection.getRange(),
  6955. start = domUtils.findParentByTagName( range.startContainer, ['ol', 'ul'], true, function ( node ) {
  6956. return node.tagName == 'TABLE';
  6957. } ),
  6958. end = domUtils.findParentByTagName( range.endContainer, ['ol', 'ul'], true, function ( node ) {
  6959. return node.tagName == 'TABLE';
  6960. } );
  6961. if ( start && end && start === end ) {
  6962. if ( !range.collapsed ) {
  6963. start = domUtils.findParentByTagName( range.startContainer, 'li', true );
  6964. end = domUtils.findParentByTagName( range.endContainer, 'li', true );
  6965. if ( start && end && start === end ) {
  6966. range.deleteContents();
  6967. li = domUtils.findParentByTagName( range.startContainer, 'li', true );
  6968. if ( li && domUtils.isEmptyBlock( li ) ) {
  6969. pre = li.previousSibling;
  6970. next = li.nextSibling;
  6971. p = me.document.createElement( 'p' );
  6972. domUtils.fillNode( me.document, p );
  6973. parentList = li.parentNode;
  6974. if ( pre && next ) {
  6975. range.setStart( next, 0 ).collapse( true ).select( true );
  6976. domUtils.remove( li );
  6977. } else {
  6978. if ( !pre && !next || !pre ) {
  6979. parentList.parentNode.insertBefore( p, parentList );
  6980. } else {
  6981. li.parentNode.parentNode.insertBefore( p, parentList.nextSibling );
  6982. }
  6983. domUtils.remove( li );
  6984. if ( !parentList.firstChild ) {
  6985. domUtils.remove( parentList );
  6986. }
  6987. range.setStart( p, 0 ).setCursor();
  6988. }
  6989. preventAndSave();
  6990. return;
  6991. }
  6992. } else {
  6993. var tmpRange = range.cloneRange(),
  6994. bk = tmpRange.collapse( false ).createBookmark();
  6995. range.deleteContents();
  6996. tmpRange.moveToBookmark( bk );
  6997. var li = domUtils.findParentByTagName( tmpRange.startContainer, 'li', true ),
  6998. pre = li.previousSibling,
  6999. next = li.nextSibling;
  7000. if ( pre ) {
  7001. li = pre;
  7002. if ( pre.firstChild && domUtils.isBlockElm( pre.firstChild ) ) {
  7003. pre = pre.firstChild;
  7004. }
  7005. if ( domUtils.isEmptyNode( pre ) ){
  7006. domUtils.remove( li );
  7007. }
  7008. }
  7009. if ( next ) {
  7010. li = next;
  7011. if ( next.firstChild && domUtils.isBlockElm( next.firstChild ) ) {
  7012. next = next.firstChild;
  7013. }
  7014. if ( domUtils.isEmptyNode( next ) ){
  7015. domUtils.remove( li );
  7016. }
  7017. }
  7018. tmpRange.select();
  7019. preventAndSave();
  7020. return;
  7021. }
  7022. }
  7023. li = domUtils.findParentByTagName( range.startContainer, 'li', true );
  7024. if ( li ) {
  7025. if ( domUtils.isEmptyBlock( li ) ) {
  7026. bk = range.createBookmark();
  7027. var parentList = li.parentNode;
  7028. if ( li !== parentList.lastChild ) {
  7029. domUtils.breakParent( li, parentList );
  7030. } else {
  7031. parentList.parentNode.insertBefore( li, parentList.nextSibling );
  7032. if ( domUtils.isEmptyNode( parentList ) ) {
  7033. domUtils.remove( parentList );
  7034. }
  7035. }
  7036. //嵌套不处理
  7037. if ( !dtd.$list[li.parentNode.tagName] ) {
  7038. if ( !domUtils.isBlockElm( li.firstChild ) ) {
  7039. p = me.document.createElement( 'p' );
  7040. li.parentNode.insertBefore( p, li );
  7041. while ( li.firstChild ) {
  7042. p.appendChild( li.firstChild );
  7043. }
  7044. domUtils.remove( li );
  7045. } else {
  7046. domUtils.remove( li, true );
  7047. }
  7048. }
  7049. range.moveToBookmark( bk ).select();
  7050. } else {
  7051. var first = li.firstChild;
  7052. if ( !first || !domUtils.isBlockElm( first ) ) {
  7053. var p = me.document.createElement( 'p' );
  7054. !li.firstChild && domUtils.fillNode( me.document, p );
  7055. while ( li.firstChild ) {
  7056. p.appendChild( li.firstChild );
  7057. }
  7058. li.appendChild( p );
  7059. first = p;
  7060. }
  7061. var span = me.document.createElement( 'span' );
  7062. range.insertNode( span );
  7063. domUtils.breakParent( span, li );
  7064. var nextLi = span.nextSibling;
  7065. first = nextLi.firstChild;
  7066. if ( !first ) {
  7067. p = me.document.createElement( 'p' );
  7068. domUtils.fillNode( me.document, p );
  7069. nextLi.appendChild( p );
  7070. first = p;
  7071. }
  7072. if ( domUtils.isEmptyNode( first ) ) {
  7073. first.innerHTML = '';
  7074. domUtils.fillNode( me.document, first );
  7075. }
  7076. range.setStart( first, 0 ).collapse( true ).shrinkBoundary().select();
  7077. domUtils.remove( span );
  7078. pre = nextLi.previousSibling;
  7079. if ( pre && domUtils.isEmptyBlock( pre ) ) {
  7080. pre.innerHTML = '<p></p>';
  7081. domUtils.fillNode( me.document, pre.firstChild );
  7082. }
  7083. }
  7084. // }
  7085. preventAndSave();
  7086. }
  7087. }
  7088. }
  7089. if ( keyCode == 8 ) {
  7090. //修中ie中li下的问题
  7091. range = me.selection.getRange();
  7092. if ( range.collapsed && domUtils.isStartInblock( range ) ) {
  7093. tmpRange = range.cloneRange().trimBoundary();
  7094. li = domUtils.findParentByTagName( range.startContainer, 'li', true );
  7095. //要在li的最左边,才能处理
  7096. if ( li && domUtils.isStartInblock( tmpRange ) ) {
  7097. if ( li && (pre = li.previousSibling) ) {
  7098. if ( keyCode == 46 && li.childNodes.length ){
  7099. return;
  7100. }
  7101. //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
  7102. if ( dtd.$list[pre.tagName] ) {
  7103. pre = pre.lastChild;
  7104. }
  7105. me.undoManger && me.undoManger.save();
  7106. first = li.firstChild;
  7107. if ( domUtils.isBlockElm( first ) ) {
  7108. if ( domUtils.isEmptyNode( first ) ) {
  7109. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  7110. pre.appendChild( first );
  7111. range.setStart( first, 0 ).setCursor( false, true );
  7112. //first不是唯一的节点
  7113. while ( li.firstChild ) {
  7114. pre.appendChild( li.firstChild );
  7115. }
  7116. } else {
  7117. start = domUtils.findParentByTagName( range.startContainer, 'p', true );
  7118. if ( start && start !== first ) {
  7119. return;
  7120. }
  7121. span = me.document.createElement( 'span' );
  7122. range.insertNode( span );
  7123. //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
  7124. if(domUtils.isEmptyBlock(pre)){
  7125. pre.innerHTML = '';
  7126. }
  7127. domUtils.moveChild( li, pre );
  7128. range.setStartBefore( span ).collapse( true ).select( true );
  7129. domUtils.remove( span );
  7130. }
  7131. } else {
  7132. if ( domUtils.isEmptyNode( li ) ) {
  7133. var p = me.document.createElement( 'p' );
  7134. pre.appendChild( p );
  7135. range.setStart( p, 0 ).setCursor();
  7136. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  7137. } else {
  7138. range.setEnd( pre, pre.childNodes.length ).collapse().select( true );
  7139. while ( li.firstChild ) {
  7140. pre.appendChild( li.firstChild );
  7141. }
  7142. }
  7143. }
  7144. domUtils.remove( li );
  7145. me.undoManger && me.undoManger.save();
  7146. domUtils.preventDefault( evt );
  7147. return;
  7148. }
  7149. //trace:980
  7150. if ( li && !li.previousSibling ) {
  7151. first = li.firstChild;
  7152. //trace:1648 要判断li下只有一个节点
  7153. if ( !first || li.lastChild === first && domUtils.isEmptyNode( domUtils.isBlockElm( first ) ? first : li ) ) {
  7154. var p = me.document.createElement( 'p' );
  7155. li.parentNode.parentNode.insertBefore( p, li.parentNode );
  7156. domUtils.fillNode( me.document, p );
  7157. range.setStart( p, 0 ).setCursor();
  7158. domUtils.remove( !li.nextSibling ? li.parentNode : li );
  7159. me.undoManger && me.undoManger.save();
  7160. domUtils.preventDefault( evt );
  7161. return;
  7162. }
  7163. }
  7164. }
  7165. }
  7166. }
  7167. } );
  7168. me.commands['insertorderedlist'] =
  7169. me.commands['insertunorderedlist'] = {
  7170. execCommand:function ( command, style ) {
  7171. if ( !style ) {
  7172. style = command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc';
  7173. }
  7174. var me = this,
  7175. range = this.selection.getRange(),
  7176. filterFn = function ( node ) {
  7177. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace( node );
  7178. },
  7179. tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul',
  7180. frag = me.document.createDocumentFragment();
  7181. //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
  7182. //range.shrinkBoundary();//.adjustmentBoundary();
  7183. range.adjustmentBoundary().shrinkBoundary();
  7184. var bko = range.createBookmark( true ),
  7185. start = domUtils.findParentByTagName( me.document.getElementById( bko.start ), 'li' ),
  7186. modifyStart = 0,
  7187. end = domUtils.findParentByTagName( me.document.getElementById( bko.end ), 'li' ),
  7188. modifyEnd = 0,
  7189. startParent, endParent,
  7190. list, tmp;
  7191. if ( start || end ) {
  7192. start && (startParent = start.parentNode);
  7193. if ( !bko.end ) {
  7194. end = start;
  7195. }
  7196. end && (endParent = end.parentNode);
  7197. if ( startParent === endParent ) {
  7198. while ( start !== end ) {
  7199. tmp = start;
  7200. start = start.nextSibling;
  7201. if ( !domUtils.isBlockElm( tmp.firstChild ) ) {
  7202. var p = me.document.createElement( 'p' );
  7203. while ( tmp.firstChild ) {
  7204. p.appendChild( tmp.firstChild );
  7205. }
  7206. tmp.appendChild( p );
  7207. }
  7208. frag.appendChild( tmp );
  7209. }
  7210. tmp = me.document.createElement( 'span' );
  7211. startParent.insertBefore( tmp, end );
  7212. if ( !domUtils.isBlockElm( end.firstChild ) ) {
  7213. p = me.document.createElement( 'p' );
  7214. while ( end.firstChild ) {
  7215. p.appendChild( end.firstChild );
  7216. }
  7217. end.appendChild( p );
  7218. }
  7219. frag.appendChild( end );
  7220. domUtils.breakParent( tmp, startParent );
  7221. if ( domUtils.isEmptyNode( tmp.previousSibling ) ) {
  7222. domUtils.remove( tmp.previousSibling );
  7223. }
  7224. if ( domUtils.isEmptyNode( tmp.nextSibling ) ) {
  7225. domUtils.remove( tmp.nextSibling )
  7226. }
  7227. var nodeStyle = domUtils.getComputedStyle( startParent, 'list-style-type' ) || (command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc');
  7228. if ( startParent.tagName.toLowerCase() == tag && nodeStyle == style ) {
  7229. for ( var i = 0, ci, tmpFrag = me.document.createDocumentFragment(); ci = frag.childNodes[i++]; ) {
  7230. while ( ci.firstChild ) {
  7231. tmpFrag.appendChild( ci.firstChild );
  7232. }
  7233. }
  7234. tmp.parentNode.insertBefore( tmpFrag, tmp );
  7235. } else {
  7236. list = me.document.createElement( tag );
  7237. domUtils.setStyle( list, 'list-style-type', style );
  7238. list.appendChild( frag );
  7239. tmp.parentNode.insertBefore( list, tmp );
  7240. }
  7241. domUtils.remove( tmp );
  7242. list && adjustList( list, tag, style );
  7243. range.moveToBookmark( bko ).select();
  7244. return;
  7245. }
  7246. //开始
  7247. if ( start ) {
  7248. while ( start ) {
  7249. tmp = start.nextSibling;
  7250. var tmpfrag = me.document.createDocumentFragment(),
  7251. hasBlock = 0;
  7252. while ( start.firstChild ) {
  7253. if ( domUtils.isBlockElm( start.firstChild ) ){
  7254. hasBlock = 1;
  7255. }
  7256. tmpfrag.appendChild( start.firstChild );
  7257. }
  7258. if ( !hasBlock ) {
  7259. var tmpP = me.document.createElement( 'p' );
  7260. tmpP.appendChild( tmpfrag );
  7261. frag.appendChild( tmpP );
  7262. } else {
  7263. frag.appendChild( tmpfrag );
  7264. }
  7265. domUtils.remove( start );
  7266. start = tmp;
  7267. }
  7268. startParent.parentNode.insertBefore( frag, startParent.nextSibling );
  7269. if ( domUtils.isEmptyNode( startParent ) ) {
  7270. range.setStartBefore( startParent );
  7271. domUtils.remove( startParent );
  7272. } else {
  7273. range.setStartAfter( startParent );
  7274. }
  7275. modifyStart = 1;
  7276. }
  7277. if ( end ) {
  7278. //结束
  7279. start = endParent.firstChild;
  7280. while ( start !== end ) {
  7281. tmp = start.nextSibling;
  7282. tmpfrag = me.document.createDocumentFragment();
  7283. hasBlock = 0;
  7284. while ( start.firstChild ) {
  7285. if ( domUtils.isBlockElm( start.firstChild ) ){
  7286. hasBlock = 1;
  7287. }
  7288. tmpfrag.appendChild( start.firstChild );
  7289. }
  7290. if ( !hasBlock ) {
  7291. tmpP = me.document.createElement( 'p' );
  7292. tmpP.appendChild( tmpfrag );
  7293. frag.appendChild( tmpP );
  7294. } else {
  7295. frag.appendChild( tmpfrag );
  7296. }
  7297. domUtils.remove( start );
  7298. start = tmp;
  7299. }
  7300. frag.appendChild( end.firstChild );
  7301. domUtils.remove( end );
  7302. endParent.parentNode.insertBefore( frag, endParent );
  7303. range.setEndBefore( endParent );
  7304. if ( domUtils.isEmptyNode( endParent ) ) {
  7305. domUtils.remove( endParent );
  7306. }
  7307. modifyEnd = 1;
  7308. }
  7309. }
  7310. if ( !modifyStart ) {
  7311. range.setStartBefore( me.document.getElementById( bko.start ) );
  7312. }
  7313. if ( bko.end && !modifyEnd ) {
  7314. range.setEndAfter( me.document.getElementById( bko.end ) );
  7315. }
  7316. range.enlarge( true, function ( node ) {
  7317. return notExchange[node.tagName];
  7318. } );
  7319. frag = me.document.createDocumentFragment();
  7320. var bk = range.createBookmark(),
  7321. current = domUtils.getNextDomNode( bk.start, false, filterFn ),
  7322. tmpRange = range.cloneRange(),
  7323. tmpNode,
  7324. block = domUtils.isBlockElm;
  7325. while ( current && current !== bk.end && (domUtils.getPosition( current, bk.end ) & domUtils.POSITION_PRECEDING) ) {
  7326. if ( current.nodeType == 3 || dtd.li[current.tagName] ) {
  7327. if ( current.nodeType == 1 && dtd.$list[current.tagName] ) {
  7328. while ( current.firstChild ) {
  7329. frag.appendChild( current.firstChild );
  7330. }
  7331. tmpNode = domUtils.getNextDomNode( current, false, filterFn );
  7332. domUtils.remove( current );
  7333. current = tmpNode;
  7334. continue;
  7335. }
  7336. tmpNode = current;
  7337. tmpRange.setStartBefore( current );
  7338. while ( current && current !== bk.end && (!block( current ) || domUtils.isBookmarkNode( current ) ) ) {
  7339. tmpNode = current;
  7340. current = domUtils.getNextDomNode( current, false, null, function ( node ) {
  7341. return !notExchange[node.tagName];
  7342. } );
  7343. }
  7344. if ( current && block( current ) ) {
  7345. tmp = domUtils.getNextDomNode( tmpNode, false, filterFn );
  7346. if ( tmp && domUtils.isBookmarkNode( tmp ) ) {
  7347. current = domUtils.getNextDomNode( tmp, false, filterFn );
  7348. tmpNode = tmp;
  7349. }
  7350. }
  7351. tmpRange.setEndAfter( tmpNode );
  7352. current = domUtils.getNextDomNode( tmpNode, false, filterFn );
  7353. var li = range.document.createElement( 'li' );
  7354. li.appendChild( tmpRange.extractContents() );
  7355. frag.appendChild( li );
  7356. } else {
  7357. current = domUtils.getNextDomNode( current, true, filterFn );
  7358. }
  7359. }
  7360. range.moveToBookmark( bk ).collapse( true );
  7361. list = me.document.createElement( tag );
  7362. domUtils.setStyle( list, 'list-style-type', style );
  7363. list.appendChild( frag );
  7364. range.insertNode( list );
  7365. //当前list上下看能否合并
  7366. adjustList( list, tag, style );
  7367. range.moveToBookmark( bko ).select();
  7368. },
  7369. queryCommandState:function ( command ) {
  7370. return this.highlight ? -1 :
  7371. utils.findNode( this.selection.getStartElementPath(), [command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul'] ) ? 1 : 0;
  7372. },
  7373. queryCommandValue:function ( command ) {
  7374. var node = utils.findNode( this.selection.getStartElementPath(), [command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul'] );
  7375. return node ? domUtils.getComputedStyle( node, 'list-style-type' ) : null;
  7376. }
  7377. };
  7378. };
  7379. ///import core
  7380. ///import plugins/serialize.js
  7381. ///import plugins/undo.js
  7382. ///commands 查看源码
  7383. ///commandsName Source
  7384. ///commandsTitle 查看源码
  7385. (function (){
  7386. function SourceFormater(config){
  7387. config = config || {};
  7388. this.indentChar = config.indentChar || ' ';
  7389. this.breakChar = config.breakChar || '\n';
  7390. this.selfClosingEnd = config.selfClosingEnd || ' />';
  7391. }
  7392. var unhtml1 = function (){
  7393. var map = { '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
  7394. function rep( m ){ return map[m]; }
  7395. return function ( str ) {
  7396. str = str + '';
  7397. return str ? str.replace( /[<>"']/g, rep ) : '';
  7398. };
  7399. }();
  7400. var inline = utils.extend({a:1,A:1},dtd.$inline,true);
  7401. function printAttrs(attrs){
  7402. var buff = [];
  7403. for (var k in attrs) {
  7404. buff.push(k + '="' + unhtml1(attrs[k]) + '"');
  7405. }
  7406. return buff.join(' ');
  7407. }
  7408. SourceFormater.prototype = {
  7409. format: function (html){
  7410. var node = UE.serialize.parseHTML(html);
  7411. this.buff = [];
  7412. this.indents = '';
  7413. this.indenting = 1;
  7414. this.visitNode(node);
  7415. return this.buff.join('');
  7416. },
  7417. visitNode: function (node){
  7418. if (node.type == 'fragment') {
  7419. this.visitChildren(node.children);
  7420. } else if (node.type == 'element') {
  7421. var selfClosing = dtd.$empty[node.tag];
  7422. this.visitTag(node.tag, node.attributes, selfClosing);
  7423. this.visitChildren(node.children);
  7424. if (!selfClosing) {
  7425. this.visitEndTag(node.tag);
  7426. }
  7427. } else if (node.type == 'comment') {
  7428. this.visitComment(node.data);
  7429. } else {
  7430. this.visitText(node.data,dtd.$notTransContent[node.parent.tag]);
  7431. }
  7432. },
  7433. visitChildren: function (children){
  7434. for (var i=0; i<children.length; i++) {
  7435. this.visitNode(children[i]);
  7436. }
  7437. },
  7438. visitTag: function (tag, attrs, selfClosing){
  7439. if (this.indenting) {
  7440. this.indent();
  7441. } else if (!inline[tag]) { // todo: 去掉a, 因为dtd的inline里面没有a
  7442. this.newline();
  7443. this.indent();
  7444. }
  7445. this.buff.push('<', tag);
  7446. var attrPart = printAttrs(attrs);
  7447. if (attrPart) {
  7448. this.buff.push(' ', attrPart);
  7449. }
  7450. if (selfClosing) {
  7451. this.buff.push(this.selfClosingEnd);
  7452. if (tag == 'br') {
  7453. this.newline();
  7454. }
  7455. } else {
  7456. this.buff.push('>');
  7457. this.indents += this.indentChar;
  7458. }
  7459. if (!inline[tag]) {
  7460. this.newline();
  7461. }
  7462. },
  7463. indent: function (){
  7464. this.buff.push(this.indents);
  7465. this.indenting = 0;
  7466. },
  7467. newline: function (){
  7468. this.buff.push(this.breakChar);
  7469. this.indenting = 1;
  7470. },
  7471. visitEndTag: function (tag){
  7472. this.indents = this.indents.slice(0, -this.indentChar.length);
  7473. if (this.indenting) {
  7474. this.indent();
  7475. } else if (!inline[tag]) {
  7476. this.newline();
  7477. this.indent();
  7478. }
  7479. this.buff.push('</', tag, '>');
  7480. },
  7481. visitText: function (text,notTrans){
  7482. if (this.indenting) {
  7483. this.indent();
  7484. }
  7485. // if(!notTrans){
  7486. // text = text.replace(/&nbsp;/g, ' ').replace(/[ ][ ]+/g, function (m){
  7487. // return new Array(m.length + 1).join('&nbsp;');
  7488. // }).replace(/(?:^ )|(?: $)/g, '&nbsp;');
  7489. // }
  7490. text = text.replace(/&nbsp;/g, ' ');
  7491. this.buff.push(text);
  7492. },
  7493. visitComment: function (text){
  7494. if (this.indenting) {
  7495. this.indent();
  7496. }
  7497. this.buff.push('<!--', text, '-->');
  7498. }
  7499. };
  7500. var sourceEditors = {
  7501. textarea: function (editor, holder){
  7502. var textarea = holder.ownerDocument.createElement('textarea');
  7503. textarea.style.cssText = 'position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;';
  7504. // todo: IE下只有onresize属性可用... 很纠结
  7505. if (browser.ie && browser.version < 8) {
  7506. textarea.style.width = holder.offsetWidth + 'px';
  7507. textarea.style.height = holder.offsetHeight + 'px';
  7508. holder.onresize = function (){
  7509. textarea.style.width = holder.offsetWidth + 'px';
  7510. textarea.style.height = holder.offsetHeight + 'px';
  7511. };
  7512. }
  7513. holder.appendChild(textarea);
  7514. return {
  7515. setContent: function (content){
  7516. textarea.value = content;
  7517. },
  7518. getContent: function (){
  7519. return textarea.value;
  7520. },
  7521. select: function (){
  7522. var range;
  7523. if (browser.ie) {
  7524. range = textarea.createTextRange();
  7525. range.collapse(true);
  7526. range.select();
  7527. } else {
  7528. //todo: chrome下无法设置焦点
  7529. textarea.setSelectionRange(0, 0);
  7530. textarea.focus();
  7531. }
  7532. },
  7533. dispose: function (){
  7534. holder.removeChild(textarea);
  7535. // todo
  7536. holder.onresize = null;
  7537. textarea = null;
  7538. holder = null;
  7539. }
  7540. };
  7541. },
  7542. codemirror: function (editor, holder){
  7543. var options = {
  7544. mode: "text/html",
  7545. tabMode: "indent",
  7546. lineNumbers: true,
  7547. lineWrapping:true
  7548. };
  7549. var codeEditor = window.CodeMirror(holder, options);
  7550. var dom = codeEditor.getWrapperElement();
  7551. dom.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
  7552. codeEditor.getScrollerElement().style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;';
  7553. codeEditor.refresh();
  7554. return {
  7555. setContent: function (content){
  7556. codeEditor.setValue(content);
  7557. },
  7558. getContent: function (){
  7559. return codeEditor.getValue();
  7560. },
  7561. select: function (){
  7562. codeEditor.focus();
  7563. },
  7564. dispose: function (){
  7565. holder.removeChild(dom);
  7566. dom = null;
  7567. codeEditor = null;
  7568. }
  7569. };
  7570. }
  7571. };
  7572. UE.plugins['source'] = function (){
  7573. var me = this;
  7574. var opt = this.options;
  7575. var formatter = new SourceFormater(opt.source);
  7576. var sourceMode = false;
  7577. var sourceEditor;
  7578. opt.sourceEditor = opt.sourceEditor || 'codemirror';
  7579. me.setOpt({
  7580. sourceEditorFirst:false
  7581. });
  7582. function createSourceEditor(holder){
  7583. return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder);
  7584. }
  7585. var bakCssText;
  7586. me.commands['source'] = {
  7587. execCommand: function (){
  7588. sourceMode = !sourceMode;
  7589. if (sourceMode) {
  7590. me.undoManger && me.undoManger.save();
  7591. this.currentSelectedArr && domUtils.clearSelectedArr(this.currentSelectedArr);
  7592. if(browser.gecko){
  7593. me.body.contentEditable = false;
  7594. }
  7595. bakCssText = me.iframe.style.cssText;
  7596. me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;';
  7597. var content = formatter.format(me.hasContents() ? me.getContent() : '');
  7598. sourceEditor = createSourceEditor(me.iframe.parentNode);
  7599. sourceEditor.setContent(content);
  7600. setTimeout(function (){
  7601. sourceEditor.select();
  7602. });
  7603. } else {
  7604. me.iframe.style.cssText = bakCssText;
  7605. var cont = sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>')+'</p>';
  7606. cont = cont.replace(/>[\n\r\t]+([ ]{4})+/g,'>').replace(/[\n\r\t]+([ ]{4})+</g,'<').replace(/>[\n\r\t]+</g,'><');
  7607. me.setContent(cont);
  7608. sourceEditor.dispose();
  7609. sourceEditor = null;
  7610. setTimeout(function(){
  7611. var first = me.body.firstChild;
  7612. //trace:1106 都删除空了,下边会报错,所以补充一个p占位
  7613. if(!first){
  7614. me.body.innerHTML = '<p>'+(browser.ie?'':'<br/>')+'</p>';
  7615. first = me.body.firstChild;
  7616. }
  7617. //要在ifm为显示时ff才能取到selection,否则报错
  7618. me.undoManger && me.undoManger.save();
  7619. while(first && first.firstChild){
  7620. first = first.firstChild;
  7621. }
  7622. var range = me.selection.getRange();
  7623. if(first.nodeType == 3 || dtd.$empty[first.tagName]){
  7624. range.setStartBefore(first);
  7625. }else{
  7626. range.setStart(first,0);
  7627. }
  7628. if(browser.gecko){
  7629. var input = document.createElement('input');
  7630. input.style.cssText = 'position:absolute;left:0;top:-32768px';
  7631. document.body.appendChild(input);
  7632. me.body.contentEditable = false;
  7633. setTimeout(function(){
  7634. domUtils.setViewportOffset(input, { left: -32768, top: 0 });
  7635. input.focus();
  7636. setTimeout(function(){
  7637. me.body.contentEditable = true;
  7638. range.setCursor(false,true);
  7639. domUtils.remove(input);
  7640. });
  7641. });
  7642. }else{
  7643. range.setCursor(false,true);
  7644. }
  7645. });
  7646. }
  7647. this.fireEvent('sourcemodechanged', sourceMode);
  7648. },
  7649. queryCommandState: function (){
  7650. return sourceMode|0;
  7651. },
  7652. notNeedUndo : 1
  7653. };
  7654. var oldQueryCommandState = me.queryCommandState;
  7655. me.queryCommandState = function (cmdName){
  7656. cmdName = cmdName.toLowerCase();
  7657. if (sourceMode) {
  7658. return cmdName == 'source' ? 1 : -1;
  7659. }
  7660. return oldQueryCommandState.apply(this, arguments);
  7661. };
  7662. //解决在源码模式下getContent不能得到最新的内容问题
  7663. var oldGetContent = me.getContent;
  7664. me.getContent = function (){
  7665. if(sourceMode && sourceEditor ){
  7666. var html = sourceEditor.getContent();
  7667. if (this.serialize) {
  7668. var node = this.serialize.parseHTML(html);
  7669. node = this.serialize.filter(node);
  7670. html = this.serialize.toHTML(node);
  7671. }
  7672. return html;
  7673. }else{
  7674. return oldGetContent.apply(this, arguments);
  7675. }
  7676. };
  7677. if(opt.sourceEditor == "codemirror"){
  7678. me.addListener("ready",function(){
  7679. utils.loadFile(document,{
  7680. src : opt.codeMirrorJsUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror2.15/codemirror.js",
  7681. tag : "script",
  7682. type : "text/javascript",
  7683. defer : "defer"
  7684. },function(){
  7685. if(opt.sourceEditorFirst){
  7686. setTimeout(function(){
  7687. me.execCommand("source");
  7688. },0);
  7689. }
  7690. });
  7691. utils.loadFile(document,{
  7692. tag : "link",
  7693. rel : "stylesheet",
  7694. type : "text/css",
  7695. href : opt.codeMirrorCssUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror2.15/codemirror.css"
  7696. });
  7697. });
  7698. }
  7699. };
  7700. })();
  7701. ///import core
  7702. ///commands 快捷键
  7703. ///commandsName ShortCutKeys
  7704. ///commandsTitle 快捷键
  7705. //配置快捷键
  7706. UE.plugins['shortcutkeys'] = function(){
  7707. var me = this,
  7708. shortcutkeys = {
  7709. "ctrl+66" : "Bold" ,//^B
  7710. "ctrl+90" : "Undo" ,//undo
  7711. "ctrl+89" : "Redo", //redo
  7712. "ctrl+73" : "Italic", //^I
  7713. "ctrl+85" : "Underline" ,//^U
  7714. "ctrl+shift+67" : "removeformat", //清除格式
  7715. "ctrl+shift+76" : "justify:left", //居左
  7716. "ctrl+shift+82" : "justify:right", //居右
  7717. "ctrl+65" : "selectAll",
  7718. "ctrl+13" : "autosubmit"//手动提交
  7719. // ,"9" : "indent" //tab
  7720. };
  7721. me.addListener('keydown',function(type,e){
  7722. var keyCode = e.keyCode || e.which,value;
  7723. for ( var i in shortcutkeys ) {
  7724. if ( /^(ctrl)(\+shift)?\+(\d+)$/.test( i.toLowerCase() ) || /^(\d+)$/.test( i ) ) {
  7725. if ( ( (RegExp.$1 == 'ctrl' ? (e.ctrlKey||e.metaKey||browser.opera && keyCode == 17) : 0)
  7726. && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1)
  7727. && keyCode == RegExp.$3
  7728. ) ||
  7729. keyCode == RegExp.$1
  7730. ){
  7731. value = shortcutkeys[i].split(':');
  7732. me.execCommand( value[0],value[1]);
  7733. domUtils.preventDefault(e);
  7734. }
  7735. }
  7736. }
  7737. });
  7738. };
  7739. ///import core
  7740. ///import plugins/undo.js
  7741. ///commands 设置回车标签p或br
  7742. ///commandsName EnterKey
  7743. ///commandsTitle 设置回车标签p或br
  7744. /**
  7745. * @description 处理回车
  7746. * @author zhanyi
  7747. */
  7748. UE.plugins['enterkey'] = function() {
  7749. var hTag,
  7750. me = this,
  7751. tag = me.options.enterTag;
  7752. me.addListener('keyup', function(type, evt) {
  7753. var keyCode = evt.keyCode || evt.which;
  7754. if (keyCode == 13) {
  7755. var range = me.selection.getRange(),
  7756. start = range.startContainer,
  7757. doSave;
  7758. //修正在h1-h6里边回车后不能嵌套p的问题
  7759. if (!browser.ie) {
  7760. if (/h\d/i.test(hTag)) {
  7761. if (browser.gecko) {
  7762. var h = domUtils.findParentByTagName(start, [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6','blockquote'], true);
  7763. if (!h) {
  7764. me.document.execCommand('formatBlock', false, '<p>');
  7765. doSave = 1;
  7766. }
  7767. } else {
  7768. //chrome remove div
  7769. if (start.nodeType == 1) {
  7770. var tmp = me.document.createTextNode(''),div;
  7771. range.insertNode(tmp);
  7772. div = domUtils.findParentByTagName(tmp, 'div', true);
  7773. if (div) {
  7774. var p = me.document.createElement('p');
  7775. while (div.firstChild) {
  7776. p.appendChild(div.firstChild);
  7777. }
  7778. div.parentNode.insertBefore(p, div);
  7779. domUtils.remove(div);
  7780. range.setStartBefore(tmp).setCursor();
  7781. doSave = 1;
  7782. }
  7783. domUtils.remove(tmp);
  7784. }
  7785. }
  7786. if (me.undoManger && doSave) {
  7787. me.undoManger.save();
  7788. }
  7789. }
  7790. //没有站位符,会出现多行的问题
  7791. browser.opera && range.select();
  7792. }
  7793. setTimeout(function() {
  7794. me.selection.getRange().scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0);
  7795. }, 50);
  7796. }
  7797. });
  7798. me.addListener('keydown', function(type, evt) {
  7799. var keyCode = evt.keyCode || evt.which;
  7800. if (keyCode == 13) {//回车
  7801. if (me.undoManger) {
  7802. me.undoManger.save();
  7803. }
  7804. hTag = '';
  7805. var range = me.selection.getRange();
  7806. if (!range.collapsed) {
  7807. //跨td不能删
  7808. var start = range.startContainer,
  7809. end = range.endContainer,
  7810. startTd = domUtils.findParentByTagName(start, 'td', true),
  7811. endTd = domUtils.findParentByTagName(end, 'td', true);
  7812. if (startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !endTd) {
  7813. evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false);
  7814. return;
  7815. }
  7816. }
  7817. me.currentSelectedArr && domUtils.clearSelectedArr(me.currentSelectedArr);
  7818. if (tag == 'p') {
  7819. if (!browser.ie) {
  7820. start = domUtils.findParentByTagName(range.startContainer, ['ol','ul','p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6','blockquote'], true);
  7821. //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
  7822. //trace:2431
  7823. if (!start && !browser.opera) {
  7824. me.document.execCommand('formatBlock', false, '<p>');
  7825. if (browser.gecko) {
  7826. range = me.selection.getRange();
  7827. start = domUtils.findParentByTagName(range.startContainer, 'p', true);
  7828. start && domUtils.removeDirtyAttr(start);
  7829. }
  7830. } else {
  7831. hTag = start.tagName;
  7832. start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start);
  7833. }
  7834. }
  7835. } else {
  7836. evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false);
  7837. if (!range.collapsed) {
  7838. range.deleteContents();
  7839. start = range.startContainer;
  7840. if (start.nodeType == 1 && (start = start.childNodes[range.startOffset])) {
  7841. while (start.nodeType == 1) {
  7842. if (dtd.$empty[start.tagName]) {
  7843. range.setStartBefore(start).setCursor();
  7844. if (me.undoManger) {
  7845. me.undoManger.save();
  7846. }
  7847. return false;
  7848. }
  7849. if (!start.firstChild) {
  7850. var br = range.document.createElement('br');
  7851. start.appendChild(br);
  7852. range.setStart(start, 0).setCursor();
  7853. if (me.undoManger) {
  7854. me.undoManger.save();
  7855. }
  7856. return false;
  7857. }
  7858. start = start.firstChild;
  7859. }
  7860. if (start === range.startContainer.childNodes[range.startOffset]) {
  7861. br = range.document.createElement('br');
  7862. range.insertNode(br).setCursor();
  7863. } else {
  7864. range.setStart(start, 0).setCursor();
  7865. }
  7866. } else {
  7867. br = range.document.createElement('br');
  7868. range.insertNode(br).setStartAfter(br).setCursor();
  7869. }
  7870. } else {
  7871. br = range.document.createElement('br');
  7872. range.insertNode(br);
  7873. var parent = br.parentNode;
  7874. if (parent.lastChild === br) {
  7875. br.parentNode.insertBefore(br.cloneNode(true), br);
  7876. range.setStartBefore(br);
  7877. } else {
  7878. range.setStartAfter(br);
  7879. }
  7880. range.setCursor();
  7881. }
  7882. }
  7883. }
  7884. });
  7885. };
  7886. /*
  7887. * 处理特殊键的兼容性问题
  7888. */
  7889. UE.plugins['keystrokes'] = function() {
  7890. var me = this,
  7891. flag = 0,
  7892. keys = domUtils.keys,
  7893. trans = {
  7894. 'B' : 'strong',
  7895. 'I' : 'em',
  7896. 'FONT' : 'span'
  7897. },
  7898. sizeMap = [0, 10, 12, 16, 18, 24, 32, 48],
  7899. listStyle = {
  7900. 'OL':['decimal','lower-alpha','lower-roman','upper-alpha','upper-roman'],
  7901. 'UL':[ 'circle','disc','square']
  7902. };
  7903. me.addListener('keydown', function(type, evt) {
  7904. var keyCode = evt.keyCode || evt.which;
  7905. if(this.selectAll){
  7906. this.selectAll = false;
  7907. if((keyCode == 8 || keyCode == 46)){
  7908. me.undoManger && me.undoManger.save();
  7909. //trace:1633
  7910. me.body.innerHTML = '<p>'+(browser.ie ? '' : '<br/>')+'</p>';
  7911. new dom.Range(me.document).setStart(me.body.firstChild,0).setCursor(false,true);
  7912. me.undoManger && me.undoManger.save();
  7913. //todo 对性能会有影响
  7914. browser.ie && me._selectionChange();
  7915. domUtils.preventDefault(evt);
  7916. return;
  7917. }
  7918. }
  7919. //处理backspace/del
  7920. if (keyCode == 8 ) {//|| keyCode == 46
  7921. var range = me.selection.getRange(),
  7922. tmpRange,
  7923. start,end;
  7924. //当删除到body最开始的位置时,会删除到body,阻止这个动作
  7925. if(range.collapsed){
  7926. start = range.startContainer;
  7927. //有可能是展位符号
  7928. if(domUtils.isWhitespace(start)){
  7929. start = start.parentNode;
  7930. }
  7931. if(domUtils.isEmptyNode(start) && start === me.body.firstChild){
  7932. if(start.tagName != 'P'){
  7933. p = me.document.createElement('p');
  7934. me.body.insertBefore(p,start);
  7935. domUtils.fillNode(me.document,p);
  7936. range.setStart(p,0).setCursor(false,true);
  7937. //trace:1645
  7938. domUtils.remove(start);
  7939. }
  7940. domUtils.preventDefault(evt);
  7941. return;
  7942. }
  7943. }
  7944. if (range.collapsed && range.startContainer.nodeType == 3 && range.startContainer.nodeValue.replace(new RegExp(domUtils.fillChar, 'g'), '').length == 0) {
  7945. range.setStartBefore(range.startContainer).collapse(true);
  7946. }
  7947. //解决选中control元素不能删除的问题
  7948. if (start = range.getClosedNode()) {
  7949. me.undoManger && me.undoManger.save();
  7950. range.setStartBefore(start);
  7951. domUtils.remove(start);
  7952. range.setCursor();
  7953. me.undoManger && me.undoManger.save();
  7954. domUtils.preventDefault(evt);
  7955. return;
  7956. }
  7957. //阻止在table上的删除
  7958. if (!browser.ie) {
  7959. start = domUtils.findParentByTagName(range.startContainer, 'table', true);
  7960. end = domUtils.findParentByTagName(range.endContainer, 'table', true);
  7961. if (start && !end || !start && end || start !== end) {
  7962. evt.preventDefault();
  7963. return;
  7964. }
  7965. //表格里回车,删除时,光标被定位到了p外边,导致多次删除才能到上一行,这里的处理忘记是为什么,暂时注视掉
  7966. //解决trace:1966的问题
  7967. // if (browser.webkit && range.collapsed && start) {
  7968. // tmpRange = range.cloneRange().txtToElmBoundary();
  7969. // start = tmpRange.startContainer;
  7970. // debugger
  7971. // if (domUtils.isBlockElm(start) && !dtd.$tableContent[start.tagName] && !domUtils.getChildCount(start, function(node) {
  7972. // return node.nodeType == 1 ? node.tagName !== 'BR' : 1;
  7973. // })) {
  7974. //
  7975. // tmpRange.setStartBefore(start).setCursor();
  7976. // domUtils.remove(start, true);
  7977. // evt.preventDefault();
  7978. // return;
  7979. // }
  7980. // }
  7981. }
  7982. if (me.undoManger) {
  7983. if (!range.collapsed) {
  7984. me.undoManger.save();
  7985. flag = 1;
  7986. }
  7987. }
  7988. }
  7989. //处理tab键的逻辑
  7990. if (keyCode == 9) {
  7991. range = me.selection.getRange();
  7992. me.undoManger && me.undoManger.save();
  7993. for (var i = 0,txt = '',tabSize = me.options.tabSize|| 4,tabNode = me.options.tabNode || '&nbsp;'; i < tabSize; i++) {
  7994. txt += tabNode;
  7995. }
  7996. var span = me.document.createElement('span');
  7997. span.innerHTML = txt;
  7998. if (range.collapsed) {
  7999. var li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  8000. if (li && domUtils.isStartInblock(range)) {
  8001. bk = range.createBookmark();
  8002. var parentLi = li.parentNode,
  8003. list = me.document.createElement(parentLi.tagName);
  8004. var index = utils.indexOf(listStyle[list.tagName], domUtils.getComputedStyle(parentLi, 'list-style-type'));
  8005. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  8006. domUtils.setStyle(list, 'list-style-type', listStyle[list.tagName][index]);
  8007. parentLi.insertBefore(list, li);
  8008. list.appendChild(li);
  8009. range.moveToBookmark(bk).select();
  8010. } else{
  8011. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  8012. }
  8013. } else {
  8014. //处理table
  8015. start = domUtils.findParentByTagName(range.startContainer, 'table', true);
  8016. end = domUtils.findParentByTagName(range.endContainer, 'table', true);
  8017. if (start || end) {
  8018. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  8019. return;
  8020. }
  8021. //处理列表 再一个list里处理
  8022. start = domUtils.findParentByTagName(range.startContainer, ['ol','ul'], true);
  8023. end = domUtils.findParentByTagName(range.endContainer, ['ol','ul'], true);
  8024. if (start && end && start === end) {
  8025. var bk = range.createBookmark();
  8026. start = domUtils.findParentByTagName(range.startContainer, 'li', true);
  8027. end = domUtils.findParentByTagName(range.endContainer, 'li', true);
  8028. //在开始单独处理
  8029. if (start === start.parentNode.firstChild) {
  8030. var parentList = me.document.createElement(start.parentNode.tagName);
  8031. start.parentNode.parentNode.insertBefore(parentList, start.parentNode);
  8032. parentList.appendChild(start.parentNode);
  8033. } else {
  8034. parentLi = start.parentNode;
  8035. list = me.document.createElement(parentLi.tagName);
  8036. index = utils.indexOf(listStyle[list.tagName], domUtils.getComputedStyle(parentLi, 'list-style-type'));
  8037. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  8038. domUtils.setStyle(list, 'list-style-type', listStyle[list.tagName][index]);
  8039. start.parentNode.insertBefore(list, start);
  8040. var nextLi;
  8041. while (start !== end) {
  8042. nextLi = start.nextSibling;
  8043. list.appendChild(start);
  8044. start = nextLi;
  8045. }
  8046. list.appendChild(end);
  8047. }
  8048. range.moveToBookmark(bk).select();
  8049. } else {
  8050. if (start || end) {
  8051. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  8052. return
  8053. }
  8054. //普通的情况
  8055. start = domUtils.findParent(range.startContainer, filterFn);
  8056. end = domUtils.findParent(range.endContainer, filterFn);
  8057. if (start && end && start === end) {
  8058. range.deleteContents();
  8059. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  8060. } else {
  8061. var bookmark = range.createBookmark(),
  8062. filterFn = function(node) {
  8063. return domUtils.isBlockElm(node);
  8064. };
  8065. range.enlarge(true);
  8066. var bookmark2 = range.createBookmark(),
  8067. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
  8068. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  8069. current.insertBefore(span.cloneNode(true).firstChild, current.firstChild);
  8070. current = domUtils.getNextDomNode(current, false, filterFn);
  8071. }
  8072. range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
  8073. }
  8074. }
  8075. }
  8076. me.undoManger && me.undoManger.save();
  8077. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  8078. }
  8079. //trace:1634
  8080. //ff的del键在容器空的时候,也会删除
  8081. if(browser.gecko && keyCode == 46){
  8082. range = me.selection.getRange();
  8083. if(range.collapsed){
  8084. start = range.startContainer;
  8085. if(domUtils.isEmptyBlock(start)){
  8086. var parent = start.parentNode;
  8087. while(domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)){
  8088. start = parent;
  8089. parent = parent.parentNode;
  8090. }
  8091. if(start === parent.lastChild)
  8092. evt.preventDefault();
  8093. return;
  8094. }
  8095. }
  8096. }
  8097. });
  8098. me.addListener('keyup', function(type, evt) {
  8099. var keyCode = evt.keyCode || evt.which;
  8100. //修复ie/chrome <strong><em>x|</em></strong> 当点退格后在输入文字后会出现 <b><i>x</i></b>
  8101. if (!browser.gecko && !keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  8102. range = me.selection.getRange();
  8103. if (range.collapsed) {
  8104. var start = range.startContainer,
  8105. isFixed = 0;
  8106. while (!domUtils.isBlockElm(start)) {
  8107. if (start.nodeType == 1 && utils.indexOf(['FONT','B','I'], start.tagName) != -1) {
  8108. var tmpNode = me.document.createElement(trans[start.tagName]);
  8109. if (start.tagName == 'FONT') {
  8110. //chrome only remember color property
  8111. tmpNode.style.cssText = (start.getAttribute('size') ? 'font-size:' + (sizeMap[start.getAttribute('size')] || 12) + 'px' : '')
  8112. + ';' + (start.getAttribute('color') ? 'color:' + start.getAttribute('color') : '')
  8113. + ';' + (start.getAttribute('face') ? 'font-family:' + start.getAttribute('face') : '')
  8114. + ';' + start.style.cssText;
  8115. }
  8116. while (start.firstChild) {
  8117. tmpNode.appendChild(start.firstChild)
  8118. }
  8119. start.parentNode.insertBefore(tmpNode, start);
  8120. domUtils.remove(start);
  8121. if (!isFixed) {
  8122. range.setEnd(tmpNode, tmpNode.childNodes.length).collapse(true)
  8123. }
  8124. start = tmpNode;
  8125. isFixed = 1;
  8126. }
  8127. start = start.parentNode;
  8128. }
  8129. isFixed && range.select()
  8130. }
  8131. }
  8132. if (keyCode == 8 ) {//|| keyCode == 46
  8133. //针对ff下在列表首行退格,不能删除空格行的问题
  8134. if(browser.gecko){
  8135. for(var i=0,li,lis = domUtils.getElementsByTagName(this.body,'li');li=lis[i++];){
  8136. if(domUtils.isEmptyNode(li) && !li.previousSibling){
  8137. var liOfPn = li.parentNode;
  8138. domUtils.remove(li);
  8139. if(domUtils.isEmptyNode(liOfPn)){
  8140. domUtils.remove(liOfPn)
  8141. }
  8142. }
  8143. }
  8144. }
  8145. var range,start,parent,
  8146. tds = this.currentSelectedArr;
  8147. if (tds && tds.length > 0) {
  8148. for (var i = 0,ti; ti = tds[i++];) {
  8149. ti.innerHTML = browser.ie ? ( browser.version < 9 ? '&#65279' : '' ) : '<br/>';
  8150. }
  8151. range = new dom.Range(this.document);
  8152. range.setStart(tds[0], 0).setCursor();
  8153. if (flag) {
  8154. me.undoManger.save();
  8155. flag = 0;
  8156. }
  8157. //阻止chrome执行默认的动作
  8158. if (browser.webkit) {
  8159. evt.preventDefault();
  8160. }
  8161. return;
  8162. }
  8163. range = me.selection.getRange();
  8164. //ctrl+a 后全部删除做处理
  8165. //
  8166. // if (domUtils.isEmptyBlock(me.body) && !range.startOffset) {
  8167. // //trace:1633
  8168. // me.body.innerHTML = '<p>'+(browser.ie ? '&nbsp;' : '<br/>')+'</p>';
  8169. // range.setStart(me.body.firstChild,0).setCursor(false,true);
  8170. // me.undoManger && me.undoManger.save();
  8171. // //todo 对性能会有影响
  8172. // browser.ie && me._selectionChange();
  8173. // return;
  8174. // }
  8175. //处理删除不干净的问题
  8176. start = range.startContainer;
  8177. if(domUtils.isWhitespace(start)){
  8178. start = start.parentNode
  8179. }
  8180. //标志位防止空的p无法删除
  8181. var removeFlag = 0;
  8182. while (start.nodeType == 1 && domUtils.isEmptyNode(start) && dtd.$removeEmpty[start.tagName]) {
  8183. removeFlag = 1;
  8184. parent = start.parentNode;
  8185. domUtils.remove(start);
  8186. start = parent;
  8187. }
  8188. if ( removeFlag && start.nodeType == 1 && domUtils.isEmptyNode(start)) {
  8189. //ie下的问题,虽然没有了相应的节点但一旦你输入文字还是会自动把删除的节点加上,
  8190. if (browser.ie) {
  8191. var span = range.document.createElement('span');
  8192. start.appendChild(span);
  8193. range.setStart(start,0).setCursor();
  8194. //for ie
  8195. li = domUtils.findParentByTagName(start,'li',true);
  8196. if(li){
  8197. var next = li.nextSibling;
  8198. while(next){
  8199. if(domUtils.isEmptyBlock(next)){
  8200. li = next;
  8201. next = next.nextSibling;
  8202. domUtils.remove(li);
  8203. continue;
  8204. }
  8205. break;
  8206. }
  8207. }
  8208. } else {
  8209. start.innerHTML = '<br/>';
  8210. range.setStart(start, 0).setCursor(false,true);
  8211. }
  8212. setTimeout(function() {
  8213. if (browser.ie) {
  8214. domUtils.remove(span);
  8215. }
  8216. if (flag) {
  8217. me.undoManger.save();
  8218. flag = 0;
  8219. }
  8220. }, 0)
  8221. } else {
  8222. if (flag) {
  8223. me.undoManger.save();
  8224. flag = 0;
  8225. }
  8226. }
  8227. }
  8228. })
  8229. };
  8230. ///import core
  8231. ///commands 修复chrome下图片不能点击的问题
  8232. ///commandsName FixImgClick
  8233. ///commandsTitle 修复chrome下图片不能点击的问题
  8234. //修复chrome下图片不能点击的问题
  8235. //todo 可以改大小
  8236. UE.plugins['fiximgclick'] = function() {
  8237. var me = this;
  8238. if ( browser.webkit ) {
  8239. me.addListener( 'click', function( type, e ) {
  8240. if ( e.target.tagName == 'IMG' ) {
  8241. var range = new dom.Range( me.document );
  8242. range.selectNode( e.target ).select();
  8243. }
  8244. } );
  8245. }
  8246. };
  8247. ///import core
  8248. ///commands 为非ie浏览器自动添加a标签
  8249. ///commandsName AutoLink
  8250. ///commandsTitle 自动增加链接
  8251. /**
  8252. * @description 为非ie浏览器自动添加a标签
  8253. * @author zhanyi
  8254. */
  8255. UE.plugins['autolink'] = function() {
  8256. var cont = 0;
  8257. if (browser.ie) {
  8258. return;
  8259. }
  8260. var me = this;
  8261. me.addListener('reset',function(){
  8262. cont = 0;
  8263. });
  8264. me.addListener('keydown', function(type, evt) {
  8265. var keyCode = evt.keyCode || evt.which;
  8266. if (keyCode == 32 || keyCode == 13) {
  8267. var sel = me.selection.getNative(),
  8268. range = sel.getRangeAt(0).cloneRange(),
  8269. offset,
  8270. charCode;
  8271. var start = range.startContainer;
  8272. while (start.nodeType == 1 && range.startOffset > 0) {
  8273. start = range.startContainer.childNodes[range.startOffset - 1];
  8274. if (!start){
  8275. break;
  8276. }
  8277. range.setStart(start, start.nodeType == 1 ? start.childNodes.length : start.nodeValue.length);
  8278. range.collapse(true);
  8279. start = range.startContainer;
  8280. }
  8281. do{
  8282. if (range.startOffset == 0) {
  8283. start = range.startContainer.previousSibling;
  8284. while (start && start.nodeType == 1) {
  8285. start = start.lastChild;
  8286. }
  8287. if (!start || domUtils.isFillChar(start)){
  8288. break;
  8289. }
  8290. offset = start.nodeValue.length;
  8291. } else {
  8292. start = range.startContainer;
  8293. offset = range.startOffset;
  8294. }
  8295. range.setStart(start, offset - 1);
  8296. charCode = range.toString().charCodeAt(0);
  8297. } while (charCode != 160 && charCode != 32);
  8298. if (range.toString().replace(new RegExp(domUtils.fillChar, 'g'), '').match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)) {
  8299. while(range.toString().length){
  8300. if(/^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(range.toString())){
  8301. break;
  8302. }
  8303. try{
  8304. range.setStart(range.startContainer,range.startOffset+1);
  8305. }catch(e){
  8306. //trace:2121
  8307. var start = range.startContainer;
  8308. while(!(next = start.nextSibling)){
  8309. if(domUtils.isBody(start)){
  8310. return;
  8311. }
  8312. start = start.parentNode;
  8313. }
  8314. range.setStart(next,0);
  8315. }
  8316. }
  8317. var a = me.document.createElement('a'),text = me.document.createTextNode(' '),href;
  8318. me.undoManger && me.undoManger.save();
  8319. a.appendChild(range.extractContents());
  8320. a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g,'');
  8321. href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar,'g'),'');
  8322. href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://"+ href;
  8323. a.setAttribute('data_ue_src',href);
  8324. a.href = href;
  8325. range.insertNode(a);
  8326. a.parentNode.insertBefore(text, a.nextSibling);
  8327. range.setStart(text, 0);
  8328. range.collapse(true);
  8329. sel.removeAllRanges();
  8330. sel.addRange(range);
  8331. me.undoManger && me.undoManger.save();
  8332. }
  8333. }
  8334. });
  8335. };
  8336. ///import core
  8337. ///commands 当输入内容超过编辑器高度时,编辑器自动增高
  8338. ///commandsName AutoHeight,autoHeightEnabled
  8339. ///commandsTitle 自动增高
  8340. /**
  8341. * @description 自动伸展
  8342. * @author zhanyi
  8343. */
  8344. UE.plugins['autoheight'] = function () {
  8345. var me = this;
  8346. //提供开关,就算加载也可以关闭
  8347. me.autoHeightEnabled = me.options.autoHeightEnabled !== false ;
  8348. if (!me.autoHeightEnabled){
  8349. return;
  8350. }
  8351. var bakOverflow,
  8352. span, tmpNode,
  8353. lastHeight = 0,
  8354. currentHeight,
  8355. timer;
  8356. function adjustHeight() {
  8357. clearTimeout(timer);
  8358. timer = setTimeout(function () {
  8359. if (me.queryCommandState('source') != 1) {
  8360. if (!span) {
  8361. span = me.document.createElement('span');
  8362. //trace:1764
  8363. span.style.cssText = 'display:block;width:0;margin:0;padding:0;border:0;clear:both;';
  8364. span.innerHTML = '.';
  8365. }
  8366. tmpNode = span.cloneNode(true);
  8367. me.body.appendChild(tmpNode);
  8368. currentHeight = Math.max(domUtils.getXY(tmpNode).y + tmpNode.offsetHeight, me.options.minFrameHeight);
  8369. if (currentHeight != lastHeight) {
  8370. me.setHeight(currentHeight);
  8371. lastHeight = currentHeight;
  8372. }
  8373. domUtils.remove(tmpNode);
  8374. }
  8375. }, 50);
  8376. }
  8377. me.addListener('destroy', function () {
  8378. me.removeListener('contentchange', adjustHeight);
  8379. me.removeListener('keyup', adjustHeight);
  8380. me.removeListener('mouseup', adjustHeight);
  8381. });
  8382. me.enableAutoHeight = function () {
  8383. if(!me.autoHeightEnabled){
  8384. return;
  8385. }
  8386. var doc = me.document;
  8387. me.autoHeightEnabled = true;
  8388. bakOverflow = doc.body.style.overflowY;
  8389. doc.body.style.overflowY = 'hidden';
  8390. me.addListener('contentchange', adjustHeight);
  8391. me.addListener('keyup', adjustHeight);
  8392. me.addListener('mouseup', adjustHeight);
  8393. //ff不给事件算得不对
  8394. setTimeout(function () {
  8395. adjustHeight();
  8396. }, browser.gecko ? 100 : 0);
  8397. me.fireEvent('autoheightchanged', me.autoHeightEnabled);
  8398. };
  8399. me.disableAutoHeight = function () {
  8400. me.body.style.overflowY = bakOverflow || '';
  8401. me.removeListener('contentchange', adjustHeight);
  8402. me.removeListener('keyup', adjustHeight);
  8403. me.removeListener('mouseup', adjustHeight);
  8404. me.autoHeightEnabled = false;
  8405. me.fireEvent('autoheightchanged', me.autoHeightEnabled);
  8406. };
  8407. me.addListener('ready', function () {
  8408. me.enableAutoHeight();
  8409. //trace:1764
  8410. var timer;
  8411. domUtils.on(browser.ie ? me.body : me.document,browser.webkit ? 'dragover' : 'drop',function(){
  8412. clearTimeout(timer);
  8413. timer = setTimeout(function(){
  8414. adjustHeight();
  8415. },100);
  8416. });
  8417. });
  8418. };
  8419. ///import core
  8420. ///commands 悬浮工具栏
  8421. ///commandsName AutoFloat,autoFloatEnabled
  8422. ///commandsTitle 悬浮工具栏
  8423. /*
  8424. * modified by chengchao01
  8425. *
  8426. * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
  8427. */
  8428. UE.plugins['autofloat'] = function() {
  8429. var me = this,
  8430. lang = me.getLang();
  8431. me.setOpt({
  8432. topOffset:0
  8433. });
  8434. var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
  8435. topOffset = me.options.topOffset;
  8436. //如果不固定toolbar的位置,则直接退出
  8437. if(!optsAutoFloatEnabled){
  8438. return;
  8439. }
  8440. var uiUtils = UE.ui.uiUtils,
  8441. LteIE6 = browser.ie && browser.version <= 6,
  8442. quirks = browser.quirks;
  8443. function checkHasUI(editor){
  8444. if(!editor.ui){
  8445. alert(lang.autofloatMsg);
  8446. return 0;
  8447. }
  8448. return 1;
  8449. }
  8450. function fixIE6FixedPos(){
  8451. var docStyle = document.body.style;
  8452. docStyle.backgroundImage = 'url("about:blank")';
  8453. docStyle.backgroundAttachment = 'fixed';
  8454. }
  8455. var bakCssText,
  8456. placeHolder = document.createElement('div'),
  8457. toolbarBox,orgTop,
  8458. getPosition,
  8459. flag =true; //ie7模式下需要偏移
  8460. function setFloating(){
  8461. var toobarBoxPos = domUtils.getXY(toolbarBox),
  8462. origalFloat = domUtils.getComputedStyle(toolbarBox,'position'),
  8463. origalLeft = domUtils.getComputedStyle(toolbarBox,'left');
  8464. toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
  8465. toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
  8466. toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
  8467. if (LteIE6 || (quirks && browser.ie)) {
  8468. if(toolbarBox.style.position != 'absolute'){
  8469. toolbarBox.style.position = 'absolute';
  8470. }
  8471. toolbarBox.style.top = (document.body.scrollTop||document.documentElement.scrollTop) - orgTop + topOffset + 'px';
  8472. } else {
  8473. if (browser.ie7Compat && flag) {
  8474. flag = false;
  8475. toolbarBox.style.left = domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left+2 + 'px';
  8476. }
  8477. if(toolbarBox.style.position != 'fixed'){
  8478. toolbarBox.style.position = 'fixed';
  8479. toolbarBox.style.top = topOffset +"px";
  8480. ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
  8481. }
  8482. }
  8483. }
  8484. function unsetFloating(){
  8485. flag = true;
  8486. if(placeHolder.parentNode){
  8487. placeHolder.parentNode.removeChild(placeHolder);
  8488. }
  8489. toolbarBox.style.cssText = bakCssText;
  8490. }
  8491. function updateFloating(){
  8492. var rect3 = getPosition(me.container);
  8493. if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > 0) {
  8494. setFloating();
  8495. }else{
  8496. unsetFloating();
  8497. }
  8498. }
  8499. var defer_updateFloating = utils.defer(function(){
  8500. updateFloating();
  8501. },browser.ie ? 200 : 100,true);
  8502. me.addListener('destroy',function(){
  8503. domUtils.un(window, ['scroll','resize'], updateFloating);
  8504. me.removeListener('keydown', defer_updateFloating);
  8505. });
  8506. me.addListener('ready', function(){
  8507. if(checkHasUI(me)){
  8508. getPosition = uiUtils.getClientRect;
  8509. toolbarBox = me.ui.getDom('toolbarbox');
  8510. orgTop = getPosition(toolbarBox).top;
  8511. bakCssText = toolbarBox.style.cssText;
  8512. placeHolder.style.height = toolbarBox.offsetHeight + 'px';
  8513. if(LteIE6){
  8514. fixIE6FixedPos();
  8515. }
  8516. me.addListener('autoheightchanged', function (t, enabled){
  8517. if (enabled) {
  8518. domUtils.on(window, ['scroll','resize'], updateFloating);
  8519. me.addListener('keydown', defer_updateFloating);
  8520. } else {
  8521. domUtils.un(window, ['scroll','resize'], updateFloating);
  8522. me.removeListener('keydown', defer_updateFloating);
  8523. }
  8524. });
  8525. me.addListener('beforefullscreenchange', function (t, enabled){
  8526. if (enabled) {
  8527. unsetFloating();
  8528. }
  8529. });
  8530. me.addListener('fullscreenchanged', function (t, enabled){
  8531. if (!enabled) {
  8532. updateFloating();
  8533. }
  8534. });
  8535. me.addListener('sourcemodechanged', function (t, enabled){
  8536. setTimeout(function (){
  8537. updateFloating();
  8538. },0);
  8539. });
  8540. }
  8541. });
  8542. };
  8543. ///import core
  8544. ///import plugins/inserthtml.js
  8545. ///commands 插入代码
  8546. ///commandsName HighlightCode
  8547. ///commandsTitle 插入代码
  8548. ///commandsDialog dialogs\code\code.html
  8549. UE.plugins['highlightcode'] = function() {
  8550. var me = this;
  8551. if(!/highlightcode/i.test(me.options.toolbars.join(''))){
  8552. return;
  8553. }
  8554. me.commands['highlightcode'] = {
  8555. execCommand: function (cmdName, code, syntax) {
  8556. if(code && syntax){
  8557. var pre = document.createElement("pre");
  8558. pre.className = "brush: "+syntax+";toolbar:false;";
  8559. pre.style.display = "";
  8560. pre.appendChild(document.createTextNode(code));
  8561. document.body.appendChild(pre);
  8562. if(me.queryCommandState("highlightcode")){
  8563. me.execCommand("highlightcode");
  8564. }
  8565. me.execCommand('inserthtml', SyntaxHighlighter.highlight(pre,null,true),true);
  8566. var div = me.document.getElementById(SyntaxHighlighter.getHighlighterDivId());
  8567. div.setAttribute('highlighter',pre.className);
  8568. domUtils.remove(pre);
  8569. adjustHeight();
  8570. }else{
  8571. var range = this.selection.getRange(),
  8572. start = domUtils.findParentByTagName(range.startContainer, 'table', true),
  8573. end = domUtils.findParentByTagName(range.endContainer, 'table', true),
  8574. codediv;
  8575. if(start && end && start === end && start.parentNode.className.indexOf("syntaxhighlighter")>-1){
  8576. codediv = start.parentNode;
  8577. if(domUtils.isBody(codediv.parentNode)){
  8578. var p = me.document.createElement('p');
  8579. p.innerHTML = browser.ie ? '' : '<br/>';
  8580. me.body.insertBefore(p,codediv);
  8581. range.setStart(p,0);
  8582. }else{
  8583. range.setStartBefore(codediv)
  8584. }
  8585. range.setCursor();
  8586. domUtils.remove(codediv);
  8587. }
  8588. }
  8589. },
  8590. queryCommandState: function(){
  8591. var range = this.selection.getRange(),start,end;
  8592. range.adjustmentBoundary();
  8593. start = domUtils.findParent(range.startContainer,function(node){
  8594. return node.nodeType == 1 && node.tagName == 'DIV' && domUtils.hasClass(node,'syntaxhighlighter');
  8595. },true);
  8596. end = domUtils.findParent(range.endContainer,function(node){
  8597. return node.nodeType == 1 && node.tagName == 'DIV' && domUtils.hasClass(node,'syntaxhighlighter');
  8598. },true);
  8599. return start && end && start == end ? 1 : 0;
  8600. }
  8601. };
  8602. me.addListener('beforeselectionchange afterselectionchange',function(type){
  8603. me.highlight = /^b/.test(type) ? me.queryCommandState('highlightcode') : 0;
  8604. });
  8605. me.addListener("ready",function(){
  8606. //避免重复加载高亮文件
  8607. if(typeof XRegExp == "undefined"){
  8608. utils.loadFile(document,{
  8609. id : "syntaxhighlighter_js",
  8610. src : me.options.highlightJsUrl || me.options.UEDITOR_HOME_URL + "third-party/SyntaxHighlighter/shCore.js",
  8611. tag : "script",
  8612. type : "text/javascript",
  8613. defer : "defer"
  8614. },function(){
  8615. changePre();
  8616. });
  8617. }
  8618. if(!me.document.getElementById("syntaxhighlighter_css")){
  8619. utils.loadFile(me.document,{
  8620. id : "syntaxhighlighter_css",
  8621. tag : "link",
  8622. rel : "stylesheet",
  8623. type : "text/css",
  8624. href : me.options.highlightCssUrl ||me.options.UEDITOR_HOME_URL + "third-party/SyntaxHighlighter/shCoreDefault.css"
  8625. });
  8626. }
  8627. });
  8628. me.addListener("beforegetcontent",function(){
  8629. for(var i=0,di,divs=domUtils.getElementsByTagName(me.body,'div');di=divs[i++];){
  8630. if(di.className == 'container'){
  8631. var pN = di.parentNode;
  8632. while(pN){
  8633. if(pN.tagName == 'DIV' && /highlighter/.test(pN.id)){
  8634. break;
  8635. }
  8636. pN = pN.parentNode;
  8637. }
  8638. if(!pN){
  8639. return;
  8640. }
  8641. var pre = me.document.createElement('pre');
  8642. for(var str=[],c=0,ci;ci=di.childNodes[c++];){
  8643. str.push(ci[browser.ie?'innerText':'textContent']);
  8644. }
  8645. pre.appendChild(me.document.createTextNode(str.join('\n')));
  8646. pre.className = pN.getAttribute('highlighter');
  8647. pN.parentNode.insertBefore(pre,pN);
  8648. domUtils.remove(pN);
  8649. }
  8650. }
  8651. });
  8652. me.addListener("aftergetcontent aftersetcontent",changePre);
  8653. function adjustHeight(){
  8654. setTimeout(function(){
  8655. var div = me.document.getElementById(SyntaxHighlighter.getHighlighterDivId());
  8656. if(div){
  8657. var tds = div.getElementsByTagName('td');
  8658. for(var i=0,li,ri;li=tds[0].childNodes[i];i++){
  8659. ri = tds[1].firstChild.childNodes[i];
  8660. //trace:1949
  8661. if(ri){
  8662. ri.style.height = li.style.height = ri.offsetHeight + 'px';
  8663. }
  8664. }
  8665. }
  8666. });
  8667. }
  8668. function changePre(){
  8669. for(var i=0,pr,pres = domUtils.getElementsByTagName(me.document,"pre");pr=pres[i++];){
  8670. if(pr.className.indexOf("brush")>-1){
  8671. var pre = document.createElement("pre"),txt,div;
  8672. pre.className = pr.className;
  8673. pre.style.display = "none";
  8674. pre.appendChild(document.createTextNode(pr[browser.ie?'innerText':'textContent']));
  8675. document.body.appendChild(pre);
  8676. try{
  8677. txt = SyntaxHighlighter.highlight(pre,null,true);
  8678. }catch(e){
  8679. domUtils.remove(pre);
  8680. return ;
  8681. }
  8682. div = me.document.createElement("div");
  8683. div.innerHTML = txt;
  8684. div.firstChild.setAttribute('highlighter',pre.className);
  8685. pr.parentNode.insertBefore(div.firstChild,pr);
  8686. domUtils.remove(pre);
  8687. domUtils.remove(pr);
  8688. adjustHeight();
  8689. }
  8690. }
  8691. }
  8692. me.addListener('getAllHtml',function(type,html){
  8693. var coreHtml = '';
  8694. for(var i= 0,ci,divs=domUtils.getElementsByTagName(me.document,'div');ci=divs[i++];){
  8695. if(domUtils.hasClass(ci,'syntaxhighlighter')){
  8696. if(!me.document.getElementById('syntaxhighlighter_css')){
  8697. coreHtml = '<link id="syntaxhighlighter_css" rel="stylesheet" type="text/css" href="' +
  8698. (me.options.highlightCssUrl ||me.options.UEDITOR_HOME_URL + 'third-party/SyntaxHighlighter/shCoreDefault.css"') + ' ></link>'
  8699. }
  8700. if(!me.window.XRegExp){
  8701. coreHtml += '<script id="syntaxhighlighter_js" type="text/javascript" src="' +
  8702. (me.options.highlightJsUrl || me.options.UEDITOR_HOME_URL + 'third-party/SyntaxHighlighter/shCore.js"') + ' ></script>'+
  8703. '<script type="text/javascript">window.onload = function(){SyntaxHighlighter.highlight();' +
  8704. 'setTimeout(function(){' +
  8705. 'for(var i=0,di;di=SyntaxHighlighter.highlightContainers[i++];){' +
  8706. 'var tds = di.getElementsByTagName("td");' +
  8707. 'for(var j=0,li,ri;li=tds[0].childNodes[j];j++){' +
  8708. 'ri = tds[1].firstChild.childNodes[j];' +
  8709. 'ri.style.height = li.style.height = ri.offsetHeight + "px";' +
  8710. '}' +
  8711. '}},100)}</script>'
  8712. }
  8713. break;
  8714. }
  8715. }
  8716. if(!coreHtml){
  8717. var tmpNode;
  8718. if(tmpNode = me.document.getElementById('syntaxhighlighter_css')){
  8719. domUtils.remove(tmpNode)
  8720. }
  8721. if(tmpNode = me.document.getElementById('syntaxhighlighter_js')){
  8722. domUtils.remove(tmpNode)
  8723. }
  8724. }
  8725. html.html = coreHtml;
  8726. });
  8727. //全屏时,重新算一下宽度
  8728. me.addListener('fullscreenchanged',function(){
  8729. var div = domUtils.getElementsByTagName(me.document,'div');
  8730. for(var j=0,di;di=div[j++];){
  8731. if(/^highlighter/.test(di.id)){
  8732. var tds = di.getElementsByTagName('td');
  8733. for(var i=0,li,ri;li=tds[0].childNodes[i];i++){
  8734. ri = tds[1].firstChild.childNodes[i];
  8735. ri.style.height = li.style.height = ri.offsetHeight + 'px';
  8736. }
  8737. }
  8738. }
  8739. });
  8740. };
  8741. ///import core
  8742. ///commands 定制过滤规则
  8743. ///commandsName Serialize
  8744. ///commandsTitle 定制过滤规则
  8745. UE.plugins['serialize'] = function () {
  8746. var ie = browser.ie,
  8747. version = browser.version;
  8748. function ptToPx(value){
  8749. return /pt/.test(value) ? value.replace( /([\d.]+)pt/g, function( str ) {
  8750. return Math.round(parseFloat(str) * 96 / 72) + "px";
  8751. } ) : value;
  8752. }
  8753. var me = this, autoClearEmptyNode = me.options.autoClearEmptyNode,
  8754. EMPTY_TAG = dtd.$empty,
  8755. parseHTML = function () {
  8756. //干掉<a> 后便变得空格,保留</a> 这样的空格
  8757. var RE_PART = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  8758. RE_ATTR = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,
  8759. EMPTY_ATTR = {checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1},
  8760. CDATA_TAG = {script:1,style: 1},
  8761. NEED_PARENT_TAG = {
  8762. "li": { "$": 'ul', "ul": 1, "ol": 1 },
  8763. "dd": { "$": "dl", "dl": 1 },
  8764. "dt": { "$": "dl", "dl": 1 },
  8765. "option": { "$": "select", "select": 1 },
  8766. "td": { "$": "tr", "tr": 1 },
  8767. "th": { "$": "tr", "tr": 1 },
  8768. "tr": { "$": "tbody", "tbody": 1, "thead": 1, "tfoot": 1, "table": 1 },
  8769. "tbody": { "$": "table", 'table':1,"colgroup": 1 },
  8770. "thead": { "$": "table", "table": 1 },
  8771. "tfoot": { "$": "table", "table": 1 },
  8772. "col": { "$": "colgroup","colgroup":1 }
  8773. };
  8774. var NEED_CHILD_TAG = {
  8775. "table": "td", "tbody": "td", "thead": "td", "tfoot": "td", "tr": "td",
  8776. "colgroup": "col",
  8777. "ul": "li", "ol": "li",
  8778. "dl": "dd",
  8779. "select": "option"
  8780. };
  8781. function parse( html, callbacks ) {
  8782. var match,
  8783. nextIndex = 0,
  8784. tagName,
  8785. cdata;
  8786. RE_PART.exec( "" );
  8787. while ( (match = RE_PART.exec( html )) ) {
  8788. var tagIndex = match.index;
  8789. if ( tagIndex > nextIndex ) {
  8790. var text = html.slice( nextIndex, tagIndex );
  8791. if ( cdata ) {
  8792. cdata.push( text );
  8793. } else {
  8794. callbacks.onText( text );
  8795. }
  8796. }
  8797. nextIndex = RE_PART.lastIndex;
  8798. if ( (tagName = match[1]) ) {
  8799. tagName = tagName.toLowerCase();
  8800. if ( cdata && tagName == cdata._tag_name ) {
  8801. callbacks.onCDATA( cdata.join( '' ) );
  8802. cdata = null;
  8803. }
  8804. if ( !cdata ) {
  8805. callbacks.onTagClose( tagName );
  8806. continue;
  8807. }
  8808. }
  8809. if ( cdata ) {
  8810. cdata.push( match[0] );
  8811. continue;
  8812. }
  8813. if ( (tagName = match[3]) ) {
  8814. if ( /="/.test( tagName ) ) {
  8815. continue;
  8816. }
  8817. tagName = tagName.toLowerCase();
  8818. var attrPart = match[4],
  8819. attrMatch,
  8820. attrMap = {},
  8821. selfClosing = attrPart && attrPart.slice( -1 ) == '/';
  8822. if ( attrPart ) {
  8823. RE_ATTR.exec( "" );
  8824. while ( (attrMatch = RE_ATTR.exec( attrPart )) ) {
  8825. var attrName = attrMatch[1].toLowerCase(),
  8826. attrValue = attrMatch[2] || attrMatch[3] || attrMatch[4] || '';
  8827. if ( !attrValue && EMPTY_ATTR[attrName] ) {
  8828. attrValue = attrName;
  8829. }
  8830. if ( attrName == 'style' ) {
  8831. if ( ie && version <= 6 ) {
  8832. attrValue = attrValue.replace( /(?!;)\s*([\w-]+):/g, function ( m, p1 ) {
  8833. return p1.toLowerCase() + ':';
  8834. } );
  8835. }
  8836. }
  8837. //没有值的属性不添加
  8838. if ( attrValue ) {
  8839. attrMap[attrName] = attrValue.replace( /:\s*/g, ':' )
  8840. }
  8841. }
  8842. }
  8843. callbacks.onTagOpen( tagName, attrMap, selfClosing );
  8844. if ( !cdata && CDATA_TAG[tagName] ) {
  8845. cdata = [];
  8846. cdata._tag_name = tagName;
  8847. }
  8848. continue;
  8849. }
  8850. if ( (tagName = match[2]) ) {
  8851. callbacks.onComment( tagName );
  8852. }
  8853. }
  8854. if ( html.length > nextIndex ) {
  8855. callbacks.onText( html.slice( nextIndex, html.length ) );
  8856. }
  8857. }
  8858. return function ( html, forceDtd ) {
  8859. var fragment = {
  8860. type: 'fragment',
  8861. parent: null,
  8862. children: []
  8863. };
  8864. var currentNode = fragment;
  8865. function addChild( node ) {
  8866. node.parent = currentNode;
  8867. currentNode.children.push( node );
  8868. }
  8869. function addElement( element, open ) {
  8870. var node = element;
  8871. // 遇到结构化标签的时候
  8872. if ( NEED_PARENT_TAG[node.tag] ) {
  8873. // 考虑这种情况的时候, 结束之前的标签
  8874. // e.g. <table><tr><td>12312`<tr>`4566
  8875. while ( NEED_PARENT_TAG[currentNode.tag] && NEED_PARENT_TAG[currentNode.tag][node.tag] ) {
  8876. currentNode = currentNode.parent;
  8877. }
  8878. // 如果前一个标签和这个标签是同一级, 结束之前的标签
  8879. // e.g. <ul><li>123<li>
  8880. if ( currentNode.tag == node.tag ) {
  8881. currentNode = currentNode.parent;
  8882. }
  8883. // 向上补齐父标签
  8884. while ( NEED_PARENT_TAG[node.tag] ) {
  8885. if ( NEED_PARENT_TAG[node.tag][currentNode.tag] ) break;
  8886. node = node.parent = {
  8887. type: 'element',
  8888. tag: NEED_PARENT_TAG[node.tag]['$'],
  8889. attributes: {},
  8890. children: [node]
  8891. };
  8892. }
  8893. }
  8894. if ( forceDtd ) {
  8895. // 如果遇到这个标签不能放在前一个标签内部,则结束前一个标签,span单独处理
  8896. while ( dtd[node.tag] && !(currentNode.tag == 'span' ? utils.extend( dtd['strong'], {'a':1,'A':1} ) : (dtd[currentNode.tag] || dtd['div']))[node.tag] ) {
  8897. if ( tagEnd( currentNode ) ) continue;
  8898. if ( !currentNode.parent ) break;
  8899. currentNode = currentNode.parent;
  8900. }
  8901. }
  8902. node.parent = currentNode;
  8903. currentNode.children.push( node );
  8904. if ( open ) {
  8905. currentNode = element;
  8906. }
  8907. if ( element.attributes.style ) {
  8908. element.attributes.style = element.attributes.style.toLowerCase();
  8909. }
  8910. return element;
  8911. }
  8912. // 结束一个标签的时候,需要判断一下它是否缺少子标签
  8913. // e.g. <table></table>
  8914. function tagEnd( node ) {
  8915. var needTag;
  8916. if ( !node.children.length && (needTag = NEED_CHILD_TAG[node.tag]) ) {
  8917. addElement( {
  8918. type: 'element',
  8919. tag: needTag,
  8920. attributes: {},
  8921. children: []
  8922. }, true );
  8923. return true;
  8924. }
  8925. return false;
  8926. }
  8927. parse( html, {
  8928. onText: function ( text ) {
  8929. while ( !(dtd[currentNode.tag] || dtd['div'])['#'] ) {
  8930. //节点之间的空白不能当作节点处理
  8931. // if(/^[ \t\r\n]+$/.test( text )){
  8932. // return;
  8933. // }
  8934. if ( tagEnd( currentNode ) ) continue;
  8935. currentNode = currentNode.parent;
  8936. }
  8937. //if(/^[ \t\n\r]*/.test(text))
  8938. addChild( {
  8939. type: 'text',
  8940. data: text
  8941. } );
  8942. },
  8943. onComment: function ( text ) {
  8944. addChild( {
  8945. type: 'comment',
  8946. data: text
  8947. } );
  8948. },
  8949. onCDATA: function ( text ) {
  8950. while ( !(dtd[currentNode.tag] || dtd['div'])['#'] ) {
  8951. if ( tagEnd( currentNode ) ) continue;
  8952. currentNode = currentNode.parent;
  8953. }
  8954. addChild( {
  8955. type: 'cdata',
  8956. data: text
  8957. } );
  8958. },
  8959. onTagOpen: function ( tag, attrs, closed ) {
  8960. closed = closed || EMPTY_TAG[tag] ;
  8961. addElement( {
  8962. type: 'element',
  8963. tag: tag,
  8964. attributes: attrs,
  8965. closed: closed,
  8966. children: []
  8967. }, !closed );
  8968. },
  8969. onTagClose: function ( tag ) {
  8970. var node = currentNode;
  8971. // 向上找匹配的标签, 这里不考虑dtd的情况是因为tagOpen的时候已经处理过了, 这里不会遇到
  8972. while ( node && tag != node.tag ) {
  8973. node = node.parent;
  8974. }
  8975. if ( node ) {
  8976. // 关闭中间的标签
  8977. for ( var tnode = currentNode; tnode !== node.parent; tnode = tnode.parent ) {
  8978. tagEnd( tnode );
  8979. }
  8980. //去掉空白的inline节点
  8981. //分页,锚点保留
  8982. //|| dtd.$removeEmptyBlock[node.tag])
  8983. // if ( !node.children.length && dtd.$removeEmpty[node.tag] && !node.attributes.anchorname && node.attributes['class'] != 'pagebreak' && node.tag != 'a') {
  8984. //
  8985. // node.parent.children.pop();
  8986. // }
  8987. currentNode = node.parent;
  8988. } else {
  8989. // 如果没有找到开始标签, 则创建新标签
  8990. // eg. </div> => <div></div>
  8991. //针对视屏网站embed会给结束符,这里特殊处理一下
  8992. if ( !(dtd.$removeEmpty[tag] || dtd.$removeEmptyBlock[tag] || tag == 'embed') ) {
  8993. node = {
  8994. type: 'element',
  8995. tag: tag,
  8996. attributes: {},
  8997. children: []
  8998. };
  8999. addElement( node, true );
  9000. tagEnd( node );
  9001. currentNode = node.parent;
  9002. }
  9003. }
  9004. }
  9005. } );
  9006. // 处理这种情况, 只有开始标签没有结束标签的情况, 需要关闭开始标签
  9007. // eg. <table>
  9008. while ( currentNode !== fragment ) {
  9009. tagEnd( currentNode );
  9010. currentNode = currentNode.parent;
  9011. }
  9012. return fragment;
  9013. };
  9014. }();
  9015. var unhtml1 = function () {
  9016. var map = { '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
  9017. function rep( m ) {
  9018. return map[m];
  9019. }
  9020. return function ( str ) {
  9021. str = str + '';
  9022. return str ? str.replace( /[<>"']/g, rep ) : '';
  9023. };
  9024. }();
  9025. var toHTML = function () {
  9026. function printChildren( node, pasteplain ) {
  9027. var children = node.children;
  9028. var buff = [];
  9029. for ( var i = 0,ci; ci = children[i]; i++ ) {
  9030. buff.push( toHTML( ci, pasteplain ) );
  9031. }
  9032. return buff.join( '' );
  9033. }
  9034. function printAttrs( attrs ) {
  9035. var buff = [];
  9036. for ( var k in attrs ) {
  9037. var value = attrs[k];
  9038. if(k == 'style'){
  9039. //pt==>px
  9040. value = ptToPx(value);
  9041. //color rgb ==> hex
  9042. if(/rgba?\s*\([^)]*\)/.test(value)){
  9043. value = value.replace( /rgba?\s*\(([^)]*)\)/g, function( str ) {
  9044. return utils.fixColor('color',str);
  9045. } )
  9046. }
  9047. //过滤掉所有的white-space,在纯文本编辑器里粘贴过来的内容,到chrome中会带有span和white-space属性,导致出现不能折行的情况
  9048. //所以在这里去掉这个属性
  9049. attrs[k] = utils.optCss(value.replace(/windowtext/g,'#000'))
  9050. .replace(/white-space[^;]+;/g,'');
  9051. }
  9052. buff.push( k + '="' + unhtml1( attrs[k] ) + '"' );
  9053. }
  9054. return buff.join( ' ' )
  9055. }
  9056. function printData( node, notTrans ) {
  9057. //trace:1399 输入html代码时空格转换成为&nbsp;
  9058. //node.data.replace(/&nbsp;/g,' ') 针对pre中的空格和出现的&nbsp;把他们在得到的html代码中都转换成为空格,为了在源码模式下显示为空格而不是&nbsp;
  9059. return notTrans ? node.data.replace(/&nbsp;/g,' ') : unhtml1( node.data ).replace(/ /g,'&nbsp;');
  9060. }
  9061. //纯文本模式下标签转换
  9062. var transHtml = {
  9063. 'div':'p',
  9064. 'li':'p',
  9065. 'tr':'p',
  9066. 'br':'br',
  9067. 'p':'p'//trace:1398 碰到p标签自己要加上p,否则transHtml[tag]是undefined
  9068. };
  9069. function printElement( node, pasteplain ) {
  9070. if ( node.type == 'element' && !node.children.length && (dtd.$removeEmpty[node.tag]) && node.tag != 'a' && utils.isEmptyObject(node.attributes) && autoClearEmptyNode) {// 锚点保留
  9071. return html;
  9072. }
  9073. var tag = node.tag;
  9074. if ( pasteplain && tag == 'td' ) {
  9075. if ( !html ) html = '';
  9076. html += printChildren( node, pasteplain ) + '&nbsp;&nbsp;&nbsp;';
  9077. } else {
  9078. var attrs = printAttrs( node.attributes );
  9079. var html = '<' + (pasteplain && transHtml[tag] ? transHtml[tag] : tag) + (attrs ? ' ' + attrs : '') + (EMPTY_TAG[tag] ? ' />' : '>');
  9080. if ( !EMPTY_TAG[tag] ) {
  9081. //trace:1627 ,2070
  9082. //p标签为空,将不占位这里占位符不起作用,用&nbsp;或者br
  9083. if( tag == 'p' && !node.children.length){
  9084. html += browser.ie ? '&nbsp;' : '<br/>';
  9085. }
  9086. html += printChildren( node, pasteplain );
  9087. html += '</' + (pasteplain && transHtml[tag] ? transHtml[tag] : tag) + '>';
  9088. }
  9089. }
  9090. return html;
  9091. }
  9092. return function ( node, pasteplain ) {
  9093. if ( node.type == 'fragment' ) {
  9094. return printChildren( node, pasteplain );
  9095. } else if ( node.type == 'element' ) {
  9096. return printElement( node, pasteplain );
  9097. } else if ( node.type == 'text' || node.type == 'cdata' ) {
  9098. return printData( node, dtd.$notTransContent[node.parent.tag] );
  9099. } else if ( node.type == 'comment' ) {
  9100. return '<!--' + node.data + '-->';
  9101. }
  9102. return '';
  9103. };
  9104. }();
  9105. //过滤word
  9106. var transformWordHtml = function () {
  9107. function isWordDocument( strValue ) {
  9108. var re = new RegExp( /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<v:)/ig );
  9109. return re.test( strValue );
  9110. }
  9111. function ensureUnits( v ) {
  9112. v = v.replace( /([\d.]+)([\w]+)?/g, function ( m, p1, p2 ) {
  9113. return (Math.round( parseFloat( p1 ) ) || 1) + (p2 || 'px');
  9114. } );
  9115. return v;
  9116. }
  9117. function filterPasteWord( str ) {
  9118. str = str.replace( /<!--\s*EndFragment\s*-->[\s\S]*$/, '' )
  9119. //remove link break
  9120. .replace( /^(\r\n|\n|\r)|(\r\n|\n|\r)$/ig, "" )
  9121. //remove &nbsp; entities at the start of contents
  9122. .replace( /^\s*(&nbsp;)+/ig, "" )
  9123. //remove &nbsp; entities at the end of contents
  9124. .replace( /(&nbsp;|<br[^>]*>)+\s*$/ig, "" )
  9125. // Word comments like conditional comments etc
  9126. .replace( /<!--[\s\S]*?-->/ig, "" )
  9127. //转换图片
  9128. .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi,function(str){
  9129. //opera能自己解析出image所这里直接返回空
  9130. if(browser.opera){
  9131. return '';
  9132. }
  9133. try{
  9134. var width = str.match(/width:([ \d.]*p[tx])/i)[1],
  9135. height = str.match(/height:([ \d.]*p[tx])/i)[1],
  9136. src = str.match(/src=\s*"([^"]*)"/i)[1];
  9137. return '<img width="'+ptToPx(width)+'" height="'+ptToPx(height)+'" src="' + src + '" />'
  9138. } catch(e){
  9139. return '';
  9140. }
  9141. })
  9142. //去掉多余的属性
  9143. .replace( /v:\w+=["']?[^'"]+["']?/g, '' )
  9144. // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content, MS Office namespaced tags, and a few other tags
  9145. .replace( /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "" )
  9146. //convert word headers to strong
  9147. .replace( /<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>" )
  9148. //remove lang attribute
  9149. .replace( /(lang)\s*=\s*([\'\"]?)[\w-]+\2/ig, "" )
  9150. //清除多余的font不能匹配&nbsp;有可能是空格
  9151. .replace( /<font[^>]*>\s*<\/font>/gi, '' )
  9152. //清除多余的class
  9153. .replace( /class\s*=\s*["']?(?:(?:MsoTableGrid)|(?:MsoListParagraph)|(?:MsoNormal(Table)?))\s*["']?/gi, '')
  9154. //修复了原有的问题, 比如style='fontsize:"宋体"'原来的匹配失效了
  9155. str = str.replace( /(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function( str, tag, tmp, style ) {
  9156. var n = [],
  9157. i = 0,
  9158. s = style.replace( /^\s+|\s+$/, '' ).replace( /&quot;/gi, "'" ).split( /;\s*/g );
  9159. // Examine each style definition within the tag's style attribute
  9160. for ( var i = 0; i < s.length; i++ ) {
  9161. var v = s[i];
  9162. var name, value,
  9163. parts = v.split( ":" );
  9164. if ( parts.length == 2 ) {
  9165. name = parts[0].toLowerCase();
  9166. value = parts[1].toLowerCase();
  9167. // Translate certain MS Office styles into their CSS equivalents
  9168. switch ( name ) {
  9169. case "mso-padding-alt":
  9170. case "mso-padding-top-alt":
  9171. case "mso-padding-right-alt":
  9172. case "mso-padding-bottom-alt":
  9173. case "mso-padding-left-alt":
  9174. case "mso-margin-alt":
  9175. case "mso-margin-top-alt":
  9176. case "mso-margin-right-alt":
  9177. case "mso-margin-bottom-alt":
  9178. case "mso-margin-left-alt":
  9179. //ie下会出现挤到一起的情况
  9180. // case "mso-table-layout-alt":
  9181. case "mso-height":
  9182. case "mso-width":
  9183. case "mso-vertical-align-alt":
  9184. //trace:1819 ff下会解析出padding在table上
  9185. if(!/<table/.test(tag))
  9186. n[i] = name.replace( /^mso-|-alt$/g, "" ) + ":" + ensureUnits( value );
  9187. continue;
  9188. case "horiz-align":
  9189. n[i] = "text-align:" + value;
  9190. continue;
  9191. case "vert-align":
  9192. n[i] = "vertical-align:" + value;
  9193. continue;
  9194. case "font-color":
  9195. case "mso-foreground":
  9196. n[i] = "color:" + value;
  9197. continue;
  9198. case "mso-background":
  9199. case "mso-highlight":
  9200. n[i] = "background:" + value;
  9201. continue;
  9202. case "mso-default-height":
  9203. n[i] = "min-height:" + ensureUnits( value );
  9204. continue;
  9205. case "mso-default-width":
  9206. n[i] = "min-width:" + ensureUnits( value );
  9207. continue;
  9208. case "mso-padding-between-alt":
  9209. n[i] = "border-collapse:separate;border-spacing:" + ensureUnits( value );
  9210. continue;
  9211. case "text-line-through":
  9212. if ( (value == "single") || (value == "double") ) {
  9213. n[i] = "text-decoration:line-through";
  9214. }
  9215. continue;
  9216. //trace:1870
  9217. // //word里边的字体统一干掉
  9218. // case 'font-family':
  9219. // continue;
  9220. case "mso-zero-height":
  9221. if ( value == "yes" ) {
  9222. n[i] = "display:none";
  9223. }
  9224. continue;
  9225. case 'margin':
  9226. if ( !/[1-9]/.test( parts[1] ) ) {
  9227. continue;
  9228. }
  9229. }
  9230. if ( /^(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( name ) ) {
  9231. // if ( !/mso\-list/.test( name ) )
  9232. continue;
  9233. }
  9234. if(/text\-indent|padding|margin/.test(name) && /\-[\d.]+/.test(value)){
  9235. continue;
  9236. }
  9237. n[i] = name + ":" + parts[1];
  9238. }
  9239. }
  9240. // If style attribute contained any valid styles the re-write it; otherwise delete style attribute.
  9241. if ( i > 0 ) {
  9242. return tag + ' style="' + n.join( ';' ) + '"';
  9243. } else {
  9244. return tag;
  9245. }
  9246. } );
  9247. str = str.replace( /([ ]+)<\/span>/ig, function ( m, p ) {
  9248. return new Array( p.length + 1 ).join( '&nbsp;' ) + '</span>';
  9249. } );
  9250. return str;
  9251. }
  9252. return function ( html ) {
  9253. //过了word,才能转p->li
  9254. first = null;
  9255. parentTag = '',liStyle = '',firstTag = '';
  9256. if ( isWordDocument( html ) ) {
  9257. html = filterPasteWord( html );
  9258. }
  9259. return html.replace( />[ \t\r\n]*</g, '><' );
  9260. };
  9261. }();
  9262. var NODE_NAME_MAP = {
  9263. 'text': '#text',
  9264. 'comment': '#comment',
  9265. 'cdata': '#cdata-section',
  9266. 'fragment': '#document-fragment'
  9267. };
  9268. // function _likeLi( node ) {
  9269. // var a;
  9270. // if ( node && node.tag == 'p' ) {
  9271. // //office 2011下有效
  9272. // if ( node.attributes['class'] == 'MsoListParagraph' || /mso-list/.test( node.attributes.style ) ) {
  9273. // a = 1;
  9274. // } else {
  9275. // var firstChild = node.children[0];
  9276. // if ( firstChild && firstChild.tag == 'span' && /Wingdings/i.test( firstChild.attributes.style ) ) {
  9277. // a = 1;
  9278. // }
  9279. // }
  9280. // }
  9281. // return a;
  9282. // }
  9283. //为p==>li 做个标志
  9284. var first,
  9285. // orderStyle = {
  9286. // 'decimal' : /\d+/,
  9287. // 'lower-roman': /^m{0,4}(cm|cd|d?c{0,3})(xc|xl|l?x{0,3})(ix|iv|v?i{0,3})$/,
  9288. // 'upper-roman': /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/,
  9289. // 'lower-alpha' : /^\(?[a-z]+\)?$/,
  9290. // 'upper-alpha': /^\(?[A-Z]+\)?$/
  9291. // },
  9292. // unorderStyle = { 'disc' : /^[l\u00B7\u2002]/, 'circle' : /^[\u006F\u00D8]/,'square' : /^[\u006E\u25C6]/},
  9293. parentTag = '',liStyle = '',firstTag;
  9294. //写入编辑器时,调用,进行转换操作
  9295. function transNode( node, word_img_flag ) {
  9296. var sizeMap = [0, 10, 12, 16, 18, 24, 32, 48],
  9297. attr,
  9298. indexOf = utils.indexOf;
  9299. switch ( node.tag ) {
  9300. case 'script':
  9301. node.tag = 'div';
  9302. node.attributes._ue_div_script = 1;
  9303. node.attributes._ue_script_data = node.children[0] ? encodeURIComponent(node.children[0].data) : '';
  9304. node.attributes._ue_custom_node_ = 1;
  9305. node.children = [];
  9306. break;
  9307. case 'style':
  9308. node.tag = 'div';
  9309. node.attributes._ue_div_style = 1;
  9310. node.attributes._ue_style_data = node.children[0] ? encodeURIComponent(node.children[0].data) : '';
  9311. node.attributes._ue_custom_node_ = 1;
  9312. node.children = [];
  9313. break;
  9314. case 'img':
  9315. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  9316. if(node.attributes.src && /^data:/.test(node.attributes.src)){
  9317. return {
  9318. type : 'fragment',
  9319. children:[]
  9320. }
  9321. }
  9322. if ( node.attributes.src && /^(?:file)/.test( node.attributes.src ) ) {
  9323. if ( !/(gif|bmp|png|jpg|jpeg)$/.test( node.attributes.src ) ) {
  9324. return {
  9325. type : 'fragment',
  9326. children:[]
  9327. }
  9328. }
  9329. node.attributes.word_img = node.attributes.src;
  9330. node.attributes.src = me.options.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
  9331. var flag = parseInt(node.attributes.width)<128||parseInt(node.attributes.height)<43;
  9332. node.attributes.style="background:url(" + (flag? me.options.UEDITOR_HOME_URL +"themes/default/images/word.gif":me.options.langPath+me.options.lang + "/images/localimage.png")+") no-repeat center center;border:1px solid #ddd";
  9333. //node.attributes.style = 'width:395px;height:173px;';
  9334. word_img_flag && (word_img_flag.flag = 1);
  9335. }
  9336. if(browser.ie && browser.version < 7 )
  9337. node.attributes.orgSrc = node.attributes.src;
  9338. node.attributes.data_ue_src = node.attributes.data_ue_src || node.attributes.src;
  9339. break;
  9340. case 'li':
  9341. var child = node.children[0];
  9342. if ( !child || child.type != 'element' || child.tag != 'p' && dtd.p[child.tag] ) {
  9343. var tmpPNode = {
  9344. type: 'element',
  9345. tag: 'p',
  9346. attributes: {},
  9347. parent : node
  9348. };
  9349. tmpPNode.children = child ? node.children :[
  9350. browser.ie ? {
  9351. type:'text',
  9352. data:domUtils.fillChar,
  9353. parent : tmpPNode
  9354. }:
  9355. {
  9356. type : 'element',
  9357. tag : 'br',
  9358. attributes:{},
  9359. closed: true,
  9360. children: [],
  9361. parent : tmpPNode
  9362. }
  9363. ];
  9364. node.children = [tmpPNode];
  9365. }
  9366. break;
  9367. case 'table':
  9368. case 'td':
  9369. optStyle( node );
  9370. break;
  9371. case 'a'://锚点,a==>img
  9372. if ( node.attributes['anchorname'] ) {
  9373. node.tag = 'img';
  9374. node.attributes = {
  9375. 'class' : 'anchorclass',
  9376. 'anchorname':node.attributes['name']
  9377. };
  9378. node.closed = 1;
  9379. }
  9380. node.attributes.href && (node.attributes.data_ue_src = node.attributes.href);
  9381. break;
  9382. case 'b':
  9383. node.tag = node.name = 'strong';
  9384. break;
  9385. case 'i':
  9386. node.tag = node.name = 'em';
  9387. break;
  9388. case 'u':
  9389. node.tag = node.name = 'span';
  9390. node.attributes.style = (node.attributes.style || '') + ';text-decoration:underline;';
  9391. break;
  9392. case 's':
  9393. case 'del':
  9394. node.tag = node.name = 'span';
  9395. node.attributes.style = (node.attributes.style || '') + ';text-decoration:line-through;';
  9396. if ( node.children.length == 1 ) {
  9397. child = node.children[0];
  9398. if ( child.tag == node.tag ) {
  9399. node.attributes.style += ";" + child.attributes.style;
  9400. node.children = child.children;
  9401. }
  9402. }
  9403. break;
  9404. case 'span':
  9405. // if ( /mso-list/.test( node.attributes.style ) ) {
  9406. //
  9407. //
  9408. // //判断了两次就不在判断了
  9409. // if ( firstTag != 'end' ) {
  9410. //
  9411. // var ci = node.children[0],p;
  9412. // while ( ci.type == 'element' ) {
  9413. // ci = ci.children[0];
  9414. // }
  9415. // for ( p in unorderStyle ) {
  9416. // if ( unorderStyle[p].test( ci.data ) ) {
  9417. //
  9418. // // ci.data = ci.data.replace(unorderStyle[p],'');
  9419. // parentTag = 'ul';
  9420. // liStyle = p;
  9421. // break;
  9422. // }
  9423. // }
  9424. //
  9425. //
  9426. // if ( !parentTag ) {
  9427. // for ( p in orderStyle ) {
  9428. // if ( orderStyle[p].test( ci.data.replace( /\.$/, '' ) ) ) {
  9429. // // ci.data = ci.data.replace(orderStyle[p],'');
  9430. // parentTag = 'ol';
  9431. // liStyle = p;
  9432. // break;
  9433. // }
  9434. // }
  9435. // }
  9436. // if ( firstTag ) {
  9437. // if ( ci.data == firstTag ) {
  9438. // if ( parentTag != 'ul' ) {
  9439. // liStyle = '';
  9440. // }
  9441. // parentTag = 'ul'
  9442. // } else {
  9443. // if ( parentTag != 'ol' ) {
  9444. // liStyle = '';
  9445. // }
  9446. // parentTag = 'ol'
  9447. // }
  9448. // firstTag = 'end'
  9449. // } else {
  9450. // firstTag = ci.data
  9451. // }
  9452. // if ( parentTag ) {
  9453. // var tmpNode = node;
  9454. // while ( tmpNode && tmpNode.tag != 'ul' && tmpNode.tag != 'ol' ) {
  9455. // tmpNode = tmpNode.parent;
  9456. // }
  9457. // if(tmpNode ){
  9458. // tmpNode.tag = parentTag;
  9459. // tmpNode.attributes.style = 'list-style-type:' + liStyle;
  9460. // }
  9461. //
  9462. //
  9463. //
  9464. // }
  9465. //
  9466. // }
  9467. //
  9468. // node = {
  9469. // type : 'fragment',
  9470. // children : []
  9471. // };
  9472. // break;
  9473. //
  9474. //
  9475. // }
  9476. var style = node.attributes.style;
  9477. if ( style ) {
  9478. if ( !node.attributes.style || browser.webkit && style == "white-space:nowrap;") {
  9479. delete node.attributes.style;
  9480. }
  9481. }
  9482. //针对ff3.6span的样式不能正确继承的修复
  9483. if(browser.gecko && browser.version <= 10902 && node.parent){
  9484. var parent = node.parent;
  9485. if(parent.tag == 'span' && parent.attributes && parent.attributes.style){
  9486. node.attributes.style = parent.attributes.style + ';' + node.attributes.style;
  9487. }
  9488. }
  9489. if ( utils.isEmptyObject( node.attributes ) && autoClearEmptyNode) {
  9490. node.type = 'fragment'
  9491. }
  9492. break;
  9493. case 'font':
  9494. node.tag = node.name = 'span';
  9495. attr = node.attributes;
  9496. node.attributes = {
  9497. 'style': (attr.size ? 'font-size:' + (sizeMap[attr.size] || 12) + 'px' : '')
  9498. + ';' + (attr.color ? 'color:'+ attr.color : '')
  9499. + ';' + (attr.face ? 'font-family:'+ attr.face : '')
  9500. + ';' + (attr.style||'')
  9501. };
  9502. while(node.parent.tag == node.tag && node.parent.children.length == 1){
  9503. node.attributes.style && (node.parent.attributes.style ? (node.parent.attributes.style += ";" + node.attributes.style) : (node.parent.attributes.style = node.attributes.style));
  9504. node.parent.children = node.children;
  9505. node = node.parent;
  9506. }
  9507. break;
  9508. case 'p':
  9509. if ( node.attributes.align ) {
  9510. node.attributes.style = (node.attributes.style || '') + ';text-align:' +
  9511. node.attributes.align + ';';
  9512. delete node.attributes.align;
  9513. }
  9514. // if ( _likeLi( node ) ) {
  9515. //
  9516. // if ( !first ) {
  9517. //
  9518. // var ulNode = {
  9519. // type: 'element',
  9520. // tag: 'ul',
  9521. // attributes: {},
  9522. // children: []
  9523. // },
  9524. // index = indexOf( node.parent.children, node );
  9525. // node.parent.children[index] = ulNode;
  9526. // ulNode.parent = node.parent;
  9527. // ulNode.children[0] = node;
  9528. // node.parent = ulNode;
  9529. //
  9530. // while ( 1 ) {
  9531. // node = ulNode.parent.children[index + 1];
  9532. // if ( _likeLi( node ) ) {
  9533. // ulNode.children[ulNode.children.length] = node;
  9534. // node.parent = ulNode;
  9535. // ulNode.parent.children.splice( index + 1, 1 );
  9536. //
  9537. // } else {
  9538. // break;
  9539. // }
  9540. // }
  9541. //
  9542. // return ulNode;
  9543. // }
  9544. // node.tag = node.name = 'li';
  9545. // //为chrome能找到标号做的处理
  9546. // if ( browser.webkit ) {
  9547. // var span = node.children[0];
  9548. //
  9549. // while ( span && span.type == 'element' ) {
  9550. // span = span.children[0]
  9551. // }
  9552. // span && (span.parent.attributes.style = (span.parent.attributes.style || '') + ';mso-list:10');
  9553. // }
  9554. //
  9555. //
  9556. // delete node.attributes['class'];
  9557. // delete node.attributes.style;
  9558. //
  9559. //
  9560. // }
  9561. }
  9562. return node;
  9563. }
  9564. function optStyle( node ) {
  9565. if ( ie && node.attributes.style ) {
  9566. var style = node.attributes.style;
  9567. node.attributes.style = style.replace(/;\s*/g,';');
  9568. node.attributes.style = node.attributes.style.replace( /^\s*|\s*$/, '' )
  9569. }
  9570. }
  9571. //getContent调用转换
  9572. function transOutNode( node ) {
  9573. switch ( node.tag ) {
  9574. case 'div' :
  9575. if(node.attributes._ue_div_script){
  9576. node.tag = 'script';
  9577. node.children = [{type:'cdata',data:node.attributes._ue_script_data?decodeURIComponent(node.attributes._ue_script_data):'',parent:node}];
  9578. delete node.attributes._ue_div_script;
  9579. delete node.attributes._ue_script_data;
  9580. delete node.attributes._ue_custom_node_;
  9581. }
  9582. if(node.attributes._ue_div_style){
  9583. node.tag = 'style';
  9584. node.children = [{type:'cdata',data:node.attributes._ue_style_data?decodeURIComponent(node.attributes._ue_style_data):'',parent:node}];
  9585. delete node.attributes._ue_div_style;
  9586. delete node.attributes._ue_style_data;
  9587. delete node.attributes._ue_custom_node_;
  9588. }
  9589. break;
  9590. case 'table':
  9591. !node.attributes.style && delete node.attributes.style;
  9592. if ( ie && node.attributes.style ) {
  9593. optStyle( node );
  9594. }
  9595. if(node.attributes['class'] == 'noBorderTable'){
  9596. delete node.attributes['class'];
  9597. }
  9598. break;
  9599. case 'td':
  9600. case 'th':
  9601. if ( /display\s*:\s*none/i.test( node.attributes.style ) ) {
  9602. return {
  9603. type: 'fragment',
  9604. children: []
  9605. };
  9606. }
  9607. if ( ie && !node.children.length ) {
  9608. var txtNode = {
  9609. type: 'text',
  9610. data:domUtils.fillChar,
  9611. parent : node
  9612. };
  9613. node.children[0] = txtNode;
  9614. }
  9615. if ( ie && node.attributes.style ) {
  9616. optStyle( node );
  9617. }
  9618. if(node.attributes['class'] == 'selectTdClass'){
  9619. delete node.attributes['class']
  9620. }
  9621. break;
  9622. case 'img'://锚点,img==>a
  9623. if ( node.attributes.anchorname ) {
  9624. node.tag = 'a';
  9625. node.attributes = {
  9626. name : node.attributes.anchorname,
  9627. anchorname : 1
  9628. };
  9629. node.closed = null;
  9630. }else{
  9631. if(node.attributes.data_ue_src){
  9632. node.attributes.src = node.attributes.data_ue_src;
  9633. delete node.attributes.data_ue_src;
  9634. }
  9635. }
  9636. break;
  9637. case 'a':
  9638. if(node.attributes.data_ue_src){
  9639. node.attributes.href = node.attributes.data_ue_src;
  9640. delete node.attributes.data_ue_src;
  9641. }
  9642. }
  9643. return node;
  9644. }
  9645. function childrenAccept( node, visit, ctx ) {
  9646. if ( !node.children || !node.children.length ) {
  9647. return node;
  9648. }
  9649. var children = node.children;
  9650. for ( var i = 0; i < children.length; i++ ) {
  9651. var newNode = visit( children[i], ctx );
  9652. if ( newNode.type == 'fragment' ) {
  9653. var args = [i, 1];
  9654. args.push.apply( args, newNode.children );
  9655. children.splice.apply( children, args );
  9656. //节点为空的就干掉,不然后边的补全操作会添加多余的节点
  9657. if ( !children.length ) {
  9658. node = {
  9659. type: 'fragment',
  9660. children: []
  9661. }
  9662. }
  9663. i --;
  9664. } else {
  9665. children[i] = newNode;
  9666. }
  9667. }
  9668. return node;
  9669. }
  9670. function Serialize( rules ) {
  9671. this.rules = rules;
  9672. }
  9673. Serialize.prototype = {
  9674. // NOTE: selector目前只支持tagName
  9675. rules: null,
  9676. // NOTE: node必须是fragment
  9677. filter: function ( node, rules, modify ) {
  9678. rules = rules || this.rules;
  9679. var whiteList = rules && rules.whiteList;
  9680. var blackList = rules && rules.blackList;
  9681. function visitNode( node, parent ) {
  9682. node.name = node.type == 'element' ?
  9683. node.tag : NODE_NAME_MAP[node.type];
  9684. if ( parent == null ) {
  9685. return childrenAccept( node, visitNode, node );
  9686. }
  9687. if ( blackList && blackList[node.name] ) {
  9688. modify && (modify.flag = 1);
  9689. return {
  9690. type: 'fragment',
  9691. children: []
  9692. };
  9693. }
  9694. if ( whiteList ) {
  9695. if ( node.type == 'element' ) {
  9696. if ( parent.type == 'fragment' ? whiteList[node.name] : whiteList[node.name] && whiteList[parent.name][node.name] ) {
  9697. var props;
  9698. if ( (props = whiteList[node.name].$) ) {
  9699. var oldAttrs = node.attributes;
  9700. var newAttrs = {};
  9701. for ( var k in props ) {
  9702. if ( oldAttrs[k] ) {
  9703. newAttrs[k] = oldAttrs[k];
  9704. }
  9705. }
  9706. node.attributes = newAttrs;
  9707. }
  9708. } else {
  9709. modify && (modify.flag = 1);
  9710. node.type = 'fragment';
  9711. // NOTE: 这里算是一个hack
  9712. node.name = parent.name;
  9713. }
  9714. } else {
  9715. // NOTE: 文本默认允许
  9716. }
  9717. }
  9718. if ( blackList || whiteList ) {
  9719. childrenAccept( node, visitNode, node );
  9720. }
  9721. return node;
  9722. }
  9723. return visitNode( node, null );
  9724. },
  9725. transformInput: function ( node, word_img_flag ) {
  9726. function visitNode( node ) {
  9727. node = transNode( node, word_img_flag );
  9728. // if ( node.tag == 'ol' || node.tag == 'ul' ) {
  9729. // first = 1;
  9730. // }
  9731. node = childrenAccept( node, visitNode, node );
  9732. // if ( node.tag == 'ol' || node.tag == 'ul' ) {
  9733. // first = 0;
  9734. // parentTag = '',liStyle = '',firstTag = '';
  9735. // }
  9736. if ( me.options.pageBreakTag && node.type == 'text' && node.data.replace( /\s/g, '' ) == me.options.pageBreakTag ) {
  9737. node.type = 'element';
  9738. node.name = node.tag = 'hr';
  9739. delete node.data;
  9740. node.attributes = {
  9741. 'class' : 'pagebreak',
  9742. noshade:"noshade",
  9743. size:"5",
  9744. 'unselectable' : 'on',
  9745. 'style' : 'moz-user-select:none;-khtml-user-select: none;'
  9746. };
  9747. node.children = [];
  9748. }
  9749. //去掉多余的空格和换行
  9750. if(node.type == 'text' && !dtd.$notTransContent[node.parent.tag]){
  9751. node.data = node.data.replace(/[\r\t\n]*/g,'')//.replace(/[ ]*$/g,'')
  9752. }
  9753. return node;
  9754. }
  9755. return visitNode( node );
  9756. },
  9757. transformOutput: function ( node ) {
  9758. function visitNode( node ) {
  9759. if ( node.tag == 'hr' && node.attributes['class'] == 'pagebreak' ) {
  9760. delete node.tag;
  9761. node.type = 'text';
  9762. node.data = me.options.pageBreakTag;
  9763. delete node.children;
  9764. }
  9765. node = transOutNode( node );
  9766. if ( node.tag == 'ol' || node.tag == 'ul' ) {
  9767. first = 1;
  9768. }
  9769. node = childrenAccept( node, visitNode, node );
  9770. if ( node.tag == 'ol' || node.tag == 'ul' ) {
  9771. first = 0;
  9772. }
  9773. return node;
  9774. }
  9775. return visitNode( node );
  9776. },
  9777. toHTML: toHTML,
  9778. parseHTML: parseHTML,
  9779. word: transformWordHtml
  9780. };
  9781. me.serialize = new Serialize( me.options.serialize || {});
  9782. UE.serialize = new Serialize( {} );
  9783. };
  9784. ///import core
  9785. ///import plugins/inserthtml.js
  9786. ///commands 视频
  9787. ///commandsName InsertVideo
  9788. ///commandsTitle 插入视频
  9789. ///commandsDialog dialogs\video\video.html
  9790. UE.plugins['video'] = function (){
  9791. var me =this,
  9792. div;
  9793. /**
  9794. * 创建插入视频字符窜
  9795. * @param url 视频地址
  9796. * @param width 视频宽度
  9797. * @param height 视频高度
  9798. * @param align 视频对齐
  9799. * @param toEmbed 是否以图片代替显示
  9800. * @param addParagraph 是否需要添加P 标签
  9801. */
  9802. function creatInsertStr(url,width,height,align,toEmbed,addParagraph){
  9803. return !toEmbed ?
  9804. (addParagraph? ('<p '+ (align !="none" ? ( align == "center"? ' style="text-align:center;" ':' style="float:"'+ align ) : '') + '>'): '') +
  9805. '<img align="'+align+'" width="'+ width +'" height="' + height + '" _url="'+url+'" class="edui-faked-video"' +
  9806. ' src="'+me.options.UEDITOR_HOME_URL+'themes/default/images/spacer.gif" style="background:url('+me.options.UEDITOR_HOME_URL+'themes/default/images/videologo.gif) no-repeat center center; border:1px solid gray;" />' +
  9807. (addParagraph?'</p>':'')
  9808. :
  9809. '<embed type="application/x-shockwave-flash" class="edui-faked-video" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  9810. ' src="' + url + '" width="' + width + '" height="' + height + '" align="' + align + '"' +
  9811. ( align !="none" ? ' style= "'+ ( align == "center"? "display:block;":" float: "+ align ) + '"' :'' ) +
  9812. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  9813. }
  9814. function switchImgAndEmbed(img2embed){
  9815. var tmpdiv,
  9816. nodes =domUtils.getElementsByTagName(me.document, !img2embed ? "embed" : "img");
  9817. for(var i=0,node;node = nodes[i++];){
  9818. if(node.className!="edui-faked-video"){
  9819. continue;
  9820. }
  9821. tmpdiv = me.document.createElement("div");
  9822. //先看float在看align,浮动有的是时候是在float上定义的
  9823. var align = node.style.cssFloat;
  9824. tmpdiv.innerHTML = creatInsertStr(img2embed ? node.getAttribute("_url"):node.getAttribute("src"),node.width,node.height,align || node.getAttribute("align"),img2embed);
  9825. node.parentNode.replaceChild(tmpdiv.firstChild,node);
  9826. }
  9827. }
  9828. me.addListener("beforegetcontent",function(){
  9829. switchImgAndEmbed(true);
  9830. });
  9831. me.addListener('aftersetcontent',function(){
  9832. switchImgAndEmbed(false);
  9833. });
  9834. me.addListener('aftergetcontent',function(cmdName){
  9835. if(cmdName == 'aftergetcontent' && me.queryCommandState('source')){
  9836. return;
  9837. }
  9838. switchImgAndEmbed(false);
  9839. });
  9840. me.commands["insertvideo"] = {
  9841. execCommand: function (cmd, videoObjs){
  9842. videoObjs = utils.isArray(videoObjs)?videoObjs:[videoObjs];
  9843. var html = [];
  9844. for(var i=0,vi,len = videoObjs.length;i<len;i++){
  9845. vi = videoObjs[i];
  9846. html.push(creatInsertStr( vi.url, vi.width || 420, vi.height || 280, vi.align||"none",false,true));
  9847. }
  9848. me.execCommand("inserthtml",html.join(""));
  9849. },
  9850. queryCommandState : function(){
  9851. var img = me.selection.getRange().getClosedNode(),
  9852. flag = img && (img.className == "edui-faked-video");
  9853. return this.highlight ? -1 :(flag?1:0);
  9854. }
  9855. };
  9856. };
  9857. ///import core
  9858. ///commands 表格
  9859. ///commandsName InsertTable,DeleteTable,InsertParagraphBeforeTable,InsertRow,DeleteRow,InsertCol,DeleteCol,MergeCells,MergeRight,MergeDown,SplittoCells,SplittoRows,SplittoCols
  9860. ///commandsTitle 表格,删除表格,表格前插行,前插入行,删除行,前插入列,删除列,合并多个单元格,右合并单元格,下合并单元格,完全拆分单元格,拆分成行,拆分成列
  9861. ///commandsDialog dialogs\table\table.html
  9862. /**
  9863. * Created by .
  9864. * User: taoqili
  9865. * Date: 11-5-5
  9866. * Time: 下午2:06
  9867. * To change this template use File | Settings | File Templates.
  9868. */
  9869. /**
  9870. * table操作插件
  9871. */
  9872. UE.plugins['table'] = function () {
  9873. var me = this,
  9874. keys = domUtils.keys,
  9875. clearSelectedTd = domUtils.clearSelectedArr;
  9876. //框选时用到的几个全局变量
  9877. var anchorTd,
  9878. tableOpt,
  9879. _isEmpty = domUtils.isEmptyNode;
  9880. function getIndex( cell ) {
  9881. var cells = cell.parentNode.cells;
  9882. for ( var i = 0, ci; ci = cells[i]; i++ ) {
  9883. if ( ci === cell ) {
  9884. return i;
  9885. }
  9886. }
  9887. }
  9888. function deleteTable( table, range ) {
  9889. var p = table.ownerDocument.createElement( 'p' );
  9890. domUtils.fillNode( me.document, p );
  9891. var pN = table.parentNode;
  9892. if ( pN && pN.getAttribute( 'dropdrag' ) ) {
  9893. table = pN;
  9894. }
  9895. table.parentNode.insertBefore( p, table );
  9896. domUtils.remove( table );
  9897. range.setStart( p, 0 ).setCursor();
  9898. }
  9899. /**
  9900. * 判断当前单元格是否处于隐藏状态
  9901. * @param cell 待判断的单元格
  9902. * @return {Boolean} 隐藏时返回true,否则返回false
  9903. */
  9904. function _isHide( cell ) {
  9905. return cell.style.display == "none";
  9906. }
  9907. function getCount( arr ) {
  9908. var count = 0;
  9909. for ( var i = 0, ti; ti = arr[i++]; ) {
  9910. if ( !_isHide( ti ) ) {
  9911. count++;
  9912. }
  9913. }
  9914. return count;
  9915. }
  9916. me.currentSelectedArr = [];
  9917. me.addListener( 'mousedown', _mouseDownEvent );
  9918. me.addListener( 'keydown', function ( type, evt ) {
  9919. var keyCode = evt.keyCode || evt.which;
  9920. if ( !keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey ) {
  9921. clearSelectedTd( me.currentSelectedArr );
  9922. }
  9923. } );
  9924. me.addListener( 'mouseup', function () {
  9925. anchorTd = null;
  9926. me.removeListener( 'mouseover', _mouseDownEvent );
  9927. var td = me.currentSelectedArr[0];
  9928. if ( td ) {
  9929. me.document.body.style.webkitUserSelect = '';
  9930. var range = new dom.Range( me.document );
  9931. if ( _isEmpty( td ) ) {
  9932. range.setStart( me.currentSelectedArr[0], 0 ).setCursor();
  9933. } else {
  9934. range.selectNodeContents( me.currentSelectedArr[0] ).select();
  9935. }
  9936. } else {
  9937. //浏览器能从table外边选到里边导致currentSelectedArr为空,清掉当前选区回到选区的最开始
  9938. var range = me.selection.getRange().shrinkBoundary();
  9939. if ( !range.collapsed ) {
  9940. var start = domUtils.findParentByTagName( range.startContainer, 'td', true ),
  9941. end = domUtils.findParentByTagName( range.endContainer, 'td', true );
  9942. //在table里边的不能清除
  9943. if ( start && !end || !start && end || start && end && start !== end ) {
  9944. range.collapse( true ).select( true );
  9945. }
  9946. }
  9947. }
  9948. } );
  9949. function reset() {
  9950. me.currentSelectedArr = [];
  9951. anchorTd = null;
  9952. }
  9953. /**
  9954. * 插入表格
  9955. * @param numRows 行数
  9956. * @param numCols 列数
  9957. * @param height 列数
  9958. * @param width 列数
  9959. * @param heightUnit 列数
  9960. * @param widthUnit 列数
  9961. * @param bgColor 表格背景
  9962. * @param border 边框大小
  9963. * @param borderColor 边框颜色
  9964. * @param cellSpacing 单元格间距
  9965. * @param cellPadding 单元格边距
  9966. */
  9967. me.commands['inserttable'] = {
  9968. queryCommandState:function () {
  9969. if ( this.highlight ) {
  9970. return -1;
  9971. }
  9972. var range = this.selection.getRange();
  9973. return domUtils.findParentByTagName( range.startContainer, 'table', true )
  9974. || domUtils.findParentByTagName( range.endContainer, 'table', true )
  9975. || me.currentSelectedArr.length > 0 ? -1 : 0;
  9976. },
  9977. execCommand:function ( cmdName, opt ) {
  9978. opt = opt || {numRows:5, numCols:5,border:1};
  9979. var html = ['<table ' + (opt.border == "0" ? ' class="noBorderTable"' : '') + ' _innerCreateTable = "true" '];
  9980. if ( opt.cellSpacing && opt.cellSpacing != '0' || opt.cellPadding && opt.cellPadding != '0' ) {
  9981. html.push( ' style="border-collapse:separate;" ' );
  9982. }
  9983. opt.cellSpacing && opt.cellSpacing != '0' && html.push( ' cellSpacing="' + opt.cellSpacing + '" ' );
  9984. opt.cellPadding && opt.cellPadding != '0' && html.push( ' cellPadding="' + opt.cellPadding + '" ' );
  9985. html.push( ' width="' + (opt.width || 100) + (typeof opt.widthUnit == "undefined" ? '%' : opt.widthUnit) + '" ' );
  9986. opt.height && html.push( ' height="' + opt.height + (typeof opt.heightUnit == "undefined" ? '%' : opt.heightUnit) + '" ' );
  9987. opt.align && (html.push( ' align="' + opt.align + '" ' ));
  9988. html.push( ' border="' + (opt.border || 0) + '" borderColor="' + (opt.borderColor || '#000000') + '"' );
  9989. opt.borderType == "1" && html.push( ' borderType="1" ' );
  9990. opt.bgColor && html.push( ' bgColor="' + opt.bgColor + '"' );
  9991. html.push( ' ><tbody>' );
  9992. opt.width = Math.floor( (opt.width || '100') / opt.numCols );
  9993. for ( var i = 0; i < opt.numRows; i++ ) {
  9994. html.push( '<tr>' );
  9995. for ( var j = 0; j < opt.numCols; j++ ) {
  9996. html.push( '<td style="width:' + opt.width + (typeof opt.widthUnit == "undefined" ? '%' : opt.widthUnit) + ';'
  9997. + (opt.borderType == '1' ? 'border:' + opt.border + 'px solid ' + (opt.borderColor || '#000000') : '')
  9998. + '">'
  9999. + (browser.ie ? domUtils.fillChar : '<br/>') + '</td>' );
  10000. }
  10001. html.push( '</tr>' );
  10002. }
  10003. me.execCommand( 'insertHtml', html.join( '' ) + '</tbody></table>' );
  10004. reset();
  10005. //如果表格的align不是默认,将不占位,给后边的block元素设置clear:both
  10006. if ( opt.align ) {
  10007. var range = me.selection.getRange(),
  10008. bk = range.createBookmark(),
  10009. start = range.startContainer;
  10010. while ( start && !domUtils.isBody( start ) ) {
  10011. if ( domUtils.isBlockElm( start ) ) {
  10012. start.style.clear = 'both';
  10013. range.moveToBookmark( bk ).select();
  10014. break;
  10015. }
  10016. start = start.parentNode;
  10017. }
  10018. }
  10019. }
  10020. };
  10021. me.commands['edittable'] = {
  10022. queryCommandState:function () {
  10023. var range = this.selection.getRange();
  10024. if ( this.highlight ) {
  10025. return -1;
  10026. }
  10027. return domUtils.findParentByTagName( range.startContainer, 'table', true )
  10028. || me.currentSelectedArr.length > 0 ? 0 : -1;
  10029. },
  10030. execCommand:function ( cmdName, opt ) {
  10031. var start = me.selection.getStart(),
  10032. table = domUtils.findParentByTagName( start, 'table', true );
  10033. if ( table ) {
  10034. table.style.cssText = table.style.cssText.replace( /border[^;]+/gi, '' );
  10035. table.style.borderCollapse = opt.cellSpacing && opt.cellSpacing != '0' || opt.cellPadding && opt.cellPadding != '0' ? 'separate' : 'collapse';
  10036. opt.cellSpacing && opt.cellSpacing != '0' ? table.setAttribute( 'cellSpacing', opt.cellSpacing ) : table.removeAttribute( 'cellSpacing' );
  10037. opt.cellPadding && opt.cellPadding != '0' ? table.setAttribute( 'cellPadding', opt.cellPadding ) : table.removeAttribute( 'cellPadding' );
  10038. opt.height && table.setAttribute( 'height', opt.height + opt.heightUnit );
  10039. opt.align && table.setAttribute( 'align', opt.align );
  10040. opt.width && table.setAttribute( 'width', opt.width + opt.widthUnit );
  10041. if(opt.bgColor){
  10042. table.setAttribute( 'bgColor', opt.bgColor );
  10043. }else{
  10044. domUtils.removeAttributes(table,["bgColor"]);
  10045. }
  10046. opt.borderColor && table.setAttribute( 'borderColor', opt.borderColor );
  10047. table.setAttribute( 'border', opt.border );
  10048. if(domUtils.hasClass(table,"noBorderTable")){
  10049. domUtils.removeClasses(table,["noBorderTable"]);
  10050. }
  10051. domUtils.addClass(table,opt.border == "0" ? " noBorderTable" : "");
  10052. if ( opt.borderType == "1" ) {
  10053. for ( var i = 0, ti, tds = table.getElementsByTagName( 'td' ); ti = tds[i++]; ) {
  10054. ti.style.border = opt.border + 'px solid ' + (opt.borderColor || '#000000');
  10055. }
  10056. table.setAttribute( 'borderType', '1' );
  10057. } else {
  10058. for ( var i = 0, ti, tds = table.getElementsByTagName( 'td' ); ti = tds[i++]; ) {
  10059. if ( browser.ie ) {
  10060. ti.style.cssText = ti.style.cssText.replace( /border[^;]+/gi, '' );
  10061. } else {
  10062. domUtils.removeStyle( ti, 'border' );
  10063. domUtils.removeStyle( ti, 'border-image' );
  10064. }
  10065. }
  10066. table.removeAttribute( 'borderType' );
  10067. }
  10068. }
  10069. }
  10070. };
  10071. me.commands['edittd'] = {
  10072. queryCommandState:function () {
  10073. if ( this.highlight ) {
  10074. return -1;
  10075. }
  10076. var range = this.selection.getRange();
  10077. return (domUtils.findParentByTagName( range.startContainer, 'table', true )
  10078. && domUtils.findParentByTagName( range.endContainer, 'table', true )) || me.currentSelectedArr.length > 0 ? 0 : -1;
  10079. },
  10080. /**
  10081. * 单元格属性编辑
  10082. * @param cmdName
  10083. * @param tdItems
  10084. */
  10085. execCommand:function ( cmdName, tdItems ) {
  10086. var range = this.selection.getRange(),
  10087. tds = !me.currentSelectedArr.length ? [domUtils.findParentByTagName( range.startContainer, ['td', 'th'], true )] : me.currentSelectedArr;
  10088. for ( var i = 0, td; td = tds[i++]; ) {
  10089. domUtils.setAttributes( td, {
  10090. "bgColor":tdItems.bgColor,
  10091. "align":tdItems.align,
  10092. "vAlign":tdItems.vAlign
  10093. } );
  10094. }
  10095. }
  10096. };
  10097. /**
  10098. * 删除表格
  10099. */
  10100. me.commands['deletetable'] = {
  10101. queryCommandState:function () {
  10102. if ( this.highlight ) {
  10103. return -1;
  10104. }
  10105. var range = this.selection.getRange();
  10106. return (domUtils.findParentByTagName( range.startContainer, 'table', true )
  10107. && domUtils.findParentByTagName( range.endContainer, 'table', true )) || me.currentSelectedArr.length > 0 ? 0 : -1;
  10108. },
  10109. execCommand:function () {
  10110. var range = this.selection.getRange(),
  10111. table = domUtils.findParentByTagName( me.currentSelectedArr.length > 0 ? me.currentSelectedArr[0] : range.startContainer, 'table', true );
  10112. deleteTable( table, range );
  10113. reset();
  10114. }
  10115. };
  10116. /**
  10117. * 向右合并单元格
  10118. */
  10119. me.commands['mergeright'] = {
  10120. queryCommandState:function () {
  10121. if ( this.highlight ) {
  10122. return -1;
  10123. }
  10124. var range = this.selection.getRange(),
  10125. start = range.startContainer,
  10126. td = domUtils.findParentByTagName( start, ['td', 'th'], true );
  10127. if ( !td || this.currentSelectedArr.length > 1 ){
  10128. return -1;
  10129. }
  10130. var tr = td.parentNode;
  10131. //最右边行不能向右合并
  10132. var rightCellIndex = getIndex( td ) + td.colSpan;
  10133. if ( rightCellIndex >= tr.cells.length ) {
  10134. return -1;
  10135. }
  10136. //单元格不在同一行不能向右合并
  10137. var rightCell = tr.cells[rightCellIndex];
  10138. if ( _isHide( rightCell ) ) {
  10139. return -1;
  10140. }
  10141. return td.rowSpan == rightCell.rowSpan ? 0 : -1;
  10142. },
  10143. execCommand:function () {
  10144. var range = this.selection.getRange(),
  10145. start = range.startContainer,
  10146. td = domUtils.findParentByTagName( start, ['td', 'th'], true ) || me.currentSelectedArr[0],
  10147. tr = td.parentNode,
  10148. rows = tr.parentNode.parentNode.rows;
  10149. //找到当前单元格右边的未隐藏单元格
  10150. var rightCellRowIndex = tr.rowIndex,
  10151. rightCellCellIndex = getIndex( td ) + td.colSpan,
  10152. rightCell = rows[rightCellRowIndex].cells[rightCellCellIndex];
  10153. //在隐藏的原生td对象上增加两个属性,分别表示当前td对应的真实td坐标
  10154. for ( var i = rightCellRowIndex; i < rightCellRowIndex + rightCell.rowSpan; i++ ) {
  10155. for ( var j = rightCellCellIndex; j < rightCellCellIndex + rightCell.colSpan; j++ ) {
  10156. var tmpCell = rows[i].cells[j];
  10157. tmpCell.setAttribute( 'rootRowIndex', tr.rowIndex );
  10158. tmpCell.setAttribute( 'rootCellIndex', getIndex( td ) );
  10159. }
  10160. }
  10161. //合并单元格
  10162. td.colSpan += rightCell.colSpan || 1;
  10163. //合并内容
  10164. _moveContent( td, rightCell );
  10165. //删除被合并的单元格,此处用隐藏方式实现来提升性能
  10166. rightCell.style.display = "none";
  10167. //重新让单元格获取焦点
  10168. //trace:1565
  10169. if ( domUtils.isEmptyBlock( td ) ) {
  10170. range.setStart( td, 0 ).setCursor();
  10171. } else {
  10172. range.selectNodeContents( td ).setCursor( true, true );
  10173. }
  10174. //处理有寛高,导致ie的文字不能输入占满
  10175. browser.ie && domUtils.removeAttributes( td, ['width', 'height'] );
  10176. }
  10177. };
  10178. /**
  10179. * 向下合并单元格
  10180. */
  10181. me.commands['mergedown'] = {
  10182. queryCommandState:function () {
  10183. if ( this.highlight ) {
  10184. return -1;
  10185. }
  10186. var range = this.selection.getRange(),
  10187. start = range.startContainer,
  10188. td = domUtils.findParentByTagName( start, 'td', true );
  10189. if ( !td || getCount( me.currentSelectedArr ) > 1 ){
  10190. return -1;
  10191. }
  10192. var tr = td.parentNode,
  10193. table = tr.parentNode.parentNode,
  10194. rows = table.rows;
  10195. //已经是最底行,不能向下合并
  10196. var downCellRowIndex = tr.rowIndex + td.rowSpan;
  10197. if ( downCellRowIndex >= rows.length ) {
  10198. return -1;
  10199. }
  10200. //如果下一个单元格是隐藏的,表明他是由左边span过来的,不能向下合并
  10201. var downCell = rows[downCellRowIndex].cells[getIndex( td )];
  10202. if ( _isHide( downCell ) ) {
  10203. return -1;
  10204. }
  10205. //只有列span都相等时才能合并
  10206. return td.colSpan == downCell.colSpan ? 0 : -1;
  10207. },
  10208. execCommand:function () {
  10209. var range = this.selection.getRange(),
  10210. start = range.startContainer,
  10211. td = domUtils.findParentByTagName( start, ['td', 'th'], true ) || me.currentSelectedArr[0];
  10212. var tr = td.parentNode,
  10213. rows = tr.parentNode.parentNode.rows;
  10214. var downCellRowIndex = tr.rowIndex + td.rowSpan,
  10215. downCellCellIndex = getIndex( td ),
  10216. downCell = rows[downCellRowIndex].cells[downCellCellIndex];
  10217. //找到当前列的下一个未被隐藏的单元格
  10218. for ( var i = downCellRowIndex; i < downCellRowIndex + downCell.rowSpan; i++ ) {
  10219. for ( var j = downCellCellIndex; j < downCellCellIndex + downCell.colSpan; j++ ) {
  10220. var tmpCell = rows[i].cells[j];
  10221. tmpCell.setAttribute( 'rootRowIndex', tr.rowIndex );
  10222. tmpCell.setAttribute( 'rootCellIndex', getIndex( td ) );
  10223. }
  10224. }
  10225. //合并单元格
  10226. td.rowSpan += downCell.rowSpan || 1;
  10227. //合并内容
  10228. _moveContent( td, downCell );
  10229. //删除被合并的单元格,此处用隐藏方式实现来提升性能
  10230. downCell.style.display = "none";
  10231. //重新让单元格获取焦点
  10232. if ( domUtils.isEmptyBlock( td ) ) {
  10233. range.setStart( td, 0 ).setCursor();
  10234. } else {
  10235. range.selectNodeContents( td ).setCursor( true, true );
  10236. }
  10237. //处理有寛高,导致ie的文字不能输入占满
  10238. browser.ie && domUtils.removeAttributes( td, ['width', 'height'] );
  10239. }
  10240. };
  10241. /**
  10242. * 删除行
  10243. */
  10244. me.commands['deleterow'] = {
  10245. queryCommandState:function () {
  10246. if ( this.highlight ) {
  10247. return -1;
  10248. }
  10249. var range = this.selection.getRange(),
  10250. start = range.startContainer,
  10251. td = domUtils.findParentByTagName( start, ['td', 'th'], true );
  10252. if ( !td && me.currentSelectedArr.length == 0 ){
  10253. return -1;
  10254. }
  10255. return 0;
  10256. },
  10257. execCommand:function () {
  10258. var range = this.selection.getRange(),
  10259. start = range.startContainer,
  10260. td = domUtils.findParentByTagName( start, ['td', 'th'], true ),
  10261. tr,
  10262. table,
  10263. cells,
  10264. rows ,
  10265. rowIndex ,
  10266. cellIndex;
  10267. if ( td && me.currentSelectedArr.length == 0 ) {
  10268. var count = (td.rowSpan || 1) - 1;
  10269. me.currentSelectedArr.push( td );
  10270. tr = td.parentNode;
  10271. table = tr.parentNode.parentNode;
  10272. rows = table.rows,
  10273. rowIndex = tr.rowIndex + 1,
  10274. cellIndex = getIndex( td );
  10275. while ( count ) {
  10276. me.currentSelectedArr.push( rows[rowIndex].cells[cellIndex] );
  10277. count--;
  10278. rowIndex++;
  10279. }
  10280. }
  10281. while ( td = me.currentSelectedArr.pop() ) {
  10282. if ( !domUtils.findParentByTagName( td, 'table' ) ) {//|| _isHide(td)
  10283. continue;
  10284. }
  10285. tr = td.parentNode,
  10286. table = tr.parentNode.parentNode;
  10287. cells = tr.cells,
  10288. rows = table.rows,
  10289. rowIndex = tr.rowIndex,
  10290. cellIndex = getIndex( td );
  10291. /*
  10292. * 从最左边开始扫描并隐藏当前行的所有单元格
  10293. * 若当前单元格的display为none,往上找到它所在的真正单元格,获取colSpan和rowSpan,
  10294. * 将rowspan减一,并跳转到cellIndex+colSpan列继续处理
  10295. * 若当前单元格的display不为none,分两种情况:
  10296. * 1、rowspan == 1 ,直接设置display为none,跳转到cellIndex+colSpan列继续处理
  10297. * 2、rowspan > 1 , 修改当前单元格的下一个单元格的display为"",
  10298. * 并将当前单元格的rowspan-1赋给下一个单元格的rowspan,当前单元格的colspan赋给下一个单元格的colspan,
  10299. * 然后隐藏当前单元格,跳转到cellIndex+colSpan列继续处理
  10300. */
  10301. for ( var currentCellIndex = 0; currentCellIndex < cells.length; ) {
  10302. var currentNode = cells[currentCellIndex];
  10303. if ( _isHide( currentNode ) ) {
  10304. var topNode = rows[currentNode.getAttribute( 'rootRowIndex' )].cells[currentNode.getAttribute( 'rootCellIndex' )];
  10305. topNode.rowSpan--;
  10306. currentCellIndex += topNode.colSpan;
  10307. } else {
  10308. if ( currentNode.rowSpan == 1 ) {
  10309. currentCellIndex += currentNode.colSpan;
  10310. } else {
  10311. var downNode = rows[rowIndex + 1].cells[currentCellIndex];
  10312. downNode.style.display = "";
  10313. downNode.rowSpan = currentNode.rowSpan - 1;
  10314. downNode.colSpan = currentNode.colSpan;
  10315. currentCellIndex += currentNode.colSpan;
  10316. }
  10317. }
  10318. }
  10319. //完成更新后再删除外层包裹的tr
  10320. domUtils.remove( tr );
  10321. //重新定位焦点
  10322. var topRowTd, focusTd, downRowTd;
  10323. if ( rowIndex == rows.length ) { //如果被删除的行是最后一行,这里之所以没有-1是因为已经删除了一行
  10324. //如果删除的行也是第一行,那么表格总共只有一行,删除整个表格
  10325. if ( rowIndex == 0 ) {
  10326. deleteTable( table, range );
  10327. return;
  10328. }
  10329. //如果上一单元格未隐藏,则直接定位,否则定位到最近的上一个非隐藏单元格
  10330. var preRowIndex = rowIndex - 1;
  10331. topRowTd = rows[preRowIndex].cells[ cellIndex];
  10332. focusTd = _isHide( topRowTd ) ? rows[topRowTd.getAttribute( 'rootRowIndex' )].cells[topRowTd.getAttribute( 'rootCellIndex' )] : topRowTd;
  10333. } else { //如果被删除的不是最后一行,则光标定位到下一行,此处未加1是因为已经删除了一行
  10334. downRowTd = rows[rowIndex].cells[cellIndex];
  10335. focusTd = _isHide( downRowTd ) ? rows[downRowTd.getAttribute( 'rootRowIndex' )].cells[downRowTd.getAttribute( 'rootCellIndex' )] : downRowTd;
  10336. }
  10337. }
  10338. range.setStart( focusTd, 0 ).setCursor();
  10339. update( table );
  10340. }
  10341. };
  10342. /**
  10343. * 删除列
  10344. */
  10345. me.commands['deletecol'] = {
  10346. queryCommandState:function () {
  10347. if ( this.highlight ) {
  10348. return -1;
  10349. }
  10350. var range = this.selection.getRange(),
  10351. start = range.startContainer,
  10352. td = domUtils.findParentByTagName( start, ['td', 'th'], true );
  10353. if ( !td && me.currentSelectedArr.length == 0 )return -1;
  10354. return 0;
  10355. },
  10356. execCommand:function () {
  10357. var range = this.selection.getRange(),
  10358. start = range.startContainer,
  10359. td = domUtils.findParentByTagName( start, ['td', 'th'], true );
  10360. if ( td && me.currentSelectedArr.length == 0 ) {
  10361. var count = (td.colSpan || 1) - 1;
  10362. me.currentSelectedArr.push( td );
  10363. while ( count ) {
  10364. do {
  10365. td = td.nextSibling
  10366. } while ( td.nodeType == 3 );
  10367. me.currentSelectedArr.push( td );
  10368. count--;
  10369. }
  10370. }
  10371. while ( td = me.currentSelectedArr.pop() ) {
  10372. if ( !domUtils.findParentByTagName( td, 'table' ) ) { //|| _isHide(td)
  10373. continue;
  10374. }
  10375. var tr = td.parentNode,
  10376. table = tr.parentNode.parentNode,
  10377. cellIndex = getIndex( td ),
  10378. rows = table.rows,
  10379. cells = tr.cells,
  10380. rowIndex = tr.rowIndex;
  10381. /*
  10382. * 从第一行开始扫描并隐藏当前列的所有单元格
  10383. * 若当前单元格的display为none,表明它是由左边Span过来的,
  10384. * 将左边第一个非none单元格的colSpan减去1并删去对应的单元格后跳转到rowIndex + rowspan行继续处理;
  10385. * 若当前单元格的display不为none,分两种情况,
  10386. * 1、当前单元格的colspan == 1 , 则直接删除该节点,跳转到rowIndex + rowspan行继续处理
  10387. * 2、当前单元格的colsapn > 1, 修改当前单元格右边单元格的display为"",
  10388. * 并将当前单元格的colspan-1赋给它的colspan,当前单元格的rolspan赋给它的rolspan,
  10389. * 然后删除当前单元格,跳转到rowIndex+rowSpan行继续处理
  10390. */
  10391. var rowSpan;
  10392. for ( var currentRowIndex = 0; currentRowIndex < rows.length; ) {
  10393. var currentNode = rows[currentRowIndex].cells[cellIndex];
  10394. if ( _isHide( currentNode ) ) {
  10395. var leftNode = rows[currentNode.getAttribute( 'rootRowIndex' )].cells[currentNode.getAttribute( 'rootCellIndex' )];
  10396. //依次删除对应的单元格
  10397. rowSpan = leftNode.rowSpan;
  10398. for ( var i = 0; i < leftNode.rowSpan; i++ ) {
  10399. var delNode = rows[currentRowIndex + i].cells[cellIndex];
  10400. domUtils.remove( delNode );
  10401. }
  10402. //修正被删后的单元格信息
  10403. leftNode.colSpan--;
  10404. currentRowIndex += rowSpan;
  10405. } else {
  10406. if ( currentNode.colSpan == 1 ) {
  10407. rowSpan = currentNode.rowSpan;
  10408. for ( var i = currentRowIndex, l = currentRowIndex + currentNode.rowSpan; i < l; i++ ) {
  10409. domUtils.remove( rows[i].cells[cellIndex] );
  10410. }
  10411. currentRowIndex += rowSpan;
  10412. } else {
  10413. var rightNode = rows[currentRowIndex].cells[cellIndex + 1];
  10414. rightNode.style.display = "";
  10415. rightNode.rowSpan = currentNode.rowSpan;
  10416. rightNode.colSpan = currentNode.colSpan - 1;
  10417. currentRowIndex += currentNode.rowSpan;
  10418. domUtils.remove( currentNode );
  10419. }
  10420. }
  10421. }
  10422. //重新定位焦点
  10423. var preColTd, focusTd, nextColTd;
  10424. if ( cellIndex == cells.length ) { //如果当前列是最后一列,光标定位到当前列的前一列,同样,这里没有减去1是因为已经被删除了一列
  10425. //如果当前列也是第一列,则删除整个表格
  10426. if ( cellIndex == 0 ) {
  10427. deleteTable( table, range );
  10428. return;
  10429. }
  10430. //找到当前单元格前一列中和本单元格最近的一个未隐藏单元格
  10431. var preCellIndex = cellIndex - 1;
  10432. preColTd = rows[rowIndex].cells[preCellIndex];
  10433. focusTd = _isHide( preColTd ) ? rows[preColTd.getAttribute( 'rootRowIndex' )].cells[preColTd.getAttribute( 'rootCellIndex' )] : preColTd;
  10434. } else { //如果当前列不是最后一列,则光标定位到当前列的后一列
  10435. nextColTd = rows[rowIndex].cells[cellIndex];
  10436. focusTd = _isHide( nextColTd ) ? rows[nextColTd.getAttribute( 'rootRowIndex' )].cells[nextColTd.getAttribute( 'rootCellIndex' )] : nextColTd;
  10437. }
  10438. }
  10439. range.setStart( focusTd, 0 ).setCursor();
  10440. update( table )
  10441. }
  10442. };
  10443. /**
  10444. * 完全拆分单元格
  10445. */
  10446. me.commands['splittocells'] = {
  10447. queryCommandState:function () {
  10448. if ( this.highlight ) {
  10449. return -1;
  10450. }
  10451. var range = this.selection.getRange(),
  10452. start = range.startContainer,
  10453. td = domUtils.findParentByTagName( start, ['td', 'th'], true );
  10454. return td && ( td.rowSpan > 1 || td.colSpan > 1 ) && (!me.currentSelectedArr.length || getCount( me.currentSelectedArr ) == 1) ? 0 : -1;
  10455. },
  10456. execCommand:function () {
  10457. var range = this.selection.getRange(),
  10458. start = range.startContainer,
  10459. td = domUtils.findParentByTagName( start, ['td', 'th'], true ),
  10460. tr = td.parentNode,
  10461. table = tr.parentNode.parentNode;
  10462. var rowIndex = tr.rowIndex,
  10463. cellIndex = getIndex( td ),
  10464. rowSpan = td.rowSpan,
  10465. colSpan = td.colSpan;
  10466. for ( var i = 0; i < rowSpan; i++ ) {
  10467. for ( var j = 0; j < colSpan; j++ ) {
  10468. var cell = table.rows[rowIndex + i].cells[cellIndex + j];
  10469. cell.rowSpan = 1;
  10470. cell.colSpan = 1;
  10471. if ( _isHide( cell ) ) {
  10472. cell.style.display = "";
  10473. cell.innerHTML = browser.ie ? '' : "<br/>";
  10474. }
  10475. }
  10476. }
  10477. }
  10478. };
  10479. /**
  10480. * 将单元格拆分成行
  10481. */
  10482. me.commands['splittorows'] = {
  10483. queryCommandState:function () {
  10484. if ( this.highlight ) {
  10485. return -1;
  10486. }
  10487. var range = this.selection.getRange(),
  10488. start = range.startContainer,
  10489. td = domUtils.findParentByTagName( start, 'td', true ) || me.currentSelectedArr[0];
  10490. return td && ( td.rowSpan > 1) && (!me.currentSelectedArr.length || getCount( me.currentSelectedArr ) == 1) ? 0 : -1;
  10491. },
  10492. execCommand:function () {
  10493. var range = this.selection.getRange(),
  10494. start = range.startContainer,
  10495. td = domUtils.findParentByTagName( start, 'td', true ) || me.currentSelectedArr[0],
  10496. tr = td.parentNode,
  10497. rows = tr.parentNode.parentNode.rows;
  10498. var rowIndex = tr.rowIndex,
  10499. cellIndex = getIndex( td ),
  10500. rowSpan = td.rowSpan,
  10501. colSpan = td.colSpan;
  10502. for ( var i = 0; i < rowSpan; i++ ) {
  10503. var cells = rows[rowIndex + i],
  10504. cell = cells.cells[cellIndex];
  10505. cell.rowSpan = 1;
  10506. cell.colSpan = colSpan;
  10507. if ( _isHide( cell ) ) {
  10508. cell.style.display = "";
  10509. //原有的内容要清除掉
  10510. cell.innerHTML = browser.ie ? '' : '<br/>'
  10511. }
  10512. //修正被隐藏单元格中存储的rootRowIndex和rootCellIndex信息
  10513. for ( var j = cellIndex + 1; j < cellIndex + colSpan; j++ ) {
  10514. cell = cells.cells[j];
  10515. cell.setAttribute( 'rootRowIndex', rowIndex + i )
  10516. }
  10517. }
  10518. clearSelectedTd( me.currentSelectedArr );
  10519. this.selection.getRange().setStart( td, 0 ).setCursor();
  10520. }
  10521. };
  10522. /**
  10523. * 在表格前插入行
  10524. */
  10525. me.commands['insertparagraphbeforetable'] = {
  10526. queryCommandState:function () {
  10527. if ( this.highlight ) {
  10528. return -1;
  10529. }
  10530. var range = this.selection.getRange(),
  10531. start = range.startContainer,
  10532. td = domUtils.findParentByTagName( start, 'td', true ) || me.currentSelectedArr[0];
  10533. return td && domUtils.findParentByTagName( td, 'table' ) ? 0 : -1;
  10534. },
  10535. execCommand:function () {
  10536. var range = this.selection.getRange(),
  10537. start = range.startContainer,
  10538. table = domUtils.findParentByTagName( start, 'table', true );
  10539. start = me.document.createElement( me.options.enterTag );
  10540. table.parentNode.insertBefore( start, table );
  10541. clearSelectedTd( me.currentSelectedArr );
  10542. if ( start.tagName == 'P' ) {
  10543. //trace:868
  10544. start.innerHTML = browser.ie ? '' : '<br/>';
  10545. range.setStart( start, 0 )
  10546. } else {
  10547. range.setStartBefore( start )
  10548. }
  10549. range.setCursor();
  10550. }
  10551. };
  10552. /**
  10553. * 将单元格拆分成列
  10554. */
  10555. me.commands['splittocols'] = {
  10556. queryCommandState:function () {
  10557. if ( this.highlight ) {
  10558. return -1;
  10559. }
  10560. var range = this.selection.getRange(),
  10561. start = range.startContainer,
  10562. td = domUtils.findParentByTagName( start, ['td', 'th'], true ) || me.currentSelectedArr[0];
  10563. return td && ( td.colSpan > 1) && (!me.currentSelectedArr.length || getCount( me.currentSelectedArr ) == 1) ? 0 : -1;
  10564. },
  10565. execCommand:function () {
  10566. var range = this.selection.getRange(),
  10567. start = range.startContainer,
  10568. td = domUtils.findParentByTagName( start, ['td', 'th'], true ) || me.currentSelectedArr[0],
  10569. tr = td.parentNode,
  10570. rows = tr.parentNode.parentNode.rows;
  10571. var rowIndex = tr.rowIndex,
  10572. cellIndex = getIndex( td ),
  10573. rowSpan = td.rowSpan,
  10574. colSpan = td.colSpan;
  10575. for ( var i = 0; i < colSpan; i++ ) {
  10576. var cell = rows[rowIndex].cells[cellIndex + i];
  10577. cell.rowSpan = rowSpan;
  10578. cell.colSpan = 1;
  10579. if ( _isHide( cell ) ) {
  10580. cell.style.display = "";
  10581. cell.innerHTML = browser.ie ? '' : '<br/>'
  10582. }
  10583. for ( var j = rowIndex + 1; j < rowIndex + rowSpan; j++ ) {
  10584. var tmpCell = rows[j].cells[cellIndex + i];
  10585. tmpCell.setAttribute( 'rootCellIndex', cellIndex + i );
  10586. }
  10587. }
  10588. clearSelectedTd( me.currentSelectedArr );
  10589. this.selection.getRange().setStart( td, 0 ).setCursor();
  10590. }
  10591. };
  10592. /**
  10593. * 插入行
  10594. */
  10595. me.commands['insertrow'] = {
  10596. queryCommandState:function () {
  10597. if ( this.highlight ) {
  10598. return -1;
  10599. }
  10600. var range = this.selection.getRange();
  10601. return domUtils.findParentByTagName( range.startContainer, 'table', true )
  10602. || domUtils.findParentByTagName( range.endContainer, 'table', true ) || me.currentSelectedArr.length != 0 ? 0 : -1;
  10603. },
  10604. execCommand:function () {
  10605. var range = this.selection.getRange(),
  10606. start = range.startContainer,
  10607. tr = domUtils.findParentByTagName( start, 'tr', true ) || me.currentSelectedArr[0].parentNode,
  10608. table = tr.parentNode.parentNode,
  10609. rows = table.rows;
  10610. //记录插入位置原来所有的单元格
  10611. var rowIndex = tr.rowIndex,
  10612. cells = rows[rowIndex].cells;
  10613. //插入新的一行
  10614. var newRow = table.insertRow( rowIndex );
  10615. var newCell;
  10616. //遍历表格中待插入位置中的所有单元格,检查其状态,并据此修正新插入行的单元格状态
  10617. for ( var cellIndex = 0; cellIndex < cells.length; ) {
  10618. var tmpCell = cells[cellIndex];
  10619. if ( _isHide( tmpCell ) ) { //如果当前单元格是隐藏的,表明当前单元格由其上部span过来,找到其上部单元格
  10620. //找到被隐藏单元格真正所属的单元格
  10621. var topCell = rows[tmpCell.getAttribute( 'rootRowIndex' )].cells[tmpCell.getAttribute( 'rootCellIndex' )];
  10622. //增加一行,并将所有新插入的单元格隐藏起来
  10623. topCell.rowSpan++;
  10624. for ( var i = 0; i < topCell.colSpan; i++ ) {
  10625. newCell = tmpCell.cloneNode( false );
  10626. domUtils.removeAttributes( newCell, ["bgColor", "valign", "align"] );
  10627. newCell.rowSpan = newCell.colSpan = 1;
  10628. newCell.innerHTML = browser.ie ? '' : "<br/>";
  10629. newCell.className = '';
  10630. if ( newRow.children[cellIndex + i] ) {
  10631. newRow.insertBefore( newCell, newRow.children[cellIndex + i] );
  10632. } else {
  10633. newRow.appendChild( newCell )
  10634. }
  10635. newCell.style.display = "none";
  10636. }
  10637. cellIndex += topCell.colSpan;
  10638. } else {//若当前单元格未隐藏,则在其上行插入colspan个单元格
  10639. for ( var j = 0; j < tmpCell.colSpan; j++ ) {
  10640. newCell = tmpCell.cloneNode( false );
  10641. domUtils.removeAttributes( newCell, ["bgColor", "valign", "align"] );
  10642. newCell.rowSpan = newCell.colSpan = 1;
  10643. newCell.innerHTML = browser.ie ? '' : "<br/>";
  10644. newCell.className = '';
  10645. if ( newRow.children[cellIndex + j] ) {
  10646. newRow.insertBefore( newCell, newRow.children[cellIndex + j] );
  10647. } else {
  10648. newRow.appendChild( newCell )
  10649. }
  10650. }
  10651. cellIndex += tmpCell.colSpan;
  10652. }
  10653. }
  10654. update( table );
  10655. range.setStart( newRow.cells[0], 0 ).setCursor();
  10656. clearSelectedTd( me.currentSelectedArr );
  10657. }
  10658. };
  10659. /**
  10660. * 插入列
  10661. */
  10662. me.commands['insertcol'] = {
  10663. queryCommandState:function () {
  10664. if ( this.highlight ) {
  10665. return -1;
  10666. }
  10667. var range = this.selection.getRange();
  10668. return domUtils.findParentByTagName( range.startContainer, 'table', true )
  10669. || domUtils.findParentByTagName( range.endContainer, 'table', true ) || me.currentSelectedArr.length != 0 ? 0 : -1;
  10670. },
  10671. execCommand:function () {
  10672. var range = this.selection.getRange(),
  10673. start = range.startContainer,
  10674. td = domUtils.findParentByTagName( start, ['td', 'th'], true ) || me.currentSelectedArr[0],
  10675. table = domUtils.findParentByTagName( td, 'table' ),
  10676. rows = table.rows;
  10677. var cellIndex = getIndex( td ),
  10678. newCell;
  10679. //遍历当前列中的所有单元格,检查其状态,并据此修正新插入列的单元格状态
  10680. for ( var rowIndex = 0; rowIndex < rows.length; ) {
  10681. var tmpCell = rows[rowIndex].cells[cellIndex], tr;
  10682. if ( _isHide( tmpCell ) ) {//如果当前单元格是隐藏的,表明当前单元格由其左边span过来,找到其左边单元格
  10683. var leftCell = rows[tmpCell.getAttribute( 'rootRowIndex' )].cells[tmpCell.getAttribute( 'rootCellIndex' )];
  10684. leftCell.colSpan++;
  10685. for ( var i = 0; i < leftCell.rowSpan; i++ ) {
  10686. newCell = td.cloneNode( false );
  10687. domUtils.removeAttributes( newCell, ["bgColor", "valign", "align"] );
  10688. newCell.rowSpan = newCell.colSpan = 1;
  10689. newCell.innerHTML = browser.ie ? '' : "<br/>";
  10690. newCell.className = '';
  10691. tr = rows[rowIndex + i];
  10692. if ( tr.children[cellIndex] ) {
  10693. tr.insertBefore( newCell, tr.children[cellIndex] );
  10694. } else {
  10695. tr.appendChild( newCell )
  10696. }
  10697. newCell.style.display = "none";
  10698. }
  10699. rowIndex += leftCell.rowSpan;
  10700. } else { //若当前单元格未隐藏,则在其左边插入rowspan个单元格
  10701. for ( var j = 0; j < tmpCell.rowSpan; j++ ) {
  10702. newCell = td.cloneNode( false );
  10703. domUtils.removeAttributes( newCell, ["bgColor", "valign", "align"] );
  10704. newCell.rowSpan = newCell.colSpan = 1;
  10705. newCell.innerHTML = browser.ie ? '' : "<br/>";
  10706. newCell.className = '';
  10707. tr = rows[rowIndex + j];
  10708. if ( tr.children[cellIndex] ) {
  10709. tr.insertBefore( newCell, tr.children[cellIndex] );
  10710. } else {
  10711. tr.appendChild( newCell )
  10712. }
  10713. newCell.innerHTML = browser.ie ? '' : "<br/>";
  10714. }
  10715. rowIndex += tmpCell.rowSpan;
  10716. }
  10717. }
  10718. update( table );
  10719. range.setStart( rows[0].cells[cellIndex], 0 ).setCursor();
  10720. clearSelectedTd( me.currentSelectedArr );
  10721. }
  10722. };
  10723. /**
  10724. * 合并多个单元格,通过两个cell将当前包含的所有横纵单元格进行合并
  10725. */
  10726. me.commands['mergecells'] = {
  10727. queryCommandState:function () {
  10728. if ( this.highlight ) {
  10729. return -1;
  10730. }
  10731. var count = 0;
  10732. for ( var i = 0, ti; ti = this.currentSelectedArr[i++]; ) {
  10733. if ( !_isHide( ti ) )
  10734. count++;
  10735. }
  10736. return count > 1 ? 0 : -1;
  10737. },
  10738. execCommand:function () {
  10739. var start = me.currentSelectedArr[0],
  10740. end = me.currentSelectedArr[me.currentSelectedArr.length - 1],
  10741. table = domUtils.findParentByTagName( start, 'table' ),
  10742. rows = table.rows,
  10743. cellsRange = {
  10744. beginRowIndex:start.parentNode.rowIndex,
  10745. beginCellIndex:getIndex( start ),
  10746. endRowIndex:end.parentNode.rowIndex,
  10747. endCellIndex:getIndex( end )
  10748. },
  10749. beginRowIndex = cellsRange.beginRowIndex,
  10750. beginCellIndex = cellsRange.beginCellIndex,
  10751. rowsLength = cellsRange.endRowIndex - cellsRange.beginRowIndex + 1,
  10752. cellLength = cellsRange.endCellIndex - cellsRange.beginCellIndex + 1,
  10753. tmp = rows[beginRowIndex].cells[beginCellIndex];
  10754. for ( var i = 0, ri; (ri = rows[beginRowIndex + i++]) && i <= rowsLength; ) {
  10755. for ( var j = 0, ci; (ci = ri.cells[beginCellIndex + j++]) && j <= cellLength; ) {
  10756. if ( i == 1 && j == 1 ) {
  10757. ci.style.display = "";
  10758. ci.rowSpan = rowsLength;
  10759. ci.colSpan = cellLength;
  10760. } else {
  10761. ci.style.display = "none";
  10762. ci.rowSpan = 1;
  10763. ci.colSpan = 1;
  10764. ci.setAttribute( 'rootRowIndex', beginRowIndex );
  10765. ci.setAttribute( 'rootCellIndex', beginCellIndex );
  10766. //传递内容
  10767. _moveContent( tmp, ci );
  10768. }
  10769. }
  10770. }
  10771. this.selection.getRange().setStart( tmp, 0 ).setCursor();
  10772. //处理有寛高,导致ie的文字不能输入占满
  10773. browser.ie && domUtils.removeAttributes( tmp, ['width', 'height'] );
  10774. clearSelectedTd( me.currentSelectedArr );
  10775. }
  10776. };
  10777. /**
  10778. * 将cellFrom单元格中的内容移动到cellTo中
  10779. * @param cellTo 目标单元格
  10780. * @param cellFrom 源单元格
  10781. */
  10782. function _moveContent( cellTo, cellFrom ) {
  10783. if ( _isEmpty( cellFrom ) ) return;
  10784. if ( _isEmpty( cellTo ) ) {
  10785. cellTo.innerHTML = cellFrom.innerHTML;
  10786. return;
  10787. }
  10788. var child = cellTo.lastChild;
  10789. if ( child.nodeType != 1 || child.tagName != 'BR' ) {
  10790. cellTo.appendChild( cellTo.ownerDocument.createElement( 'br' ) )
  10791. }
  10792. //依次移动内容
  10793. while ( child = cellFrom.firstChild ) {
  10794. cellTo.appendChild( child );
  10795. }
  10796. }
  10797. /**
  10798. * 根据两个单元格来获取中间包含的所有单元格集合选区
  10799. * @param cellA
  10800. * @param cellB
  10801. * @return {Object} 选区的左上和右下坐标
  10802. */
  10803. function _getCellsRange( cellA, cellB ) {
  10804. var trA = cellA.parentNode,
  10805. trB = cellB.parentNode,
  10806. aRowIndex = trA.rowIndex,
  10807. bRowIndex = trB.rowIndex,
  10808. rows = trA.parentNode.parentNode.rows,
  10809. rowsNum = rows.length,
  10810. cellsNum = rows[0].cells.length,
  10811. cellAIndex = getIndex( cellA ),
  10812. cellBIndex = getIndex( cellB );
  10813. if ( cellA == cellB ) {
  10814. return {
  10815. beginRowIndex:aRowIndex,
  10816. beginCellIndex:cellAIndex,
  10817. endRowIndex:aRowIndex + cellA.rowSpan - 1,
  10818. endCellIndex:cellBIndex + cellA.colSpan - 1
  10819. }
  10820. }
  10821. var
  10822. beginRowIndex = Math.min( aRowIndex, bRowIndex ),
  10823. beginCellIndex = Math.min( cellAIndex, cellBIndex ),
  10824. endRowIndex = Math.max( aRowIndex + cellA.rowSpan - 1, bRowIndex + cellB.rowSpan - 1 ),
  10825. endCellIndex = Math.max( cellAIndex + cellA.colSpan - 1, cellBIndex + cellB.colSpan - 1 );
  10826. while ( 1 ) {
  10827. var tmpBeginRowIndex = beginRowIndex,
  10828. tmpBeginCellIndex = beginCellIndex,
  10829. tmpEndRowIndex = endRowIndex,
  10830. tmpEndCellIndex = endCellIndex;
  10831. // 检查是否有超出TableRange上边界的情况
  10832. if ( beginRowIndex > 0 ) {
  10833. for ( cellIndex = beginCellIndex; cellIndex <= endCellIndex; ) {
  10834. var currentTopTd = rows[beginRowIndex].cells[cellIndex];
  10835. if ( _isHide( currentTopTd ) ) {
  10836. //overflowRowIndex = beginRowIndex == currentTopTd.rootRowIndex ? 1:0;
  10837. beginRowIndex = currentTopTd.getAttribute( 'rootRowIndex' );
  10838. currentTopTd = rows[currentTopTd.getAttribute( 'rootRowIndex' )].cells[currentTopTd.getAttribute( 'rootCellIndex' )];
  10839. }
  10840. cellIndex = getIndex( currentTopTd ) + (currentTopTd.colSpan || 1);
  10841. }
  10842. }
  10843. //检查是否有超出左边界的情况
  10844. if ( beginCellIndex > 0 ) {
  10845. for ( var rowIndex = beginRowIndex; rowIndex <= endRowIndex; ) {
  10846. var currentLeftTd = rows[rowIndex].cells[beginCellIndex];
  10847. if ( _isHide( currentLeftTd ) ) {
  10848. // overflowCellIndex = beginCellIndex== currentLeftTd.rootCellIndex ? 1:0;
  10849. beginCellIndex = currentLeftTd.getAttribute( 'rootCellIndex' );
  10850. currentLeftTd = rows[currentLeftTd.getAttribute( 'rootRowIndex' )].cells[currentLeftTd.getAttribute( 'rootCellIndex' )];
  10851. }
  10852. rowIndex = currentLeftTd.parentNode.rowIndex + (currentLeftTd.rowSpan || 1);
  10853. }
  10854. }
  10855. // 检查是否有超出TableRange下边界的情况
  10856. if ( endRowIndex < rowsNum ) {
  10857. for ( var cellIndex = beginCellIndex; cellIndex <= endCellIndex; ) {
  10858. var currentDownTd = rows[endRowIndex].cells[cellIndex];
  10859. if ( _isHide( currentDownTd ) ) {
  10860. currentDownTd = rows[currentDownTd.getAttribute( 'rootRowIndex' )].cells[currentDownTd.getAttribute( 'rootCellIndex' )];
  10861. }
  10862. endRowIndex = currentDownTd.parentNode.rowIndex + currentDownTd.rowSpan - 1;
  10863. cellIndex = getIndex( currentDownTd ) + (currentDownTd.colSpan || 1);
  10864. }
  10865. }
  10866. //检查是否有超出右边界的情况
  10867. if ( endCellIndex < cellsNum ) {
  10868. for ( rowIndex = beginRowIndex; rowIndex <= endRowIndex; ) {
  10869. var currentRightTd = rows[rowIndex].cells[endCellIndex];
  10870. if ( _isHide( currentRightTd ) ) {
  10871. currentRightTd = rows[currentRightTd.getAttribute( 'rootRowIndex' )].cells[currentRightTd.getAttribute( 'rootCellIndex' )];
  10872. }
  10873. endCellIndex = getIndex( currentRightTd ) + currentRightTd.colSpan - 1;
  10874. rowIndex = currentRightTd.parentNode.rowIndex + (currentRightTd.rowSpan || 1);
  10875. }
  10876. }
  10877. if ( tmpBeginCellIndex == beginCellIndex && tmpEndCellIndex == endCellIndex && tmpEndRowIndex == endRowIndex && tmpBeginRowIndex == beginRowIndex ) {
  10878. break;
  10879. }
  10880. }
  10881. //返回选区的起始和结束坐标
  10882. return {
  10883. beginRowIndex:beginRowIndex,
  10884. beginCellIndex:beginCellIndex,
  10885. endRowIndex:endRowIndex,
  10886. endCellIndex:endCellIndex
  10887. }
  10888. }
  10889. /**
  10890. * 鼠标按下事件
  10891. * @param type
  10892. * @param evt
  10893. */
  10894. function _mouseDownEvent( type, evt ) {
  10895. anchorTd = evt.target || evt.srcElement;
  10896. if ( me.queryCommandState( 'highlightcode' ) || domUtils.findParent( anchorTd, function ( node ) {
  10897. return node.tagName == "DIV" && /highlighter/.test( node.id );
  10898. } ) ) {
  10899. return;
  10900. }
  10901. if ( evt.button == 2 )return;
  10902. me.document.body.style.webkitUserSelect = '';
  10903. clearSelectedTd( me.currentSelectedArr );
  10904. domUtils.clearSelectedArr( me.currentSelectedArr );
  10905. //在td里边点击,anchorTd不是td
  10906. if ( anchorTd.tagName !== 'TD' ) {
  10907. anchorTd = domUtils.findParentByTagName( anchorTd, 'td' ) || anchorTd;
  10908. }
  10909. if ( anchorTd.tagName == 'TD' ) {
  10910. me.addListener( 'mouseover', function ( type, evt ) {
  10911. var tmpTd = evt.target || evt.srcElement;
  10912. _mouseOverEvent.call( me, tmpTd );
  10913. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  10914. } );
  10915. } else {
  10916. reset();
  10917. }
  10918. }
  10919. /**
  10920. * 鼠标移动事件
  10921. * @param tmpTd
  10922. */
  10923. function _mouseOverEvent( tmpTd ) {
  10924. //需要判断两个TD是否位于同一个表格内
  10925. if ( anchorTd && tmpTd.tagName == "TD" && domUtils.findParentByTagName( anchorTd, 'table' ) == domUtils.findParentByTagName( tmpTd, 'table' ) ) {
  10926. me.document.body.style.webkitUserSelect = 'none';
  10927. var table = tmpTd.parentNode.parentNode.parentNode;
  10928. me.selection.getNative()[browser.ie ? 'empty' : 'removeAllRanges']();
  10929. var range = _getCellsRange( anchorTd, tmpTd );
  10930. _toggleSelect( table, range );
  10931. }
  10932. }
  10933. /**
  10934. * 切换选区状态
  10935. * @param table
  10936. * @param cellsRange
  10937. */
  10938. function _toggleSelect( table, cellsRange ) {
  10939. var rows = table.rows;
  10940. clearSelectedTd( me.currentSelectedArr );
  10941. for ( var i = cellsRange.beginRowIndex; i <= cellsRange.endRowIndex; i++ ) {
  10942. for ( var j = cellsRange.beginCellIndex; j <= cellsRange.endCellIndex; j++ ) {
  10943. var td = rows[i].cells[j];
  10944. td.className = "selectTdClass";
  10945. me.currentSelectedArr.push( td );
  10946. }
  10947. }
  10948. }
  10949. //更新rootRowIndxe,rootCellIndex
  10950. function update( table ) {
  10951. var tds = table.getElementsByTagName( 'td' ),
  10952. rowIndex, cellIndex, rows = table.rows;
  10953. for ( var j = 0, tj; tj = tds[j++]; ) {
  10954. if ( !_isHide( tj ) ) {
  10955. rowIndex = tj.parentNode.rowIndex;
  10956. cellIndex = getIndex( tj );
  10957. for ( var r = 0; r < tj.rowSpan; r++ ) {
  10958. var c = r == 0 ? 1 : 0;
  10959. for ( ; c < tj.colSpan; c++ ) {
  10960. var tmp = rows[rowIndex + r].children[cellIndex + c];
  10961. tmp.setAttribute( 'rootRowIndex', rowIndex );
  10962. tmp.setAttribute( 'rootCellIndex', cellIndex );
  10963. }
  10964. }
  10965. }
  10966. if ( !_isHide( tj ) ) {
  10967. domUtils.removeAttributes( tj, ['rootRowIndex', 'rootCellIndex'] );
  10968. }
  10969. if ( tj.colSpan && tj.colSpan == 1 ) {
  10970. tj.removeAttribute( 'colSpan' )
  10971. }
  10972. if ( tj.rowSpan && tj.rowSpan == 1 ) {
  10973. tj.removeAttribute( 'rowSpan' )
  10974. }
  10975. var width;
  10976. if ( !_isHide( tj ) && (width = tj.style.width) && /%/.test( width ) ) {
  10977. tj.style.width = Math.floor( 100 / tj.parentNode.cells.length ) + '%'
  10978. }
  10979. }
  10980. }
  10981. me.adjustTable = function ( cont ) {
  10982. var table = cont.getElementsByTagName( 'table' );
  10983. for ( var i = 0, ti; ti = table[i++]; ) {
  10984. //如果表格的align不是默认,将不占位,给后边的block元素设置clear:both
  10985. if ( ti.getAttribute( 'align' ) ) {
  10986. var next = ti.nextSibling;
  10987. while ( next ) {
  10988. if ( domUtils.isBlockElm( next ) ) {
  10989. break;
  10990. }
  10991. next = next.nextSibling;
  10992. }
  10993. if ( next ) {
  10994. next.style.clear = 'both';
  10995. }
  10996. }
  10997. ti.removeAttribute( '_innerCreateTable' );
  10998. var tds = domUtils.getElementsByTagName( ti, 'td' ),
  10999. td, tmpTd;
  11000. for ( var j = 0, tj; tj = tds[j++]; ) {
  11001. if ( domUtils.isEmptyNode( tj ) ) {
  11002. tj.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
  11003. }
  11004. var index = getIndex( tj ),
  11005. rowIndex = tj.parentNode.rowIndex,
  11006. rows = domUtils.findParentByTagName( tj, 'table' ).rows;
  11007. for ( var r = 0; r < tj.rowSpan; r++ ) {
  11008. var c = r == 0 ? 1 : 0;
  11009. for ( ; c < tj.colSpan; c++ ) {
  11010. if ( !td ) {
  11011. td = tj.cloneNode( false );
  11012. td.rowSpan = td.colSpan = 1;
  11013. td.style.display = 'none';
  11014. td.innerHTML = browser.ie ? '' : '<br/>';
  11015. } else {
  11016. td = td.cloneNode( true )
  11017. }
  11018. td.setAttribute( 'rootRowIndex', tj.parentNode.rowIndex );
  11019. td.setAttribute( 'rootCellIndex', index );
  11020. if ( r == 0 ) {
  11021. if ( tj.nextSibling ) {
  11022. tj.parentNode.insertBefore( td, tj.nextSibling );
  11023. } else {
  11024. tj.parentNode.appendChild( td )
  11025. }
  11026. } else {
  11027. tmpTd = rows[rowIndex + r].children[index];
  11028. if ( tmpTd ) {
  11029. tmpTd.parentNode.insertBefore( td, tmpTd )
  11030. } else {
  11031. //trace:1032
  11032. rows[rowIndex + r].appendChild( td )
  11033. }
  11034. }
  11035. }
  11036. }
  11037. }
  11038. var bw = domUtils.getComputedStyle( ti, "border-width" );
  11039. if ( bw == '0px' && ti.style.border!="none" || ((bw == ""||bw =="medium") && ti.getAttribute( "border" ) === "0")) { //trace 2377 ie7下获取宽度值为medium
  11040. domUtils.addClass(ti,"noBorderTable");
  11041. }
  11042. }
  11043. me.fireEvent( "afteradjusttable", cont );
  11044. };
  11045. // me.addListener( 'beforegetcontent', function () {
  11046. // for ( var i = 0, ti, ts = me.document.getElementsByTagName( 'table' ); ti = ts[i++]; ) {
  11047. // var pN = ti.parentNode;
  11048. // if ( pN && pN.getAttribute( 'dropdrag' ) ) {
  11049. // domUtils.remove( pN, true )
  11050. // }
  11051. // }
  11052. // } );
  11053. //
  11054. // me.addListener( 'aftergetcontent', function () {
  11055. // if ( !me.queryCommandState( 'source' ) )
  11056. // me.fireEvent( 'afteradjusttable', me.document )
  11057. // } );
  11058. // //table拖拽
  11059. // me.addListener( "afteradjusttable", function ( type, cont ) {
  11060. // var table = cont.getElementsByTagName( "table" ),
  11061. // dragCont = domUtils.creElm( me.document, 'div', {
  11062. // style:'margin:0;padding:5px;border:0;',
  11063. // dropdrag:true
  11064. // } );
  11065. //
  11066. // for ( var i = 0, ti; ti = table[i++]; ) {
  11067. // var parentNode = ti.parentNode;
  11068. // if ( parentNode && parentNode.nodeType == 1 ) {
  11069. // //插入代码
  11070. // if ( /syntaxhighlighter/.test( parentNode.className ) ) continue;
  11071. // (function ( ti ) {
  11072. // var div = dragCont.cloneNode( false );
  11073. // ti.parentNode.insertBefore( div, ti );
  11074. // div.appendChild( ti );
  11075. // var borderStyle;
  11076. // domUtils.on( div, 'mousemove', function ( evt ) {
  11077. // var tag = evt.srcElement || evt.target;
  11078. // if ( tag.tagName.toLowerCase() == "div" ) {
  11079. // if ( ie && me.body.getAttribute( "contentEditable" ) == 'true' )
  11080. // me.body.setAttribute( "contentEditable", "false" );
  11081. // borderStyle = clickPosition( ti, this, evt )
  11082. //
  11083. // }
  11084. // } );
  11085. // if ( ie ) {
  11086. // domUtils.on( div, 'mouseleave', function ( evt ) {
  11087. //
  11088. // if ( domUtils.isTagNode( evt.srcElement, "div" ) && me.body.getAttribute( "contentEditable" ) == 'false' ) {
  11089. //
  11090. // me.body.setAttribute( "contentEditable", "true" );
  11091. // }
  11092. //
  11093. //
  11094. // } );
  11095. // }
  11096. //
  11097. // domUtils.on( div, "mousedown", function ( evt ) {
  11098. //
  11099. // if ( domUtils.isTagNode( evt.srcElement || evt.target, 'div' ) ) {
  11100. // if ( ie && me.body.getAttribute( "contentEditable" ) == 'true' )
  11101. // me.body.setAttribute( "contentEditable", "false" );
  11102. // var tWidth = ti.offsetWidth,
  11103. // tHeight = ti.offsetHeight,
  11104. // align = ti.getAttribute( 'align' );
  11105. // try {
  11106. // baidu.editor.ui.uiUtils.startDrag( evt, {
  11107. // ondragstart:function () {
  11108. // },
  11109. // ondragmove:function ( x, y ) {
  11110. //
  11111. // if ( align && align != "left" && /\w?w-/.test( borderStyle ) ) {
  11112. // x = -x;
  11113. // }
  11114. // if ( /^s?[we]/.test( borderStyle ) ) {
  11115. // ti.setAttribute( "width", (tWidth + x) > 0 ? tWidth + x : 0 );
  11116. // }
  11117. // if ( /^s/.test( borderStyle ) ) {
  11118. // ti.setAttribute( "height", (tHeight + y) > 0 ? tHeight + y : 0 );
  11119. // }
  11120. // },
  11121. // ondragstop:function () {
  11122. // }
  11123. // }, me.document );
  11124. // } catch ( e ) {
  11125. // alert( me.getLang("tableDrag"));
  11126. // }
  11127. //
  11128. // }
  11129. // } );
  11130. //
  11131. // domUtils.on( ti, "mouseover", function () {
  11132. // var div = ti.parentNode;
  11133. // if ( div && div.parentNode && div.getAttribute( 'dropdrag' ) ) {
  11134. // domUtils.setStyle( div, "cursor", "text" );
  11135. // if ( ie && me.body.getAttribute( "contentEditable" ) == 'false' )
  11136. // me.body.setAttribute( "contentEditable", "true" );
  11137. // }
  11138. //
  11139. //
  11140. // } );
  11141. // })( ti );
  11142. //
  11143. // }
  11144. // }
  11145. // } );
  11146. // function clickPosition( table, div, evt ) {
  11147. // var pos = domUtils.getXY( table ),
  11148. // tWidth = table.offsetWidth,
  11149. // tHeight = table.offsetHeight,
  11150. // evtPos = {
  11151. // top:evt.clientY,
  11152. // left:evt.clientX
  11153. // },
  11154. // borderStyle = "";
  11155. //
  11156. // if ( Math.abs( evtPos.left - pos.x - tWidth ) < 15 ) {
  11157. // //右,右下
  11158. // borderStyle = Math.abs( evtPos.top - pos.y - tHeight ) < 15 ? "se-resize" : "e-resize";
  11159. // } else if ( Math.abs( evtPos.top - pos.y - tHeight ) < 15 && Math.abs( evtPos.left - pos.x ) < tWidth ) {
  11160. // //下
  11161. // borderStyle = "s-resize";
  11162. // }
  11163. // domUtils.setStyle( div, "cursor", borderStyle || 'text' );
  11164. // return borderStyle;
  11165. // }
  11166. };
  11167. ///import core
  11168. ///commands 右键菜单
  11169. ///commandsName ContextMenu
  11170. ///commandsTitle 右键菜单
  11171. /**
  11172. * 右键菜单
  11173. * @function
  11174. * @name baidu.editor.plugins.contextmenu
  11175. * @author zhanyi
  11176. */
  11177. UE.plugins['contextmenu'] = function () {
  11178. var me = this,
  11179. lang = me.getLang( "contextMenu" ),
  11180. menu,
  11181. items = me.options.contextMenu || [
  11182. {label:lang['delete'], cmdName:'delete'},
  11183. {label:lang['selectall'], cmdName:'selectall'},
  11184. {
  11185. label:lang.deletecode,
  11186. cmdName:'highlightcode',
  11187. icon:'deletehighlightcode'
  11188. },
  11189. {
  11190. label:lang.cleardoc,
  11191. cmdName:'cleardoc',
  11192. exec:function () {
  11193. if ( confirm( lang.confirmclear ) ) {
  11194. this.execCommand( 'cleardoc' );
  11195. }
  11196. }
  11197. },
  11198. '-',
  11199. {
  11200. label:lang.unlink,
  11201. cmdName:'unlink'
  11202. },
  11203. '-',
  11204. {
  11205. group:lang.paragraph,
  11206. icon:'justifyjustify',
  11207. subMenu:[
  11208. {
  11209. label:me.getLang( "justifyleft" ),
  11210. cmdName:'justify',
  11211. value:'left'
  11212. },
  11213. {
  11214. label:me.getLang( "justifyright" ),
  11215. cmdName:'justify',
  11216. value:'right'
  11217. },
  11218. {
  11219. label:me.getLang( "justifyrenter" ),
  11220. cmdName:'justify',
  11221. value:'center'
  11222. },
  11223. {
  11224. label:me.getLang( "justify" ),
  11225. cmdName:'justify',
  11226. value:'justify'
  11227. }
  11228. ]
  11229. },
  11230. '-',
  11231. {
  11232. label:lang.edittable,
  11233. cmdName:'edittable',
  11234. exec:function () {
  11235. this.ui._dialogs['inserttableDialog'].open();
  11236. }
  11237. },
  11238. {
  11239. label:lang.edittd,
  11240. cmdName:'edittd',
  11241. exec:function () {
  11242. //如果没有创建,创建一下先
  11243. if ( UE.ui['edittd'] ) {
  11244. new UE.ui['edittd']( this );
  11245. }
  11246. this.ui._dialogs['edittdDialog'].open();
  11247. }
  11248. },
  11249. {
  11250. group:lang.table,
  11251. icon:'table',
  11252. subMenu:[
  11253. {
  11254. label:lang.deletetable,
  11255. cmdName:'deletetable'
  11256. },
  11257. {
  11258. label:lang.insertparagraphbeforetable,
  11259. cmdName:'insertparagraphbeforetable'
  11260. },
  11261. '-',
  11262. {
  11263. label:lang.deleterow,
  11264. cmdName:'deleterow'
  11265. },
  11266. {
  11267. label:lang.deletecol,
  11268. cmdName:'deletecol'
  11269. },
  11270. '-',
  11271. {
  11272. label:lang.insertrow,
  11273. cmdName:'insertrow'
  11274. },
  11275. {
  11276. label:lang.insertcol,
  11277. cmdName:'insertcol'
  11278. },
  11279. '-',
  11280. {
  11281. label:lang.mergeright,
  11282. cmdName:'mergeright'
  11283. },
  11284. {
  11285. label:lang.mergedown,
  11286. cmdName:'mergedown'
  11287. },
  11288. '-',
  11289. {
  11290. label:lang.splittorows,
  11291. cmdName:'splittorows'
  11292. },
  11293. {
  11294. label:lang.splittocols,
  11295. cmdName:'splittocols'
  11296. },
  11297. {
  11298. label:lang.mergecells,
  11299. cmdName:'mergecells'
  11300. },
  11301. {
  11302. label:lang.splittocells,
  11303. cmdName:'splittocells'
  11304. }
  11305. ]
  11306. },
  11307. {
  11308. label:lang['copy'],
  11309. cmdName:'copy',
  11310. exec:function () {
  11311. alert( lang.copymsg );
  11312. },
  11313. query:function () {
  11314. return 0;
  11315. }
  11316. },
  11317. {
  11318. label:lang['paste'],
  11319. cmdName:'paste',
  11320. exec:function () {
  11321. alert( lang.pastemsg );
  11322. },
  11323. query:function () {
  11324. return 0;
  11325. }
  11326. }
  11327. ];
  11328. if ( !items.length ) {
  11329. return;
  11330. }
  11331. var uiUtils = UE.ui.uiUtils;
  11332. me.addListener( 'contextmenu', function ( type, evt ) {
  11333. var offset = uiUtils.getViewportOffsetByEvent( evt );
  11334. me.fireEvent( 'beforeselectionchange' );
  11335. if ( menu ) {
  11336. menu.destroy();
  11337. }
  11338. for ( var i = 0, ti, contextItems = []; ti = items[i]; i++ ) {
  11339. var last;
  11340. (function ( item ) {
  11341. if ( item == '-' ) {
  11342. if ( (last = contextItems[contextItems.length - 1 ] ) && last !== '-' ) {
  11343. contextItems.push( '-' );
  11344. }
  11345. } else if ( item.hasOwnProperty( "group" ) ) {
  11346. for ( var j = 0, cj, subMenu = []; cj = item.subMenu[j]; j++ ) {
  11347. (function ( subItem ) {
  11348. if ( subItem == '-' ) {
  11349. if ( (last = subMenu[subMenu.length - 1 ] ) && last !== '-' ) {
  11350. subMenu.push( '-' );
  11351. }
  11352. } else {
  11353. if ( (me.commands[subItem.cmdName] || UE.commands[subItem.cmdName] || subItem.query) &&
  11354. (subItem.query ? subItem.query() : me.queryCommandState( subItem.cmdName )) > -1 ) {
  11355. subMenu.push( {
  11356. 'label':subItem.label || me.getLang( "contextMenu." + subItem.cmdName + (subItem.value || '') ),
  11357. 'className':'edui-for-' + subItem.cmdName + (subItem.value || ''),
  11358. onclick:subItem.exec ? function () {
  11359. subItem.exec.call( me );
  11360. } : function () {
  11361. me.execCommand( subItem.cmdName, subItem.value );
  11362. }
  11363. } );
  11364. }
  11365. }
  11366. })( cj );
  11367. }
  11368. if ( subMenu.length ) {
  11369. contextItems.push( {
  11370. //todo 修正成自动获取方式
  11371. 'label':item.icon == "table" ? me.getLang( "contextMenu.table" ) : me.getLang( "contextMenu.paragraph" ),
  11372. className:'edui-for-' + item.icon,
  11373. 'subMenu':{
  11374. items:subMenu,
  11375. editor:me
  11376. }
  11377. } );
  11378. }
  11379. } else {
  11380. //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
  11381. if ( (me.commands[item.cmdName] || UE.commands[item.cmdName] || item.query) &&
  11382. (item.query ? item.query() : me.queryCommandState( item.cmdName )) > -1 ) {
  11383. //highlight todo
  11384. if ( item.cmdName == 'highlightcode' && me.queryCommandState( item.cmdName ) == 0 ) {
  11385. return;
  11386. }
  11387. contextItems.push( {
  11388. 'label':item.label || me.getLang( "contextMenu." + item.cmdName ),
  11389. className:'edui-for-' + (item.icon ? item.icon : item.cmdName + (item.value || '')),
  11390. onclick:item.exec ? function () {
  11391. item.exec.call( me );
  11392. } : function () {
  11393. me.execCommand( item.cmdName, item.value );
  11394. }
  11395. } );
  11396. }
  11397. }
  11398. })( ti );
  11399. }
  11400. if ( contextItems[contextItems.length - 1] == '-' ) {
  11401. contextItems.pop();
  11402. }
  11403. menu = new UE.ui.Menu( {
  11404. items:contextItems,
  11405. editor:me
  11406. } );
  11407. menu.render();
  11408. menu.showAt( offset );
  11409. domUtils.preventDefault( evt );
  11410. if ( browser.ie ) {
  11411. var ieRange;
  11412. try {
  11413. ieRange = me.selection.getNative().createRange();
  11414. } catch ( e ) {
  11415. return;
  11416. }
  11417. if ( ieRange.item ) {
  11418. var range = new dom.Range( me.document );
  11419. range.selectNode( ieRange.item( 0 ) ).select( true, true );
  11420. }
  11421. }
  11422. } );
  11423. };
  11424. ///import core
  11425. ///commands 加粗,斜体,上标,下标
  11426. ///commandsName Bold,Italic,Subscript,Superscript
  11427. ///commandsTitle 加粗,加斜,下标,上标
  11428. /**
  11429. * b u i等基础功能实现
  11430. * @function
  11431. * @name baidu.editor.execCommands
  11432. * @param {String} cmdName bold加粗。italic斜体。subscript上标。superscript下标。
  11433. */
  11434. UE.plugins['basestyle'] = function(){
  11435. var basestyles = {
  11436. 'bold':['strong','b'],
  11437. 'italic':['em','i'],
  11438. 'subscript':['sub'],
  11439. 'superscript':['sup']
  11440. },
  11441. getObj = function(editor,tagNames){
  11442. //var start = editor.selection.getStart();
  11443. var path = editor.selection.getStartElementPath();
  11444. // return domUtils.findParentByTagName( start, tagNames, true )
  11445. return utils.findNode(path,tagNames);
  11446. },
  11447. me = this;
  11448. for ( var style in basestyles ) {
  11449. (function( cmd, tagNames ) {
  11450. me.commands[cmd] = {
  11451. execCommand : function( cmdName ) {
  11452. var range = new dom.Range(me.document),obj = '';
  11453. //table的处理
  11454. if(me.currentSelectedArr && me.currentSelectedArr.length > 0){
  11455. for(var i=0,ci;ci=me.currentSelectedArr[i++];){
  11456. if(ci.style.display != 'none'){
  11457. range.selectNodeContents(ci).select();
  11458. //trace:943
  11459. !obj && (obj = getObj(this,tagNames));
  11460. if(cmdName == 'superscript' || cmdName == 'subscript'){
  11461. if(!obj || obj.tagName.toLowerCase() != cmdName){
  11462. range.removeInlineStyle(['sub','sup']);
  11463. }
  11464. }
  11465. obj ? range.removeInlineStyle( tagNames ) : range.applyInlineStyle( tagNames[0] );
  11466. }
  11467. }
  11468. range.selectNodeContents(me.currentSelectedArr[0]).select();
  11469. }else{
  11470. range = me.selection.getRange();
  11471. obj = getObj(this,tagNames);
  11472. if ( range.collapsed ) {
  11473. if ( obj ) {
  11474. var tmpText = me.document.createTextNode('');
  11475. range.insertNode( tmpText ).removeInlineStyle( tagNames );
  11476. range.setStartBefore(tmpText);
  11477. domUtils.remove(tmpText);
  11478. } else {
  11479. var tmpNode = range.document.createElement( tagNames[0] );
  11480. if(cmdName == 'superscript' || cmdName == 'subscript'){
  11481. tmpText = me.document.createTextNode('');
  11482. range.insertNode(tmpText)
  11483. .removeInlineStyle(['sub','sup'])
  11484. .setStartBefore(tmpText)
  11485. .collapse(true);
  11486. }
  11487. range.insertNode( tmpNode ).setStart( tmpNode, 0 );
  11488. }
  11489. range.collapse( true );
  11490. } else {
  11491. if(cmdName == 'superscript' || cmdName == 'subscript'){
  11492. if(!obj || obj.tagName.toLowerCase() != cmdName){
  11493. range.removeInlineStyle(['sub','sup']);
  11494. }
  11495. }
  11496. obj ? range.removeInlineStyle( tagNames ) : range.applyInlineStyle( tagNames[0] );
  11497. }
  11498. range.select();
  11499. }
  11500. return true;
  11501. },
  11502. queryCommandState : function() {
  11503. if(this.highlight){
  11504. return -1;
  11505. }
  11506. return getObj(this,tagNames) ? 1 : 0;
  11507. }
  11508. };
  11509. })( style, basestyles[style] );
  11510. }
  11511. };
  11512. ///import core
  11513. ///commands 选区路径
  11514. ///commandsName ElementPath,elementPathEnabled
  11515. ///commandsTitle 选区路径
  11516. /**
  11517. * 选区路径
  11518. * @function
  11519. * @name baidu.editor.execCommand
  11520. * @param {String} cmdName elementpath选区路径
  11521. */
  11522. UE.plugins['elementpath'] = function(){
  11523. var currentLevel,
  11524. tagNames,
  11525. me = this;
  11526. me.setOpt('elementPathEnabled',true);
  11527. if(!me.options.elementPathEnabled){
  11528. return;
  11529. }
  11530. me.commands['elementpath'] = {
  11531. execCommand : function( cmdName, level ) {
  11532. var start = tagNames[level],
  11533. range = me.selection.getRange();
  11534. me.currentSelectedArr && domUtils.clearSelectedArr(me.currentSelectedArr);
  11535. currentLevel = level*1;
  11536. if(dtd.$tableContent[start.tagName]){
  11537. switch (start.tagName){
  11538. case 'TD':me.currentSelectedArr = [start];
  11539. start.className = me.options.selectedTdClass;
  11540. break;
  11541. case 'TR':
  11542. var cells = start.cells;
  11543. for(var i=0,ti;ti=cells[i++];){
  11544. me.currentSelectedArr.push(ti);
  11545. ti.className = me.options.selectedTdClass;
  11546. }
  11547. break;
  11548. case 'TABLE':
  11549. case 'TBODY':
  11550. var rows = start.rows;
  11551. for(var i=0,ri;ri=rows[i++];){
  11552. cells = ri.cells;
  11553. for(var j=0,tj;tj=cells[j++];){
  11554. me.currentSelectedArr.push(tj);
  11555. tj.className = me.options.selectedTdClass;
  11556. }
  11557. }
  11558. }
  11559. start = me.currentSelectedArr[0];
  11560. if(domUtils.isEmptyNode(start)){
  11561. range.setStart(start,0).setCursor();
  11562. }else{
  11563. range.selectNodeContents(start).select();
  11564. }
  11565. }else{
  11566. range.selectNode(start).select();
  11567. }
  11568. },
  11569. queryCommandValue : function() {
  11570. //产生一个副本,不能修改原来的startElementPath;
  11571. var parents = [].concat(this.selection.getStartElementPath()).reverse(),
  11572. names = [];
  11573. tagNames = parents;
  11574. for(var i=0,ci;ci=parents[i];i++){
  11575. if(ci.nodeType == 3) {
  11576. continue;
  11577. }
  11578. var name = ci.tagName.toLowerCase();
  11579. if(name == 'img' && ci.getAttribute('anchorname')){
  11580. name = 'anchor';
  11581. }
  11582. names[i] = name;
  11583. if(currentLevel == i){
  11584. currentLevel = -1;
  11585. break;
  11586. }
  11587. }
  11588. return names;
  11589. }
  11590. };
  11591. };
  11592. ///import core
  11593. ///import plugins\removeformat.js
  11594. ///commands 格式刷
  11595. ///commandsName FormatMatch
  11596. ///commandsTitle 格式刷
  11597. /**
  11598. * 格式刷,只格式inline的
  11599. * @function
  11600. * @name baidu.editor.execCommand
  11601. * @param {String} cmdName formatmatch执行格式刷
  11602. */
  11603. UE.plugins['formatmatch'] = function(){
  11604. var me = this,
  11605. list = [],img,
  11606. flag = 0;
  11607. me.addListener('reset',function(){
  11608. list = [];
  11609. flag = 0;
  11610. });
  11611. function addList(type,evt){
  11612. if(browser.webkit){
  11613. var target = evt.target.tagName == 'IMG' ? evt.target : null;
  11614. }
  11615. function addFormat(range){
  11616. if(text && (!me.currentSelectedArr || !me.currentSelectedArr.length)){
  11617. range.selectNode(text);
  11618. }
  11619. return range.applyInlineStyle(list[list.length-1].tagName,null,list);
  11620. }
  11621. me.undoManger && me.undoManger.save();
  11622. var range = me.selection.getRange(),
  11623. imgT = target || range.getClosedNode();
  11624. if(img && imgT && imgT.tagName == 'IMG'){
  11625. //trace:964
  11626. imgT.style.cssText += ';float:' + (img.style.cssFloat || img.style.styleFloat ||'none') + ';display:' + (img.style.display||'inline');
  11627. img = null;
  11628. }else{
  11629. if(!img){
  11630. var collapsed = range.collapsed;
  11631. if(collapsed){
  11632. var text = me.document.createTextNode('match');
  11633. range.insertNode(text).select();
  11634. }
  11635. me.__hasEnterExecCommand = true;
  11636. //不能把block上的属性干掉
  11637. //trace:1553
  11638. var removeFormatAttributes = me.options.removeFormatAttributes;
  11639. me.options.removeFormatAttributes = '';
  11640. me.execCommand('removeformat');
  11641. me.options.removeFormatAttributes = removeFormatAttributes;
  11642. me.__hasEnterExecCommand = false;
  11643. //trace:969
  11644. range = me.selection.getRange();
  11645. if(list.length == 0){
  11646. if(me.currentSelectedArr && me.currentSelectedArr.length > 0){
  11647. range.selectNodeContents(me.currentSelectedArr[0]).select();
  11648. }
  11649. }else{
  11650. if(me.currentSelectedArr && me.currentSelectedArr.length > 0){
  11651. for(var i=0,ci;ci=me.currentSelectedArr[i++];){
  11652. range.selectNodeContents(ci);
  11653. addFormat(range);
  11654. }
  11655. range.selectNodeContents(me.currentSelectedArr[0]).select();
  11656. }else{
  11657. addFormat(range);
  11658. }
  11659. }
  11660. if(!me.currentSelectedArr || !me.currentSelectedArr.length){
  11661. if(text){
  11662. range.setStartBefore(text).collapse(true);
  11663. }
  11664. range.select();
  11665. }
  11666. text && domUtils.remove(text);
  11667. }
  11668. }
  11669. me.undoManger && me.undoManger.save();
  11670. me.removeListener('mouseup',addList);
  11671. flag = 0;
  11672. }
  11673. me.commands['formatmatch'] = {
  11674. execCommand : function( cmdName ) {
  11675. if(flag){
  11676. flag = 0;
  11677. list = [];
  11678. me.removeListener('mouseup',addList);
  11679. return;
  11680. }
  11681. var range = me.selection.getRange();
  11682. img = range.getClosedNode();
  11683. if(!img || img.tagName != 'IMG'){
  11684. range.collapse(true).shrinkBoundary();
  11685. var start = range.startContainer;
  11686. list = domUtils.findParents(start,true,function(node){
  11687. return !domUtils.isBlockElm(node) && node.nodeType == 1;
  11688. });
  11689. //a不能加入格式刷, 并且克隆节点
  11690. for(var i=0,ci;ci=list[i];i++){
  11691. if(ci.tagName == 'A'){
  11692. list.splice(i,1);
  11693. break;
  11694. }
  11695. }
  11696. }
  11697. me.addListener('mouseup',addList);
  11698. flag = 1;
  11699. },
  11700. queryCommandState : function() {
  11701. if(this.highlight){
  11702. return -1;
  11703. }
  11704. return flag;
  11705. },
  11706. notNeedUndo : 1
  11707. };
  11708. };
  11709. ///import core
  11710. ///commands 查找替换
  11711. ///commandsName SearchReplace
  11712. ///commandsTitle 查询替换
  11713. ///commandsDialog dialogs\searchreplace\searchreplace.html
  11714. /**
  11715. * @description 查找替换
  11716. * @author zhanyi
  11717. */
  11718. UE.plugins['searchreplace'] = function(){
  11719. var currentRange,
  11720. first,
  11721. me = this;
  11722. me.addListener('reset',function(){
  11723. currentRange = null;
  11724. first = null;
  11725. });
  11726. me.commands['searchreplace'] = {
  11727. execCommand : function(cmdName,opt){
  11728. var me = this,
  11729. sel = me.selection,
  11730. range,
  11731. nativeRange,
  11732. num = 0,
  11733. opt = utils.extend(opt,{
  11734. all : false,
  11735. casesensitive : false,
  11736. dir : 1
  11737. },true);
  11738. if(browser.ie){
  11739. while(1){
  11740. var tmpRange;
  11741. nativeRange = me.document.selection.createRange();
  11742. tmpRange = nativeRange.duplicate();
  11743. tmpRange.moveToElementText(me.document.body);
  11744. if(opt.all){
  11745. first = 0;
  11746. opt.dir = 1;
  11747. if(currentRange){
  11748. tmpRange.setEndPoint(opt.dir == -1 ? 'EndToStart' : 'StartToEnd',currentRange);
  11749. }
  11750. }else{
  11751. tmpRange.setEndPoint(opt.dir == -1 ? 'EndToStart' : 'StartToEnd',nativeRange);
  11752. if(opt.hasOwnProperty("replaceStr")){
  11753. tmpRange.setEndPoint(opt.dir == -1 ? 'StartToEnd' : 'EndToStart',nativeRange);
  11754. }
  11755. }
  11756. nativeRange = tmpRange.duplicate();
  11757. if(!tmpRange.findText(opt.searchStr,opt.dir,opt.casesensitive ? 4 : 0)){
  11758. currentRange = null;
  11759. tmpRange = me.document.selection.createRange();
  11760. tmpRange.scrollIntoView();
  11761. return num;
  11762. }
  11763. tmpRange.select();
  11764. //替换
  11765. if(opt.hasOwnProperty("replaceStr")){
  11766. range = sel.getRange();
  11767. range.deleteContents().insertNode(range.document.createTextNode(opt.replaceStr)).select();
  11768. currentRange = sel.getNative().createRange();
  11769. }
  11770. num++;
  11771. if(!opt.all){
  11772. break;
  11773. }
  11774. }
  11775. }else{
  11776. var w = me.window,nativeSel = sel.getNative(),tmpRange;
  11777. while(1){
  11778. if(opt.all){
  11779. if(currentRange){
  11780. currentRange.collapse(false);
  11781. nativeRange = currentRange;
  11782. }else{
  11783. nativeRange = me.document.createRange();
  11784. nativeRange.setStart(me.document.body,0);
  11785. }
  11786. nativeSel.removeAllRanges();
  11787. nativeSel.addRange( nativeRange );
  11788. first = 0;
  11789. opt.dir = 1;
  11790. }else{
  11791. nativeRange = w.getSelection().getRangeAt(0);
  11792. if(opt.hasOwnProperty("replaceStr")){
  11793. nativeRange.collapse(opt.dir == 1 ? true : false);
  11794. }
  11795. }
  11796. //如果是第一次并且海选中了内容那就要清除,为find做准备
  11797. if(!first){
  11798. nativeRange.collapse( opt.dir <0 ? true : false);
  11799. nativeSel.removeAllRanges();
  11800. nativeSel.addRange( nativeRange );
  11801. }else{
  11802. nativeSel.removeAllRanges();
  11803. }
  11804. if(!w.find(opt.searchStr,opt.casesensitive,opt.dir < 0 ? true : false) ) {
  11805. currentRange = null;
  11806. nativeSel.removeAllRanges();
  11807. return num;
  11808. }
  11809. first = 0;
  11810. range = w.getSelection().getRangeAt(0);
  11811. if(!range.collapsed){
  11812. if(opt.hasOwnProperty("replaceStr")){
  11813. range.deleteContents();
  11814. var text = w.document.createTextNode(opt.replaceStr);
  11815. range.insertNode(text);
  11816. range.selectNode(text);
  11817. nativeSel.addRange(range);
  11818. currentRange = range.cloneRange();
  11819. }
  11820. }
  11821. num++;
  11822. if(!opt.all){
  11823. break;
  11824. }
  11825. }
  11826. }
  11827. return true;
  11828. }
  11829. };
  11830. };
  11831. ///import core
  11832. ///commands 自定义样式
  11833. ///commandsName CustomStyle
  11834. ///commandsTitle 自定义样式
  11835. UE.plugins['customstyle'] = function() {
  11836. var me = this;
  11837. me.setOpt({ 'customstyle':[
  11838. {tag:'h1',name:'tc', style:'font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;'},
  11839. {tag:'h1',name:'tl', style:'font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;margin:0 0 10px 0;'},
  11840. {tag:'span',name:'im', style:'font-size:16px;font-style:italic;font-weight:bold;color:#000;line-height:18px;'},
  11841. {tag:'span',name:'hi', style:'font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;'}
  11842. ]});
  11843. me.commands['customstyle'] = {
  11844. execCommand : function(cmdName, obj) {
  11845. var me = this,
  11846. tagName = obj.tag,
  11847. node = domUtils.findParent(me.selection.getStart(), function(node) {
  11848. return node.getAttribute('label');
  11849. }, true),
  11850. range,bk,tmpObj = {};
  11851. for (var p in obj) {
  11852. tmpObj[p] = obj[p];
  11853. }
  11854. delete tmpObj.tag;
  11855. if (node && node.getAttribute('label') == obj.label) {
  11856. range = this.selection.getRange();
  11857. bk = range.createBookmark();
  11858. if (range.collapsed) {
  11859. //trace:1732 删掉自定义标签,要有p来回填站位
  11860. if(dtd.$block[node.tagName]){
  11861. var fillNode = me.document.createElement('p');
  11862. domUtils.moveChild(node, fillNode);
  11863. node.parentNode.insertBefore(fillNode, node);
  11864. domUtils.remove(node);
  11865. }else{
  11866. domUtils.remove(node,true);
  11867. }
  11868. } else {
  11869. var common = domUtils.getCommonAncestor(bk.start, bk.end),
  11870. nodes = domUtils.getElementsByTagName(common, tagName);
  11871. if(new RegExp(tagName,'i').test(common.tagName)){
  11872. nodes.push(common);
  11873. }
  11874. for (var i = 0,ni; ni = nodes[i++];) {
  11875. if (ni.getAttribute('label') == obj.label) {
  11876. var ps = domUtils.getPosition(ni, bk.start),pe = domUtils.getPosition(ni, bk.end);
  11877. if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS)
  11878. &&
  11879. (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
  11880. )
  11881. if (dtd.$block[tagName]) {
  11882. var fillNode = me.document.createElement('p');
  11883. domUtils.moveChild(ni, fillNode);
  11884. ni.parentNode.insertBefore(fillNode, ni);
  11885. }
  11886. domUtils.remove(ni, true);
  11887. }
  11888. }
  11889. node = domUtils.findParent(common, function(node) {
  11890. return node.getAttribute('label') == obj.label;
  11891. }, true);
  11892. if (node) {
  11893. domUtils.remove(node, true);
  11894. }
  11895. }
  11896. range.moveToBookmark(bk).select();
  11897. } else {
  11898. if (dtd.$block[tagName]) {
  11899. this.execCommand('paragraph', tagName, tmpObj,'customstyle');
  11900. range = me.selection.getRange();
  11901. if (!range.collapsed) {
  11902. range.collapse();
  11903. node = domUtils.findParent(me.selection.getStart(), function(node) {
  11904. return node.getAttribute('label') == obj.label;
  11905. }, true);
  11906. var pNode = me.document.createElement('p');
  11907. domUtils.insertAfter(node, pNode);
  11908. domUtils.fillNode(me.document, pNode);
  11909. range.setStart(pNode, 0).setCursor();
  11910. }
  11911. } else {
  11912. range = me.selection.getRange();
  11913. if (range.collapsed) {
  11914. node = me.document.createElement(tagName);
  11915. domUtils.setAttributes(node, tmpObj);
  11916. range.insertNode(node).setStart(node, 0).setCursor();
  11917. return;
  11918. }
  11919. bk = range.createBookmark();
  11920. range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select();
  11921. }
  11922. }
  11923. },
  11924. queryCommandValue : function() {
  11925. var parent = utils.findNode(this.selection.getStartElementPath(),null,function(node){return node.getAttribute('label')});
  11926. return parent ? parent.getAttribute('label') : '';
  11927. },
  11928. queryCommandState : function() {
  11929. return this.highlight ? -1 : 0;
  11930. }
  11931. };
  11932. //当去掉customstyle是,如果是块元素,用p代替
  11933. me.addListener('keyup', function(type, evt) {
  11934. var keyCode = evt.keyCode || evt.which;
  11935. if (keyCode == 32 || keyCode == 13) {
  11936. var range = me.selection.getRange();
  11937. if (range.collapsed) {
  11938. var node = domUtils.findParent(me.selection.getStart(), function(node) {
  11939. return node.getAttribute('label');
  11940. }, true);
  11941. if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
  11942. var p = me.document.createElement('p');
  11943. domUtils.insertAfter(node, p);
  11944. domUtils.fillNode(me.document, p);
  11945. domUtils.remove(node);
  11946. range.setStart(p, 0).setCursor();
  11947. }
  11948. }
  11949. }
  11950. });
  11951. };
  11952. ///import core
  11953. ///commandsName catchRemoteImage
  11954. /**
  11955. * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
  11956. *
  11957. */
  11958. UE.plugins['catchremoteimage'] = function () {
  11959. if (this.options.catchRemoteImageEnable===false){
  11960. return;
  11961. }
  11962. var me = this;
  11963. this.setOpt({
  11964. localDomain:["127.0.0.1","localhost","img.baidu.com"],
  11965. separater:'ue_separate_ue',
  11966. catchFieldName:"upfile",
  11967. catchRemoteImageEnable:true
  11968. });
  11969. var ajax = UE.ajax,
  11970. localDomain = me.options.localDomain ,
  11971. catcherUrl = me.options.catcherUrl,
  11972. separater = me.options.separater;
  11973. function catchremoteimage(imgs, callbacks) {
  11974. var submitStr = imgs.join(separater);
  11975. var tmpOption = {
  11976. timeout:60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
  11977. onsuccess:callbacks["success"],
  11978. onerror:callbacks["error"]
  11979. };
  11980. tmpOption[me.options.catchFieldName] = submitStr;
  11981. ajax.request(catcherUrl, tmpOption);
  11982. }
  11983. me.addListener("afterpaste", function () {
  11984. me.fireEvent("catchRemoteImage");
  11985. });
  11986. me.addListener("catchRemoteImage", function () {
  11987. var remoteImages = [];
  11988. var imgs = domUtils.getElementsByTagName(me.document, "img");
  11989. var test = function (src,urls) {
  11990. for (var j = 0, url; url = urls[j++];) {
  11991. if (src.indexOf(url) !== -1) {
  11992. return true;
  11993. }
  11994. }
  11995. return false;
  11996. };
  11997. for (var i = 0, ci; ci = imgs[i++];) {
  11998. if (ci.getAttribute("word_img")){
  11999. continue;
  12000. }
  12001. var src = ci.getAttribute("data_ue_src") || ci.src || "";
  12002. if (/^(https?|ftp):/i.test(src) && !test(src,localDomain)) {
  12003. remoteImages.push(src);
  12004. }
  12005. }
  12006. if (remoteImages.length) {
  12007. catchremoteimage(remoteImages, {
  12008. //成功抓取
  12009. success:function (xhr) {
  12010. try {
  12011. var info = eval("(" + xhr.responseText + ")");
  12012. } catch (e) {
  12013. return;
  12014. }
  12015. var srcUrls = info.srcUrl.split(separater),
  12016. urls = info.url.split(separater);
  12017. for (var i = 0, ci; ci = imgs[i++];) {
  12018. var src = ci.getAttribute("data_ue_src") || ci.src || "";
  12019. for (var j = 0, cj; cj = srcUrls[j++];) {
  12020. var url = urls[j - 1];
  12021. if (src == cj && url != "error") { //抓取失败时不做替换处理
  12022. //地址修正
  12023. var newSrc = me.options.catcherPath + url;
  12024. domUtils.setAttributes(ci, {
  12025. "src":newSrc,
  12026. "data_ue_src":newSrc
  12027. });
  12028. break;
  12029. }
  12030. }
  12031. }
  12032. },
  12033. //回调失败,本次请求超时
  12034. error:function () {
  12035. me.fireEvent("catchremoteerror");
  12036. }
  12037. });
  12038. }
  12039. });
  12040. };
  12041. ///import core
  12042. ///commandsName snapscreen
  12043. ///commandsTitle 截屏
  12044. /**
  12045. * 截屏插件
  12046. */
  12047. UE.commands['snapscreen'] = {
  12048. execCommand: function(){
  12049. var me = this,lang = me.getLang("snapScreen_plugin");
  12050. me.setOpt({
  12051. snapscreenServerPort: 80 //屏幕截图的server端端口
  12052. ,snapscreenImgAlign: 'center' //截图的图片默认的排版方式
  12053. });
  12054. var editorOptions = me.options;
  12055. if(!browser.ie){
  12056. alert(lang.browserMsg);
  12057. return;
  12058. }
  12059. var onSuccess = function(rs){
  12060. try{
  12061. rs = eval("("+ rs +")");
  12062. }catch(e){
  12063. alert(lang.callBackErrorMsg);
  12064. return;
  12065. }
  12066. if(rs.state != 'SUCCESS'){
  12067. alert(rs.state);
  12068. return;
  12069. }
  12070. me.execCommand('insertimage', {
  12071. src: editorOptions.snapscreenPath + rs.url,
  12072. floatStyle: editorOptions.snapscreenImgAlign,
  12073. data_ue_src:editorOptions.snapscreenPath + rs.url
  12074. });
  12075. };
  12076. var onStartUpload = function(){
  12077. //开始截图上传
  12078. };
  12079. var onError = function(){
  12080. alert(lang.uploadErrorMsg);
  12081. };
  12082. try{
  12083. var nativeObj = new ActiveXObject('Snapsie.CoSnapsie');
  12084. nativeObj.saveSnapshot(editorOptions.snapscreenHost, editorOptions.snapscreenServerUrl, editorOptions.snapscreenServerPort, onStartUpload,onSuccess,onError);
  12085. }catch(e){
  12086. me.ui._dialogs['snapscreenDialog'].open();
  12087. }
  12088. },
  12089. queryCommandState: function(){
  12090. return this.highlight || !browser.ie ? -1 :0;
  12091. }
  12092. };
  12093. ///import core
  12094. ///commandsName attachment
  12095. ///commandsTitle 附件上传
  12096. UE.commands["attachment"] = {
  12097. queryCommandState:function(){
  12098. return this.highlight ? -1 :0;
  12099. }
  12100. };
  12101. /**
  12102. * Created by JetBrains PhpStorm.
  12103. * User: taoqili
  12104. * Date: 12-5-7
  12105. * Time: 下午2:37
  12106. * To change this template use File | Settings | File Templates.
  12107. */
  12108. UE.plugins['webapp'] = function () {
  12109. var me = this;
  12110. function createInsertStr( obj, toIframe, addParagraph ) {
  12111. return !toIframe ?
  12112. (addParagraph ? '<p>' : '') + '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
  12113. ' 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 + '" />' +
  12114. (addParagraph ? '</p>' : '')
  12115. :
  12116. '<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>';
  12117. }
  12118. function switchImgAndIframe( img2frame ) {
  12119. var tmpdiv,
  12120. nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
  12121. for ( var i = 0, node; node = nodes[i++]; ) {
  12122. if ( node.className != "edui-faked-webapp" ){
  12123. continue;
  12124. }
  12125. tmpdiv = me.document.createElement( "div" );
  12126. 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 );
  12127. node.parentNode.replaceChild( tmpdiv.firstChild, node );
  12128. }
  12129. }
  12130. me.addListener( "beforegetcontent", function () {
  12131. switchImgAndIframe( true );
  12132. } );
  12133. me.addListener( 'aftersetcontent', function () {
  12134. switchImgAndIframe( false );
  12135. } );
  12136. me.addListener( 'aftergetcontent', function ( cmdName ) {
  12137. if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
  12138. return;
  12139. }
  12140. switchImgAndIframe( false );
  12141. } );
  12142. UE.commands['webapp'] = {
  12143. execCommand:function ( cmd, obj ) {
  12144. me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
  12145. },
  12146. queryCommandState:function () {
  12147. return me.highlight ? -1 : 0;
  12148. }
  12149. };
  12150. };
  12151. ///import core
  12152. ///commands 模板
  12153. ///commandsName template
  12154. ///commandsTitle 模板
  12155. ///commandsDialog dialogs\template\template.html
  12156. (function() {
  12157. UE.plugins['template'] = function(){
  12158. var me = this;
  12159. UE.commands['template'] = {
  12160. execCommand : function(cmd,obj) {
  12161. obj.html&&me.execCommand("inserthtml",obj.html);
  12162. },
  12163. queryCommandState : function(){
  12164. return this.highlight ? -1 : 0;
  12165. }
  12166. };
  12167. me.addListener("click",function(type,evt){
  12168. var el = evt.target || evt.srcElement,
  12169. range = me.selection.getRange();
  12170. var tnode = domUtils.findParent(el,function(node){
  12171. if(node.className && domUtils.hasClass(node,"ue_t")){
  12172. return node;
  12173. }
  12174. },true);
  12175. tnode&&range.selectNode(tnode).shrinkBoundary().select();
  12176. });
  12177. me.addListener("keydown",function(type, evt){
  12178. var range = me.selection.getRange();
  12179. if(!range.collapsed){
  12180. if(!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey){
  12181. var tnode = domUtils.findParent(range.startContainer,function(node){
  12182. if(node.className && domUtils.hasClass(node,"ue_t")){
  12183. return node;
  12184. }
  12185. },true);
  12186. if(tnode){
  12187. domUtils.removeClasses(tnode,["ue_t"]);
  12188. }
  12189. }
  12190. }
  12191. });
  12192. };
  12193. })();
  12194. var baidu = baidu || {};
  12195. baidu.editor = baidu.editor || {};
  12196. baidu.editor.ui = {};
  12197. (function (){
  12198. var browser = baidu.editor.browser,
  12199. domUtils = baidu.editor.dom.domUtils;
  12200. var magic = '$EDITORUI';
  12201. var root = window[magic] = {};
  12202. var uidMagic = 'ID' + magic;
  12203. var uidCount = 0;
  12204. var uiUtils = baidu.editor.ui.uiUtils = {
  12205. uid: function (obj){
  12206. return (obj ? obj[uidMagic] || (obj[uidMagic] = ++ uidCount) : ++ uidCount);
  12207. },
  12208. hook: function ( fn, callback ) {
  12209. var dg;
  12210. if (fn && fn._callbacks) {
  12211. dg = fn;
  12212. } else {
  12213. dg = function (){
  12214. var q;
  12215. if (fn) {
  12216. q = fn.apply(this, arguments);
  12217. }
  12218. var callbacks = dg._callbacks;
  12219. var k = callbacks.length;
  12220. while (k --) {
  12221. var r = callbacks[k].apply(this, arguments);
  12222. if (q === undefined) {
  12223. q = r;
  12224. }
  12225. }
  12226. return q;
  12227. };
  12228. dg._callbacks = [];
  12229. }
  12230. dg._callbacks.push(callback);
  12231. return dg;
  12232. },
  12233. createElementByHtml: function (html){
  12234. var el = document.createElement('div');
  12235. el.innerHTML = html;
  12236. el = el.firstChild;
  12237. el.parentNode.removeChild(el);
  12238. return el;
  12239. },
  12240. getViewportElement: function (){
  12241. return (browser.ie && browser.quirks) ?
  12242. document.body : document.documentElement;
  12243. },
  12244. getClientRect: function (element){
  12245. var bcr;
  12246. //trace IE6下在控制编辑器显隐时可能会报错,catch一下
  12247. try{
  12248. bcr = element.getBoundingClientRect();
  12249. }catch(e){
  12250. bcr={left:0,top:0,height:0,width:0}
  12251. }
  12252. var rect = {
  12253. left: Math.round(bcr.left),
  12254. top: Math.round(bcr.top),
  12255. height: Math.round(bcr.bottom - bcr.top),
  12256. width: Math.round(bcr.right - bcr.left)
  12257. };
  12258. var doc;
  12259. while ((doc = element.ownerDocument) !== document &&
  12260. (element = domUtils.getWindow(doc).frameElement)) {
  12261. bcr = element.getBoundingClientRect();
  12262. rect.left += bcr.left;
  12263. rect.top += bcr.top;
  12264. }
  12265. rect.bottom = rect.top + rect.height;
  12266. rect.right = rect.left + rect.width;
  12267. return rect;
  12268. },
  12269. getViewportRect: function (){
  12270. var viewportEl = uiUtils.getViewportElement();
  12271. var width = (window.innerWidth || viewportEl.clientWidth) | 0;
  12272. var height = (window.innerHeight ||viewportEl.clientHeight) | 0;
  12273. return {
  12274. left: 0,
  12275. top: 0,
  12276. height: height,
  12277. width: width,
  12278. bottom: height,
  12279. right: width
  12280. };
  12281. },
  12282. setViewportOffset: function (element, offset){
  12283. var rect;
  12284. var fixedLayer = uiUtils.getFixedLayer();
  12285. if (element.parentNode === fixedLayer) {
  12286. element.style.left = offset.left + 'px';
  12287. element.style.top = offset.top + 'px';
  12288. } else {
  12289. domUtils.setViewportOffset(element, offset);
  12290. }
  12291. },
  12292. getEventOffset: function (evt){
  12293. var el = evt.target || evt.srcElement;
  12294. var rect = uiUtils.getClientRect(el);
  12295. var offset = uiUtils.getViewportOffsetByEvent(evt);
  12296. return {
  12297. left: offset.left - rect.left,
  12298. top: offset.top - rect.top
  12299. };
  12300. },
  12301. getViewportOffsetByEvent: function (evt){
  12302. var el = evt.target || evt.srcElement;
  12303. var frameEl = domUtils.getWindow(el).frameElement;
  12304. var offset = {
  12305. left: evt.clientX,
  12306. top: evt.clientY
  12307. };
  12308. if (frameEl && el.ownerDocument !== document) {
  12309. var rect = uiUtils.getClientRect(frameEl);
  12310. offset.left += rect.left;
  12311. offset.top += rect.top;
  12312. }
  12313. return offset;
  12314. },
  12315. setGlobal: function (id, obj){
  12316. root[id] = obj;
  12317. return magic + '["' + id + '"]';
  12318. },
  12319. unsetGlobal: function (id){
  12320. delete root[id];
  12321. },
  12322. copyAttributes: function (tgt, src){
  12323. var attributes = src.attributes;
  12324. var k = attributes.length;
  12325. while (k --) {
  12326. var attrNode = attributes[k];
  12327. if ( attrNode.nodeName != 'style' && attrNode.nodeName != 'class' && (!browser.ie || attrNode.specified) ) {
  12328. tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue);
  12329. }
  12330. }
  12331. if (src.className) {
  12332. tgt.className += ' ' + src.className;
  12333. }
  12334. if (src.style.cssText) {
  12335. tgt.style.cssText += ';' + src.style.cssText;
  12336. }
  12337. },
  12338. removeStyle: function (el, styleName){
  12339. if (el.style.removeProperty) {
  12340. el.style.removeProperty(styleName);
  12341. } else if (el.style.removeAttribute) {
  12342. el.style.removeAttribute(styleName);
  12343. } else throw '';
  12344. },
  12345. contains: function (elA, elB){
  12346. return elA && elB && (elA === elB ? false : (
  12347. elA.contains ? elA.contains(elB) :
  12348. elA.compareDocumentPosition(elB) & 16
  12349. ));
  12350. },
  12351. startDrag: function (evt, callbacks,doc){
  12352. var doc = doc || document;
  12353. var startX = evt.clientX;
  12354. var startY = evt.clientY;
  12355. function handleMouseMove(evt){
  12356. var x = evt.clientX - startX;
  12357. var y = evt.clientY - startY;
  12358. callbacks.ondragmove(x, y);
  12359. if (evt.stopPropagation) {
  12360. evt.stopPropagation();
  12361. } else {
  12362. evt.cancelBubble = true;
  12363. }
  12364. }
  12365. if (doc.addEventListener) {
  12366. function handleMouseUp(evt){
  12367. doc.removeEventListener('mousemove', handleMouseMove, true);
  12368. doc.removeEventListener('mouseup', handleMouseMove, true);
  12369. window.removeEventListener('mouseup', handleMouseUp, true);
  12370. callbacks.ondragstop();
  12371. }
  12372. doc.addEventListener('mousemove', handleMouseMove, true);
  12373. doc.addEventListener('mouseup', handleMouseUp, true);
  12374. window.addEventListener('mouseup', handleMouseUp, true);
  12375. evt.preventDefault();
  12376. } else {
  12377. var elm = evt.srcElement;
  12378. elm.setCapture();
  12379. function releaseCaptrue(){
  12380. elm.releaseCapture();
  12381. elm.detachEvent('onmousemove', handleMouseMove);
  12382. elm.detachEvent('onmouseup', releaseCaptrue);
  12383. elm.detachEvent('onlosecaptrue', releaseCaptrue);
  12384. callbacks.ondragstop();
  12385. }
  12386. elm.attachEvent('onmousemove', handleMouseMove);
  12387. elm.attachEvent('onmouseup', releaseCaptrue);
  12388. elm.attachEvent('onlosecaptrue', releaseCaptrue);
  12389. evt.returnValue = false;
  12390. }
  12391. callbacks.ondragstart();
  12392. },
  12393. getFixedLayer: function (){
  12394. var layer = document.getElementById('edui_fixedlayer');
  12395. if (layer == null) {
  12396. layer = document.createElement('div');
  12397. layer.id = 'edui_fixedlayer';
  12398. document.body.appendChild(layer);
  12399. if (browser.ie && browser.version <= 8) {
  12400. layer.style.position = 'absolute';
  12401. bindFixedLayer();
  12402. setTimeout(updateFixedOffset);
  12403. } else {
  12404. layer.style.position = 'fixed';
  12405. }
  12406. layer.style.left = '0';
  12407. layer.style.top = '0';
  12408. layer.style.width = '0';
  12409. layer.style.height = '0';
  12410. }
  12411. return layer;
  12412. },
  12413. makeUnselectable: function (element){
  12414. if (browser.opera || (browser.ie && browser.version < 9)) {
  12415. element.unselectable = 'on';
  12416. if (element.hasChildNodes()) {
  12417. for (var i=0; i<element.childNodes.length; i++) {
  12418. if (element.childNodes[i].nodeType == 1) {
  12419. uiUtils.makeUnselectable(element.childNodes[i]);
  12420. }
  12421. }
  12422. }
  12423. } else {
  12424. if (element.style.MozUserSelect !== undefined) {
  12425. element.style.MozUserSelect = 'none';
  12426. } else if (element.style.WebkitUserSelect !== undefined) {
  12427. element.style.WebkitUserSelect = 'none';
  12428. } else if (element.style.KhtmlUserSelect !== undefined) {
  12429. element.style.KhtmlUserSelect = 'none';
  12430. }
  12431. }
  12432. }
  12433. };
  12434. function updateFixedOffset(){
  12435. var layer = document.getElementById('edui_fixedlayer');
  12436. uiUtils.setViewportOffset(layer, {
  12437. left: 0,
  12438. top: 0
  12439. });
  12440. // layer.style.display = 'none';
  12441. // layer.style.display = 'block';
  12442. //#trace: 1354
  12443. // setTimeout(updateFixedOffset);
  12444. }
  12445. function bindFixedLayer(adjOffset){
  12446. domUtils.on(window, 'scroll', updateFixedOffset);
  12447. domUtils.on(window, 'resize', baidu.editor.utils.defer(updateFixedOffset, 0, true));
  12448. }
  12449. })();
  12450. (function (){
  12451. var utils = baidu.editor.utils,
  12452. uiUtils = baidu.editor.ui.uiUtils,
  12453. EventBase = baidu.editor.EventBase,
  12454. UIBase = baidu.editor.ui.UIBase = function (){};
  12455. UIBase.prototype = {
  12456. className: '',
  12457. uiName: '',
  12458. initOptions: function (options){
  12459. var me = this;
  12460. for (var k in options) {
  12461. me[k] = options[k];
  12462. }
  12463. this.id = this.id || 'edui' + uiUtils.uid();
  12464. },
  12465. initUIBase: function (){
  12466. this._globalKey = utils.unhtml( uiUtils.setGlobal(this.id, this) );
  12467. },
  12468. render: function (holder){
  12469. var html = this.renderHtml();
  12470. var el = uiUtils.createElementByHtml(html);
  12471. var seatEl = this.getDom();
  12472. if (seatEl != null) {
  12473. seatEl.parentNode.replaceChild(el, seatEl);
  12474. uiUtils.copyAttributes(el, seatEl);
  12475. } else {
  12476. if (typeof holder == 'string') {
  12477. holder = document.getElementById(holder);
  12478. }
  12479. holder = holder || uiUtils.getFixedLayer();
  12480. holder.appendChild(el);
  12481. }
  12482. this.postRender();
  12483. },
  12484. getDom: function (name){
  12485. if (!name) {
  12486. return document.getElementById( this.id );
  12487. } else {
  12488. return document.getElementById( this.id + '_' + name );
  12489. }
  12490. },
  12491. postRender: function (){
  12492. this.fireEvent('postrender');
  12493. },
  12494. getHtmlTpl: function (){
  12495. return '';
  12496. },
  12497. formatHtml: function (tpl){
  12498. var prefix = 'edui-' + this.uiName;
  12499. return (tpl
  12500. .replace(/##/g, this.id)
  12501. .replace(/%%-/g, this.uiName ? prefix + '-' : '')
  12502. .replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className)
  12503. .replace(/\$\$/g, this._globalKey));
  12504. },
  12505. renderHtml: function (){
  12506. return this.formatHtml(this.getHtmlTpl());
  12507. },
  12508. dispose: function (){
  12509. var box = this.getDom();
  12510. if (box) baidu.editor.dom.domUtils.remove( box );
  12511. uiUtils.unsetGlobal(this.id);
  12512. }
  12513. };
  12514. utils.inherits(UIBase, EventBase);
  12515. })();
  12516. (function (){
  12517. var utils = baidu.editor.utils,
  12518. UIBase = baidu.editor.ui.UIBase,
  12519. Separator = baidu.editor.ui.Separator = function (options){
  12520. this.initOptions(options);
  12521. this.initSeparator();
  12522. };
  12523. Separator.prototype = {
  12524. uiName: 'separator',
  12525. initSeparator: function (){
  12526. this.initUIBase();
  12527. },
  12528. getHtmlTpl: function (){
  12529. return '<div id="##" class="edui-box %%"></div>';
  12530. }
  12531. };
  12532. utils.inherits(Separator, UIBase);
  12533. })();
  12534. ///import core
  12535. ///import uicore
  12536. (function (){
  12537. var utils = baidu.editor.utils,
  12538. domUtils = baidu.editor.dom.domUtils,
  12539. UIBase = baidu.editor.ui.UIBase,
  12540. uiUtils = baidu.editor.ui.uiUtils;
  12541. var Mask = baidu.editor.ui.Mask = function (options){
  12542. this.initOptions(options);
  12543. this.initUIBase();
  12544. };
  12545. Mask.prototype = {
  12546. getHtmlTpl: function (){
  12547. return '<div id="##" class="edui-mask %%" onmousedown="return $$._onMouseDown(event, this);"></div>';
  12548. },
  12549. postRender: function (){
  12550. var me = this;
  12551. domUtils.on(window, 'resize', function (){
  12552. setTimeout(function (){
  12553. if (!me.isHidden()) {
  12554. me._fill();
  12555. }
  12556. });
  12557. });
  12558. },
  12559. show: function (zIndex){
  12560. this._fill();
  12561. this.getDom().style.display = '';
  12562. this.getDom().style.zIndex = zIndex;
  12563. },
  12564. hide: function (){
  12565. this.getDom().style.display = 'none';
  12566. this.getDom().style.zIndex = '';
  12567. },
  12568. isHidden: function (){
  12569. return this.getDom().style.display == 'none';
  12570. },
  12571. _onMouseDown: function (){
  12572. return false;
  12573. },
  12574. _fill: function (){
  12575. var el = this.getDom();
  12576. var vpRect = uiUtils.getViewportRect();
  12577. el.style.width = vpRect.width + 'px';
  12578. el.style.height = vpRect.height + 'px';
  12579. }
  12580. };
  12581. utils.inherits(Mask, UIBase);
  12582. })();
  12583. ///import core
  12584. ///import uicore
  12585. (function () {
  12586. var utils = baidu.editor.utils,
  12587. uiUtils = baidu.editor.ui.uiUtils,
  12588. domUtils = baidu.editor.dom.domUtils,
  12589. UIBase = baidu.editor.ui.UIBase,
  12590. Popup = baidu.editor.ui.Popup = function (options){
  12591. this.initOptions(options);
  12592. this.initPopup();
  12593. };
  12594. var allPopups = [];
  12595. function closeAllPopup( el ){
  12596. var newAll = [];
  12597. for ( var i = 0; i < allPopups.length; i++ ) {
  12598. var pop = allPopups[i];
  12599. if (!pop.isHidden()) {
  12600. if (pop.queryAutoHide(el) !== false) {
  12601. pop.hide();
  12602. }
  12603. }
  12604. }
  12605. }
  12606. Popup.postHide = closeAllPopup;
  12607. var ANCHOR_CLASSES = ['edui-anchor-topleft','edui-anchor-topright',
  12608. 'edui-anchor-bottomleft','edui-anchor-bottomright'];
  12609. Popup.prototype = {
  12610. SHADOW_RADIUS: 5,
  12611. content: null,
  12612. _hidden: false,
  12613. autoRender: true,
  12614. canSideLeft: true,
  12615. canSideUp: true,
  12616. initPopup: function (){
  12617. this.initUIBase();
  12618. allPopups.push( this );
  12619. },
  12620. getHtmlTpl: function (){
  12621. return '<div id="##" class="edui-popup %%">' +
  12622. ' <div id="##_body" class="edui-popup-body">' +
  12623. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: white;" frameborder="0" width="100%" height="100%" src="javascript:"></iframe>' +
  12624. ' <div class="edui-shadow"></div>' +
  12625. ' <div id="##_content" class="edui-popup-content">' +
  12626. this.getContentHtmlTpl() +
  12627. ' </div>' +
  12628. ' </div>' +
  12629. '</div>';
  12630. },
  12631. getContentHtmlTpl: function (){
  12632. if(this.content){
  12633. if (typeof this.content == 'string') {
  12634. return this.content;
  12635. }
  12636. return this.content.renderHtml();
  12637. }else{
  12638. return ''
  12639. }
  12640. },
  12641. _UIBase_postRender: UIBase.prototype.postRender,
  12642. postRender: function (){
  12643. if (this.content instanceof UIBase) {
  12644. this.content.postRender();
  12645. }
  12646. this.fireEvent('postRenderAfter');
  12647. this.hide(true);
  12648. this._UIBase_postRender();
  12649. },
  12650. _doAutoRender: function (){
  12651. if (!this.getDom() && this.autoRender) {
  12652. this.render();
  12653. }
  12654. },
  12655. mesureSize: function (){
  12656. var box = this.getDom('content');
  12657. return uiUtils.getClientRect(box);
  12658. },
  12659. fitSize: function (){
  12660. var popBodyEl = this.getDom('body');
  12661. popBodyEl.style.width = '';
  12662. popBodyEl.style.height = '';
  12663. var size = this.mesureSize();
  12664. popBodyEl.style.width = size.width + 'px';
  12665. popBodyEl.style.height = size.height + 'px';
  12666. return size;
  12667. },
  12668. showAnchor: function ( element, hoz ){
  12669. this.showAnchorRect( uiUtils.getClientRect( element ), hoz );
  12670. },
  12671. showAnchorRect: function ( rect, hoz, adj ){
  12672. this._doAutoRender();
  12673. var vpRect = uiUtils.getViewportRect();
  12674. this._show();
  12675. var popSize = this.fitSize();
  12676. var sideLeft, sideUp, left, top;
  12677. if (hoz) {
  12678. sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width);
  12679. sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height);
  12680. left = (sideLeft ? rect.left - popSize.width : rect.right);
  12681. top = (sideUp ? rect.bottom - popSize.height : rect.top);
  12682. } else {
  12683. sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width);
  12684. sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height);
  12685. left = (sideLeft ? rect.right - popSize.width : rect.left);
  12686. top = (sideUp ? rect.top - popSize.height : rect.bottom);
  12687. }
  12688. var popEl = this.getDom();
  12689. uiUtils.setViewportOffset(popEl, {
  12690. left: left,
  12691. top: top
  12692. });
  12693. domUtils.removeClasses(popEl, ANCHOR_CLASSES);
  12694. popEl.className += ' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
  12695. if(this.editor){
  12696. popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
  12697. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = popEl.style.zIndex - 1;
  12698. }
  12699. },
  12700. showAt: function (offset) {
  12701. var left = offset.left;
  12702. var top = offset.top;
  12703. var rect = {
  12704. left: left,
  12705. top: top,
  12706. right: left,
  12707. bottom: top,
  12708. height: 0,
  12709. width: 0
  12710. };
  12711. this.showAnchorRect(rect, false, true);
  12712. },
  12713. _show: function (){
  12714. if (this._hidden) {
  12715. var box = this.getDom();
  12716. box.style.display = '';
  12717. this._hidden = false;
  12718. // if (box.setActive) {
  12719. // box.setActive();
  12720. // }
  12721. this.fireEvent('show');
  12722. }
  12723. },
  12724. isHidden: function (){
  12725. return this._hidden;
  12726. },
  12727. show: function (){
  12728. this._doAutoRender();
  12729. this._show();
  12730. },
  12731. hide: function (notNofity){
  12732. if (!this._hidden && this.getDom()) {
  12733. // this.getDom().style.visibility = 'hidden';
  12734. this.getDom().style.display = 'none';
  12735. this._hidden = true;
  12736. if (!notNofity) {
  12737. this.fireEvent('hide');
  12738. }
  12739. }
  12740. },
  12741. queryAutoHide: function (el){
  12742. return !el || !uiUtils.contains(this.getDom(), el);
  12743. }
  12744. };
  12745. utils.inherits(Popup, UIBase);
  12746. domUtils.on( document, 'mousedown', function ( evt ) {
  12747. var el = evt.target || evt.srcElement;
  12748. closeAllPopup( el );
  12749. } );
  12750. domUtils.on( window, 'scroll', function () {
  12751. closeAllPopup();
  12752. } );
  12753. // var lastVpRect = uiUtils.getViewportRect();
  12754. // domUtils.on( window, 'resize', function () {
  12755. // var vpRect = uiUtils.getViewportRect();
  12756. // if (vpRect.width != lastVpRect.width || vpRect.height != lastVpRect.height) {
  12757. // closeAllPopup();
  12758. // }
  12759. // } );
  12760. })();
  12761. ///import core
  12762. ///import uicore
  12763. (function (){
  12764. var utils = baidu.editor.utils,
  12765. UIBase = baidu.editor.ui.UIBase,
  12766. ColorPicker = baidu.editor.ui.ColorPicker = function (options){
  12767. this.initOptions(options);
  12768. this.noColorText = this.noColorText || this.editor.getLang("clearColor");
  12769. this.initUIBase();
  12770. };
  12771. ColorPicker.prototype = {
  12772. getHtmlTpl: function (){
  12773. return genColorPicker(this.noColorText,this.editor);
  12774. },
  12775. _onTableClick: function (evt){
  12776. var tgt = evt.target || evt.srcElement;
  12777. var color = tgt.getAttribute('data-color');
  12778. if (color) {
  12779. this.fireEvent('pickcolor', color);
  12780. }
  12781. },
  12782. _onTableOver: function (evt){
  12783. var tgt = evt.target || evt.srcElement;
  12784. var color = tgt.getAttribute('data-color');
  12785. if (color) {
  12786. this.getDom('preview').style.backgroundColor = color;
  12787. }
  12788. },
  12789. _onTableOut: function (){
  12790. this.getDom('preview').style.backgroundColor = '';
  12791. },
  12792. _onPickNoColor: function (){
  12793. this.fireEvent('picknocolor');
  12794. }
  12795. };
  12796. utils.inherits(ColorPicker, UIBase);
  12797. var COLORS = (
  12798. 'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' +
  12799. 'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' +
  12800. 'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' +
  12801. 'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' +
  12802. 'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' +
  12803. '7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' +
  12804. 'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,').split(',');
  12805. function genColorPicker(noColorText,editor){
  12806. var html = '<div id="##" class="edui-colorpicker %%">' +
  12807. '<div class="edui-colorpicker-topbar edui-clearfix">' +
  12808. '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
  12809. '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">'+ noColorText +'</div>' +
  12810. '</div>' +
  12811. '<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">' +
  12812. '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#366092;padding-top: 2px"><td colspan="10">'+editor.getLang("themeColor")+'</td> </tr>'+
  12813. '<tr class="edui-colorpicker-tablefirstrow" >';
  12814. for (var i=0; i<COLORS.length; i++) {
  12815. if (i && i%10 === 0) {
  12816. html += '</tr>'+(i==60?'<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#366092;"><td colspan="10">'+editor.getLang("standardColor")+'</td></tr>':'')+'<tr'+(i==60?' class="edui-colorpicker-tablefirstrow"':'')+'>';
  12817. }
  12818. html += i<70 ? '<td style="padding: 0 2px;"><a hidefocus title="'+COLORS[i]+'" onclick="return false;" href="javascript:" unselectable="on" class="edui-box edui-colorpicker-colorcell"' +
  12819. ' data-color="#'+ COLORS[i] +'"'+
  12820. ' style="background-color:#'+ COLORS[i] +';border:solid #ccc;'+
  12821. (i<10 || i>=60?'border-width:1px;':
  12822. i>=10&&i<20?'border-width:1px 1px 0 1px;':
  12823. 'border-width:0 1px 0 1px;')+
  12824. '"' +
  12825. '></a></td>':'';
  12826. }
  12827. html += '</tr></table></div>';
  12828. return html;
  12829. }
  12830. })();
  12831. ///import core
  12832. ///import uicore
  12833. (function (){
  12834. var utils = baidu.editor.utils,
  12835. uiUtils = baidu.editor.ui.uiUtils,
  12836. UIBase = baidu.editor.ui.UIBase;
  12837. var TablePicker = baidu.editor.ui.TablePicker = function (options){
  12838. this.initOptions(options);
  12839. this.initTablePicker();
  12840. };
  12841. TablePicker.prototype = {
  12842. defaultNumRows: 10,
  12843. defaultNumCols: 10,
  12844. maxNumRows: 20,
  12845. maxNumCols: 20,
  12846. numRows: 10,
  12847. numCols: 10,
  12848. lengthOfCellSide: 22,
  12849. initTablePicker: function (){
  12850. this.initUIBase();
  12851. },
  12852. getHtmlTpl: function (){
  12853. var me = this;
  12854. return '<div id="##" class="edui-tablepicker %%">' +
  12855. '<div class="edui-tablepicker-body">' +
  12856. '<div class="edui-infoarea">' +
  12857. '<span id="##_label" class="edui-label"></span>' +
  12858. '<span class="edui-clickable" onclick="$$._onMore();">'+me.editor.getLang("more")+'</span>' +
  12859. '</div>' +
  12860. '<div class="edui-pickarea"' +
  12861. ' onmousemove="$$._onMouseMove(event, this);"' +
  12862. ' onmouseover="$$._onMouseOver(event, this);"' +
  12863. ' onmouseout="$$._onMouseOut(event, this);"' +
  12864. ' onclick="$$._onClick(event, this);"' +
  12865. '>' +
  12866. '<div id="##_overlay" class="edui-overlay"></div>' +
  12867. '</div>' +
  12868. '</div>' +
  12869. '</div>';
  12870. },
  12871. _UIBase_render: UIBase.prototype.render,
  12872. render: function (holder){
  12873. this._UIBase_render(holder);
  12874. this.getDom('label').innerHTML = '0'+this.editor.getLang("t_row")+' x 0'+this.editor.getLang("t_col");
  12875. },
  12876. _track: function (numCols, numRows){
  12877. var style = this.getDom('overlay').style;
  12878. var sideLen = this.lengthOfCellSide;
  12879. style.width = numCols * sideLen + 'px';
  12880. style.height = numRows * sideLen + 'px';
  12881. var label = this.getDom('label');
  12882. label.innerHTML = numCols +this.editor.getLang("t_col")+' x ' + numRows + this.editor.getLang("t_row");
  12883. this.numCols = numCols;
  12884. this.numRows = numRows;
  12885. },
  12886. _onMouseOver: function (evt, el){
  12887. var rel = evt.relatedTarget || evt.fromElement;
  12888. if (!uiUtils.contains(el, rel) && el !== rel) {
  12889. this.getDom('label').innerHTML = '0'+this.editor.getLang("t_col")+' x 0'+this.editor.getLang("t_row");
  12890. this.getDom('overlay').style.visibility = '';
  12891. }
  12892. },
  12893. _onMouseOut: function (evt, el){
  12894. var rel = evt.relatedTarget || evt.toElement;
  12895. if (!uiUtils.contains(el, rel) && el !== rel) {
  12896. this.getDom('label').innerHTML = '0'+this.editor.getLang("t_col")+' x 0'+this.editor.getLang("t_row");
  12897. this.getDom('overlay').style.visibility = 'hidden';
  12898. }
  12899. },
  12900. _onMouseMove: function (evt, el){
  12901. var style = this.getDom('overlay').style;
  12902. var offset = uiUtils.getEventOffset(evt);
  12903. var sideLen = this.lengthOfCellSide;
  12904. var numCols = Math.ceil(offset.left / sideLen);
  12905. var numRows = Math.ceil(offset.top / sideLen);
  12906. this._track(numCols, numRows);
  12907. },
  12908. _onClick: function (){
  12909. this.fireEvent('picktable', this.numCols, this.numRows);
  12910. },
  12911. _onMore: function (){
  12912. this.fireEvent('more');
  12913. }
  12914. };
  12915. utils.inherits(TablePicker, UIBase);
  12916. })();
  12917. (function (){
  12918. var browser = baidu.editor.browser,
  12919. domUtils = baidu.editor.dom.domUtils,
  12920. uiUtils = baidu.editor.ui.uiUtils;
  12921. var TPL_STATEFUL = 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
  12922. ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
  12923. ( browser.ie ? (
  12924. ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
  12925. ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"' )
  12926. : (
  12927. ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
  12928. ' onmouseout="$$.Stateful_onMouseOut(event, this);"' ));
  12929. baidu.editor.ui.Stateful = {
  12930. alwalysHoverable: false,
  12931. Stateful_init: function (){
  12932. this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
  12933. this.getHtmlTpl = this.Stateful_getHtmlTpl;
  12934. },
  12935. Stateful_getHtmlTpl: function (){
  12936. var tpl = this._Stateful_dGetHtmlTpl();
  12937. // 使用function避免$转义
  12938. return tpl.replace(/stateful/g, function (){ return TPL_STATEFUL; });
  12939. },
  12940. Stateful_onMouseEnter: function (evt, el){
  12941. if (!this.isDisabled() || this.alwalysHoverable) {
  12942. this.addState('hover');
  12943. this.fireEvent('over');
  12944. }
  12945. },
  12946. Stateful_onMouseLeave: function (evt, el){
  12947. if (!this.isDisabled() || this.alwalysHoverable) {
  12948. this.removeState('hover');
  12949. this.removeState('active');
  12950. this.fireEvent('out');
  12951. }
  12952. },
  12953. Stateful_onMouseOver: function (evt, el){
  12954. var rel = evt.relatedTarget;
  12955. if (!uiUtils.contains(el, rel) && el !== rel) {
  12956. this.Stateful_onMouseEnter(evt, el);
  12957. }
  12958. },
  12959. Stateful_onMouseOut: function (evt, el){
  12960. var rel = evt.relatedTarget;
  12961. if (!uiUtils.contains(el, rel) && el !== rel) {
  12962. this.Stateful_onMouseLeave(evt, el);
  12963. }
  12964. },
  12965. Stateful_onMouseDown: function (evt, el){
  12966. if (!this.isDisabled()) {
  12967. this.addState('active');
  12968. }
  12969. },
  12970. Stateful_onMouseUp: function (evt, el){
  12971. if (!this.isDisabled()) {
  12972. this.removeState('active');
  12973. }
  12974. },
  12975. Stateful_postRender: function (){
  12976. if (this.disabled && !this.hasState('disabled')) {
  12977. this.addState('disabled');
  12978. }
  12979. },
  12980. hasState: function (state){
  12981. return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state);
  12982. },
  12983. addState: function (state){
  12984. if (!this.hasState(state)) {
  12985. this.getStateDom().className += ' edui-state-' + state;
  12986. }
  12987. },
  12988. removeState: function (state){
  12989. if (this.hasState(state)) {
  12990. domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state]);
  12991. }
  12992. },
  12993. getStateDom: function (){
  12994. return this.getDom('state');
  12995. },
  12996. isChecked: function (){
  12997. return this.hasState('checked');
  12998. },
  12999. setChecked: function (checked){
  13000. if (!this.isDisabled() && checked) {
  13001. this.addState('checked');
  13002. } else {
  13003. this.removeState('checked');
  13004. }
  13005. },
  13006. isDisabled: function (){
  13007. return this.hasState('disabled');
  13008. },
  13009. setDisabled: function (disabled){
  13010. if (disabled) {
  13011. this.removeState('hover');
  13012. this.removeState('checked');
  13013. this.removeState('active');
  13014. this.addState('disabled');
  13015. } else {
  13016. this.removeState('disabled');
  13017. }
  13018. }
  13019. };
  13020. })();
  13021. ///import core
  13022. ///import uicore
  13023. ///import ui/stateful.js
  13024. (function (){
  13025. var utils = baidu.editor.utils,
  13026. UIBase = baidu.editor.ui.UIBase,
  13027. Stateful = baidu.editor.ui.Stateful,
  13028. Button = baidu.editor.ui.Button = function (options){
  13029. this.initOptions(options);
  13030. this.initButton();
  13031. };
  13032. Button.prototype = {
  13033. uiName: 'button',
  13034. label: '',
  13035. title: '',
  13036. showIcon: true,
  13037. showText: true,
  13038. initButton: function (){
  13039. this.initUIBase();
  13040. this.Stateful_init();
  13041. },
  13042. getHtmlTpl: function (){
  13043. return '<div id="##" class="edui-box %%">' +
  13044. '<div id="##_state" stateful>' +
  13045. '<div class="%%-wrap"><div id="##_body" unselectable="on" ' + (this.title ? 'title="' + this.title + '"' : '') +
  13046. ' class="%%-body" onmousedown="return false;" onclick="return $$._onClick();">' +
  13047. (this.showIcon ? '<div class="edui-box edui-icon"></div>' : '') +
  13048. (this.showText ? '<div class="edui-box edui-label">' + this.label + '</div>' : '') +
  13049. '</div>' +
  13050. '</div>' +
  13051. '</div></div>';
  13052. },
  13053. postRender: function (){
  13054. this.Stateful_postRender();
  13055. this.setDisabled(this.disabled)
  13056. },
  13057. _onClick: function (){
  13058. if (!this.isDisabled()) {
  13059. this.fireEvent('click');
  13060. }
  13061. }
  13062. };
  13063. utils.inherits(Button, UIBase);
  13064. utils.extend(Button.prototype, Stateful);
  13065. })();
  13066. ///import core
  13067. ///import uicore
  13068. ///import ui/stateful.js
  13069. (function (){
  13070. var utils = baidu.editor.utils,
  13071. uiUtils = baidu.editor.ui.uiUtils,
  13072. domUtils = baidu.editor.dom.domUtils,
  13073. UIBase = baidu.editor.ui.UIBase,
  13074. Stateful = baidu.editor.ui.Stateful,
  13075. SplitButton = baidu.editor.ui.SplitButton = function (options){
  13076. this.initOptions(options);
  13077. this.initSplitButton();
  13078. };
  13079. SplitButton.prototype = {
  13080. popup: null,
  13081. uiName: 'splitbutton',
  13082. title: '',
  13083. initSplitButton: function (){
  13084. this.initUIBase();
  13085. this.Stateful_init();
  13086. var me = this;
  13087. if (this.popup != null) {
  13088. var popup = this.popup;
  13089. this.popup = null;
  13090. this.setPopup(popup);
  13091. }
  13092. },
  13093. _UIBase_postRender: UIBase.prototype.postRender,
  13094. postRender: function (){
  13095. this.Stateful_postRender();
  13096. this._UIBase_postRender();
  13097. },
  13098. setPopup: function (popup){
  13099. if (this.popup === popup) return;
  13100. if (this.popup != null) {
  13101. this.popup.dispose();
  13102. }
  13103. popup.addListener('show', utils.bind(this._onPopupShow, this));
  13104. popup.addListener('hide', utils.bind(this._onPopupHide, this));
  13105. popup.addListener('postrender', utils.bind(function (){
  13106. popup.getDom('body').appendChild(
  13107. uiUtils.createElementByHtml('<div id="' +
  13108. this.popup.id + '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
  13109. (uiUtils.getClientRect(this.getDom()).width - 2) + 'px"></div>')
  13110. );
  13111. popup.getDom().className += ' ' + this.className;
  13112. }, this));
  13113. this.popup = popup;
  13114. },
  13115. _onPopupShow: function (){
  13116. this.addState('opened');
  13117. },
  13118. _onPopupHide: function (){
  13119. this.removeState('opened');
  13120. },
  13121. getHtmlTpl: function (){
  13122. return '<div id="##" class="edui-box %%">' +
  13123. '<div '+ (this.title ? 'title="' + this.title + '"' : '') +' id="##_state" stateful><div class="%%-body">' +
  13124. '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
  13125. '<div class="edui-box edui-icon"></div>' +
  13126. '</div>' +
  13127. '<div class="edui-box edui-splitborder"></div>' +
  13128. '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
  13129. '</div></div></div>';
  13130. },
  13131. showPopup: function (){
  13132. // 当popup往上弹出的时候,做特殊处理
  13133. var rect = uiUtils.getClientRect(this.getDom());
  13134. rect.top -= this.popup.SHADOW_RADIUS;
  13135. rect.height += this.popup.SHADOW_RADIUS;
  13136. this.popup.showAnchorRect(rect);
  13137. },
  13138. _onArrowClick: function (event, el){
  13139. if (!this.isDisabled()) {
  13140. this.showPopup();
  13141. }
  13142. },
  13143. _onButtonClick: function (){
  13144. if (!this.isDisabled()) {
  13145. this.fireEvent('buttonclick');
  13146. }
  13147. }
  13148. };
  13149. utils.inherits(SplitButton, UIBase);
  13150. utils.extend(SplitButton.prototype, Stateful, true);
  13151. })();
  13152. ///import core
  13153. ///import uicore
  13154. ///import ui/colorpicker.js
  13155. ///import ui/popup.js
  13156. ///import ui/splitbutton.js
  13157. (function (){
  13158. var utils = baidu.editor.utils,
  13159. uiUtils = baidu.editor.ui.uiUtils,
  13160. ColorPicker = baidu.editor.ui.ColorPicker,
  13161. Popup = baidu.editor.ui.Popup,
  13162. SplitButton = baidu.editor.ui.SplitButton,
  13163. ColorButton = baidu.editor.ui.ColorButton = function (options){
  13164. this.initOptions(options);
  13165. this.initColorButton();
  13166. };
  13167. ColorButton.prototype = {
  13168. initColorButton: function (){
  13169. var me = this;
  13170. this.popup = new Popup({
  13171. content: new ColorPicker({
  13172. noColorText: me.editor.getLang("clearColor"),
  13173. editor:me.editor,
  13174. onpickcolor: function (t, color){
  13175. me._onPickColor(color);
  13176. },
  13177. onpicknocolor: function (t, color){
  13178. me._onPickNoColor(color);
  13179. }
  13180. }),
  13181. editor:me.editor
  13182. });
  13183. this.initSplitButton();
  13184. },
  13185. _SplitButton_postRender: SplitButton.prototype.postRender,
  13186. postRender: function (){
  13187. this._SplitButton_postRender();
  13188. this.getDom('button_body').appendChild(
  13189. uiUtils.createElementByHtml('<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>')
  13190. );
  13191. this.getDom().className += ' edui-colorbutton';
  13192. },
  13193. setColor: function (color){
  13194. this.getDom('colorlump').style.backgroundColor = color;
  13195. this.color = color;
  13196. },
  13197. _onPickColor: function (color){
  13198. if (this.fireEvent('pickcolor', color) !== false) {
  13199. this.setColor(color);
  13200. this.popup.hide();
  13201. }
  13202. },
  13203. _onPickNoColor: function (color){
  13204. if (this.fireEvent('picknocolor') !== false) {
  13205. this.popup.hide();
  13206. }
  13207. }
  13208. };
  13209. utils.inherits(ColorButton, SplitButton);
  13210. })();
  13211. ///import core
  13212. ///import uicore
  13213. ///import ui/popup.js
  13214. ///import ui/tablepicker.js
  13215. ///import ui/splitbutton.js
  13216. (function (){
  13217. var utils = baidu.editor.utils,
  13218. Popup = baidu.editor.ui.Popup,
  13219. TablePicker = baidu.editor.ui.TablePicker,
  13220. SplitButton = baidu.editor.ui.SplitButton,
  13221. TableButton = baidu.editor.ui.TableButton = function (options){
  13222. this.initOptions(options);
  13223. this.initTableButton();
  13224. };
  13225. TableButton.prototype = {
  13226. initTableButton: function (){
  13227. var me = this;
  13228. this.popup = new Popup({
  13229. content: new TablePicker({
  13230. editor:me.editor,
  13231. onpicktable: function (t, numCols, numRows){
  13232. me._onPickTable(numCols, numRows);
  13233. },
  13234. onmore: function (){
  13235. me.popup.hide();
  13236. me.fireEvent('more');
  13237. }
  13238. }),
  13239. 'editor':me.editor
  13240. });
  13241. this.initSplitButton();
  13242. },
  13243. _onPickTable: function (numCols, numRows){
  13244. if (this.fireEvent('picktable', numCols, numRows) !== false) {
  13245. this.popup.hide();
  13246. }
  13247. }
  13248. };
  13249. utils.inherits(TableButton, SplitButton);
  13250. })();
  13251. ///import core
  13252. ///import uicore
  13253. (function (){
  13254. var utils = baidu.editor.utils,
  13255. UIBase = baidu.editor.ui.UIBase;
  13256. var AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker = function (options){
  13257. this.initOptions(options);
  13258. this.initAutoTypeSetPicker();
  13259. };
  13260. AutoTypeSetPicker.prototype = {
  13261. initAutoTypeSetPicker: function (){
  13262. this.initUIBase();
  13263. },
  13264. getHtmlTpl: function (){
  13265. var me = this.editor,
  13266. opt = me.options.autotypeset,
  13267. lang = me.getLang("autoTypeSet");
  13268. return '<div id="##" class="edui-autotypesetpicker %%">' +
  13269. '<div class="edui-autotypesetpicker-body">' +
  13270. '<table >' +
  13271. '<tr><td colspan="2"><input type="checkbox" name="mergeEmptyline" '+ (opt["mergeEmptyline"] ? "checked" : "" )+'>'+lang.mergeLine+'</td><td colspan="2"><input type="checkbox" name="removeEmptyline" '+ (opt["removeEmptyline"] ? "checked" : "" )+'>'+lang.delLine+'</td></tr>'+
  13272. '<tr><td colspan="2"><input type="checkbox" name="removeClass" '+ (opt["removeClass"] ? "checked" : "" )+'>'+lang.removeFormat+'</td><td colspan="2"><input type="checkbox" name="indent" '+ (opt["indent"] ? "checked" : "" )+'>'+lang.indent+'</td></tr>'+
  13273. '<tr><td colspan="2"><input type="checkbox" name="textAlign" '+ (opt["textAlign"] ? "checked" : "" )+'>'+lang.alignment+'</td><td colspan="2" id="textAlignValue"><input type="radio" name="textAlignValue" value="left" '+((opt["textAlign"]&&opt["textAlign"]=="left") ? "checked" : "")+'>'+me.getLang("justifyleft")+'<input type="radio" name="textAlignValue" value="center" '+((opt["textAlign"]&&opt["textAlign"]=="center") ? "checked" : "")+'>'+me.getLang("justifycenter")+'<input type="radio" name="textAlignValue" value="right" '+((opt["textAlign"]&&opt["textAlign"]=="right") ? "checked" : "")+'>'+me.getLang("justifyright")+' </tr>'+
  13274. '<tr><td colspan="2"><input type="checkbox" name="imageBlockLine" '+ (opt["imageBlockLine"] ? "checked" : "" )+'>'+lang.imageFloat+'</td>' +
  13275. '<td colspan="2" id="imageBlockLineValue">' +
  13276. '<input type="radio" name="imageBlockLineValue" value="none" '+((opt["imageBlockLine"]&&opt["imageBlockLine"]=="none") ? "checked" : "")+'>' + me.getLang("default")+
  13277. '<input type="radio" name="imageBlockLineValue" value="left" '+((opt["imageBlockLine"]&&opt["imageBlockLine"]=="left") ? "checked" : "")+'>' + me.getLang("justifyleft")+
  13278. '<input type="radio" name="imageBlockLineValue" value="center" '+((opt["imageBlockLine"]&&opt["imageBlockLine"]=="center") ? "checked" : "")+'>' + me.getLang("justifycenter") +
  13279. '<input type="radio" name="imageBlockLineValue" value="right" '+((opt["imageBlockLine"]&&opt["imageBlockLine"]=="right") ? "checked" : "")+'>'+me.getLang("justifyright")+'</tr>'+
  13280. '<tr><td colspan="2"><input type="checkbox" name="clearFontSize" '+ (opt["clearFontSize"] ? "checked" : "" )+'>'+lang.removeFontsize+'</td><td colspan="2"><input type="checkbox" name="clearFontFamily" '+ (opt["clearFontFamily"] ? "checked" : "" )+'>'+lang.removeFontFamily+'</td></tr>'+
  13281. '<tr><td colspan="4"><input type="checkbox" name="removeEmptyNode" '+ (opt["removeEmptyNode"] ? "checked" : "" )+'>'+lang.removeHtml+'</td></tr>'+
  13282. '<tr><td colspan="4"><input type="checkbox" name="pasteFilter" '+ (opt["pasteFilter"] ? "checked" : "" )+'>'+lang.pasteFilter+'</td></tr>'+
  13283. '<tr><td colspan="4" align="right"><button >'+lang.run+'</button></td></tr>'+
  13284. '</table>'+
  13285. '</div>' +
  13286. '</div>';
  13287. },
  13288. _UIBase_render: UIBase.prototype.render
  13289. };
  13290. utils.inherits(AutoTypeSetPicker, UIBase);
  13291. })();
  13292. ///import core
  13293. ///import uicore
  13294. ///import ui/popup.js
  13295. ///import ui/autotypesetpicker.js
  13296. ///import ui/splitbutton.js
  13297. (function (){
  13298. var utils = baidu.editor.utils,
  13299. Popup = baidu.editor.ui.Popup,
  13300. AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
  13301. SplitButton = baidu.editor.ui.SplitButton,
  13302. AutoTypeSetButton = baidu.editor.ui.AutoTypeSetButton = function (options){
  13303. this.initOptions(options);
  13304. this.initAutoTypeSetButton();
  13305. };
  13306. function getPara(me){
  13307. var opt = me.editor.options.autotypeset,
  13308. cont = me.getDom(),
  13309. ipts = domUtils.getElementsByTagName(cont,"input");
  13310. for(var i=ipts.length-1,ipt;ipt=ipts[i--];){
  13311. if(ipt.getAttribute("type")=="checkbox"){
  13312. var attrName = ipt.getAttribute("name");
  13313. opt[attrName] && delete opt[attrName];
  13314. if(ipt.checked){
  13315. var attrValue = document.getElementById(attrName+"Value");
  13316. if(attrValue){
  13317. if(/input/ig.test(attrValue.tagName)){
  13318. opt[attrName] = attrValue.value;
  13319. }else{
  13320. var iptChilds = attrValue.getElementsByTagName("input");
  13321. for(var j=iptChilds.length-1,iptchild;iptchild=iptChilds[j--];){
  13322. if(iptchild.checked){
  13323. opt[attrName] = iptchild.value;
  13324. break;
  13325. }
  13326. }
  13327. }
  13328. }else{
  13329. opt[attrName] = true;
  13330. }
  13331. }
  13332. }
  13333. }
  13334. var selects = domUtils.getElementsByTagName(cont,"select");
  13335. for(var i=0,si;si=selects[i++];){
  13336. var attr = si.getAttribute('name');
  13337. opt[attr] = opt[attr] ? si.value : '';
  13338. }
  13339. me.editor.options.autotypeset = opt;
  13340. }
  13341. AutoTypeSetButton.prototype = {
  13342. initAutoTypeSetButton: function (){
  13343. var me = this;
  13344. this.popup = new Popup({
  13345. //传入配置参数
  13346. content: new AutoTypeSetPicker({editor:me.editor}),
  13347. 'editor':me.editor,
  13348. hide : function(){
  13349. if (!this._hidden && this.getDom()) {
  13350. getPara(this);
  13351. this.getDom().style.display = 'none';
  13352. this._hidden = true;
  13353. this.fireEvent('hide');
  13354. }
  13355. }
  13356. });
  13357. var flag = 0;
  13358. this.popup.addListener('postRenderAfter',function(){
  13359. var popupUI = this;
  13360. if(flag)return;
  13361. var cont = this.getDom(),
  13362. btn = cont.getElementsByTagName('button')[0];
  13363. btn.onclick = function(){
  13364. getPara(popupUI);
  13365. me.editor.execCommand('autotypeset')
  13366. };
  13367. flag = 1;
  13368. });
  13369. this.initSplitButton();
  13370. }
  13371. };
  13372. utils.inherits(AutoTypeSetButton, SplitButton);
  13373. })();
  13374. (function (){
  13375. var utils = baidu.editor.utils,
  13376. uiUtils = baidu.editor.ui.uiUtils,
  13377. UIBase = baidu.editor.ui.UIBase,
  13378. Toolbar = baidu.editor.ui.Toolbar = function (options){
  13379. this.initOptions(options);
  13380. this.initToolbar();
  13381. };
  13382. Toolbar.prototype = {
  13383. items: null,
  13384. initToolbar: function (){
  13385. this.items = this.items || [];
  13386. this.initUIBase();
  13387. },
  13388. add: function (item){
  13389. this.items.push(item);
  13390. },
  13391. getHtmlTpl: function (){
  13392. var buff = [];
  13393. for (var i=0; i<this.items.length; i++) {
  13394. buff[i] = this.items[i].renderHtml();
  13395. }
  13396. return '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
  13397. buff.join('') +
  13398. '</div>'
  13399. },
  13400. postRender: function (){
  13401. var box = this.getDom();
  13402. for (var i=0; i<this.items.length; i++) {
  13403. this.items[i].postRender();
  13404. }
  13405. uiUtils.makeUnselectable(box);
  13406. },
  13407. _onMouseDown: function (){
  13408. return false;
  13409. }
  13410. };
  13411. utils.inherits(Toolbar, UIBase);
  13412. })();
  13413. ///import core
  13414. ///import uicore
  13415. ///import ui\popup.js
  13416. ///import ui\stateful.js
  13417. (function (){
  13418. var utils = baidu.editor.utils,
  13419. domUtils = baidu.editor.dom.domUtils,
  13420. uiUtils = baidu.editor.ui.uiUtils,
  13421. UIBase = baidu.editor.ui.UIBase,
  13422. Popup = baidu.editor.ui.Popup,
  13423. Stateful = baidu.editor.ui.Stateful,
  13424. Menu = baidu.editor.ui.Menu = function (options){
  13425. this.initOptions(options);
  13426. this.initMenu();
  13427. };
  13428. var menuSeparator = {
  13429. renderHtml: function (){
  13430. return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>';
  13431. },
  13432. postRender: function (){},
  13433. queryAutoHide: function (){ return true; }
  13434. };
  13435. Menu.prototype = {
  13436. items: null,
  13437. uiName: 'menu',
  13438. initMenu: function (){
  13439. this.items = this.items || [];
  13440. this.initPopup();
  13441. this.initItems();
  13442. },
  13443. initItems: function (){
  13444. for (var i=0; i<this.items.length; i++) {
  13445. var item = this.items[i];
  13446. if (item == '-') {
  13447. this.items[i] = this.getSeparator();
  13448. } else if (!(item instanceof MenuItem)) {
  13449. this.items[i] = this.createItem(item);
  13450. }
  13451. }
  13452. },
  13453. getSeparator: function (){
  13454. return menuSeparator;
  13455. },
  13456. createItem: function (item){
  13457. return new MenuItem(item);
  13458. },
  13459. _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
  13460. getContentHtmlTpl: function (){
  13461. if (this.items.length == 0) {
  13462. return this._Popup_getContentHtmlTpl();
  13463. }
  13464. var buff = [];
  13465. for (var i=0; i<this.items.length; i++) {
  13466. var item = this.items[i];
  13467. buff[i] = item.renderHtml();
  13468. }
  13469. return ('<div class="%%-body">' + buff.join('') + '</div>');
  13470. },
  13471. _Popup_postRender: Popup.prototype.postRender,
  13472. postRender: function (){
  13473. var me = this;
  13474. for (var i=0; i<this.items.length; i++) {
  13475. var item = this.items[i];
  13476. item.ownerMenu = this;
  13477. item.postRender();
  13478. }
  13479. domUtils.on(this.getDom(), 'mouseover', function (evt){
  13480. evt = evt || event;
  13481. var rel = evt.relatedTarget || evt.fromElement;
  13482. var el = me.getDom();
  13483. if (!uiUtils.contains(el, rel) && el !== rel) {
  13484. me.fireEvent('over');
  13485. }
  13486. });
  13487. this._Popup_postRender();
  13488. },
  13489. queryAutoHide: function (el){
  13490. if (el) {
  13491. if (uiUtils.contains(this.getDom(), el)) {
  13492. return false;
  13493. }
  13494. for (var i=0; i<this.items.length; i++) {
  13495. var item = this.items[i];
  13496. if (item.queryAutoHide(el) === false) {
  13497. return false;
  13498. }
  13499. }
  13500. }
  13501. },
  13502. clearItems: function (){
  13503. for (var i=0; i<this.items.length; i++) {
  13504. var item = this.items[i];
  13505. clearTimeout(item._showingTimer);
  13506. clearTimeout(item._closingTimer);
  13507. if (item.subMenu) {
  13508. item.subMenu.destroy();
  13509. }
  13510. }
  13511. this.items = [];
  13512. },
  13513. destroy: function (){
  13514. if (this.getDom()) {
  13515. domUtils.remove(this.getDom());
  13516. }
  13517. this.clearItems();
  13518. },
  13519. dispose: function (){
  13520. this.destroy();
  13521. }
  13522. };
  13523. utils.inherits(Menu, Popup);
  13524. var MenuItem = baidu.editor.ui.MenuItem = function (options){
  13525. this.initOptions(options);
  13526. this.initUIBase();
  13527. this.Stateful_init();
  13528. if (this.subMenu && !(this.subMenu instanceof Menu)) {
  13529. this.subMenu = new Menu(this.subMenu);
  13530. }
  13531. };
  13532. MenuItem.prototype = {
  13533. label: '',
  13534. subMenu: null,
  13535. ownerMenu: null,
  13536. uiName: 'menuitem',
  13537. alwalysHoverable: true,
  13538. getHtmlTpl: function (){
  13539. return '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
  13540. '<div class="%%-body">' +
  13541. this.renderLabelHtml() +
  13542. '</div>' +
  13543. '</div>';
  13544. },
  13545. postRender: function (){
  13546. var me = this;
  13547. this.addListener('over', function (){
  13548. me.ownerMenu.fireEvent('submenuover', me);
  13549. if (me.subMenu) {
  13550. me.delayShowSubMenu();
  13551. }
  13552. });
  13553. if (this.subMenu) {
  13554. this.getDom().className += ' edui-hassubmenu';
  13555. this.subMenu.render();
  13556. this.addListener('out', function (){
  13557. me.delayHideSubMenu();
  13558. });
  13559. this.subMenu.addListener('over', function (){
  13560. clearTimeout(me._closingTimer);
  13561. me._closingTimer = null;
  13562. me.addState('opened');
  13563. });
  13564. this.ownerMenu.addListener('hide', function (){
  13565. me.hideSubMenu();
  13566. });
  13567. this.ownerMenu.addListener('submenuover', function (t, subMenu){
  13568. if (subMenu !== me) {
  13569. me.delayHideSubMenu();
  13570. }
  13571. });
  13572. this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
  13573. this.subMenu.queryAutoHide = function (el){
  13574. if (el && uiUtils.contains(me.getDom(), el)) {
  13575. return false;
  13576. }
  13577. return this._bakQueryAutoHide(el);
  13578. };
  13579. }
  13580. this.getDom().style.tabIndex = '-1';
  13581. uiUtils.makeUnselectable(this.getDom());
  13582. this.Stateful_postRender();
  13583. },
  13584. delayShowSubMenu: function (){
  13585. var me = this;
  13586. if (!me.isDisabled()) {
  13587. me.addState('opened');
  13588. clearTimeout(me._showingTimer);
  13589. clearTimeout(me._closingTimer);
  13590. me._closingTimer = null;
  13591. me._showingTimer = setTimeout(function (){
  13592. me.showSubMenu();
  13593. }, 250);
  13594. }
  13595. },
  13596. delayHideSubMenu: function (){
  13597. var me = this;
  13598. if (!me.isDisabled()) {
  13599. me.removeState('opened');
  13600. clearTimeout(me._showingTimer);
  13601. if (!me._closingTimer) {
  13602. me._closingTimer = setTimeout(function (){
  13603. if (!me.hasState('opened')) {
  13604. me.hideSubMenu();
  13605. }
  13606. me._closingTimer = null;
  13607. }, 400);
  13608. }
  13609. }
  13610. },
  13611. renderLabelHtml: function (){
  13612. return '<div class="edui-arrow"></div>' +
  13613. '<div class="edui-box edui-icon"></div>' +
  13614. '<div class="edui-box edui-label %%-label">' + (this.label || '') + '</div>';
  13615. },
  13616. getStateDom: function (){
  13617. return this.getDom();
  13618. },
  13619. queryAutoHide: function (el){
  13620. if (this.subMenu && this.hasState('opened')) {
  13621. return this.subMenu.queryAutoHide(el);
  13622. }
  13623. },
  13624. _onClick: function (event, this_){
  13625. if (this.hasState('disabled')) return;
  13626. if (this.fireEvent('click', event, this_) !== false) {
  13627. if (this.subMenu) {
  13628. this.showSubMenu();
  13629. } else {
  13630. Popup.postHide();
  13631. }
  13632. }
  13633. },
  13634. showSubMenu: function (){
  13635. var rect = uiUtils.getClientRect(this.getDom());
  13636. rect.right -= 5;
  13637. rect.left += 2;
  13638. rect.width -= 7;
  13639. rect.top -= 4;
  13640. rect.bottom += 4;
  13641. rect.height += 8;
  13642. this.subMenu.showAnchorRect(rect, true, true);
  13643. },
  13644. hideSubMenu: function (){
  13645. this.subMenu.hide();
  13646. }
  13647. };
  13648. utils.inherits(MenuItem, UIBase);
  13649. utils.extend(MenuItem.prototype, Stateful, true);
  13650. })();
  13651. ///import core
  13652. ///import uicore
  13653. ///import ui/menu.js
  13654. ///import ui/splitbutton.js
  13655. (function (){
  13656. // todo: menu和item提成通用list
  13657. var utils = baidu.editor.utils,
  13658. uiUtils = baidu.editor.ui.uiUtils,
  13659. Menu = baidu.editor.ui.Menu,
  13660. SplitButton = baidu.editor.ui.SplitButton,
  13661. Combox = baidu.editor.ui.Combox = function (options){
  13662. this.initOptions(options);
  13663. this.initCombox();
  13664. };
  13665. Combox.prototype = {
  13666. uiName: 'combox',
  13667. initCombox: function (){
  13668. var me = this;
  13669. this.items = this.items || [];
  13670. for (var i=0; i<this.items.length; i++) {
  13671. var item = this.items[i];
  13672. item.uiName = 'listitem';
  13673. item.index = i;
  13674. item.onclick = function (){
  13675. me.selectByIndex(this.index);
  13676. };
  13677. }
  13678. this.popup = new Menu({
  13679. items: this.items,
  13680. uiName: 'list',
  13681. editor:this.editor
  13682. });
  13683. this.initSplitButton();
  13684. },
  13685. _SplitButton_postRender: SplitButton.prototype.postRender,
  13686. postRender: function (){
  13687. this._SplitButton_postRender();
  13688. this.setLabel(this.label || '');
  13689. this.setValue(this.initValue || '');
  13690. },
  13691. showPopup: function (){
  13692. var rect = uiUtils.getClientRect(this.getDom());
  13693. rect.top += 1;
  13694. rect.bottom -= 1;
  13695. rect.height -= 2;
  13696. this.popup.showAnchorRect(rect);
  13697. },
  13698. getValue: function (){
  13699. return this.value;
  13700. },
  13701. setValue: function (value){
  13702. var index = this.indexByValue(value);
  13703. if (index != -1) {
  13704. this.selectedIndex = index;
  13705. this.setLabel(this.items[index].label);
  13706. this.value = this.items[index].value;
  13707. } else {
  13708. this.selectedIndex = -1;
  13709. this.setLabel(this.getLabelForUnknowValue(value));
  13710. this.value = value;
  13711. }
  13712. },
  13713. setLabel: function (label){
  13714. this.getDom('button_body').innerHTML = label;
  13715. this.label = label;
  13716. },
  13717. getLabelForUnknowValue: function (value){
  13718. return value;
  13719. },
  13720. indexByValue: function (value){
  13721. for (var i=0; i<this.items.length; i++) {
  13722. if (value == this.items[i].value) {
  13723. return i;
  13724. }
  13725. }
  13726. return -1;
  13727. },
  13728. getItem: function (index){
  13729. return this.items[index];
  13730. },
  13731. selectByIndex: function (index){
  13732. if (index < this.items.length && this.fireEvent('select', index) !== false) {
  13733. this.selectedIndex = index;
  13734. this.value = this.items[index].value;
  13735. this.setLabel(this.items[index].label);
  13736. }
  13737. }
  13738. };
  13739. utils.inherits(Combox, SplitButton);
  13740. })();
  13741. ///import core
  13742. ///import uicore
  13743. ///import ui/mask.js
  13744. ///import ui/button.js
  13745. (function (){
  13746. var utils = baidu.editor.utils,
  13747. domUtils = baidu.editor.dom.domUtils,
  13748. uiUtils = baidu.editor.ui.uiUtils,
  13749. Mask = baidu.editor.ui.Mask,
  13750. UIBase = baidu.editor.ui.UIBase,
  13751. Button = baidu.editor.ui.Button,
  13752. Dialog = baidu.editor.ui.Dialog = function (options){
  13753. this.initOptions(utils.extend({
  13754. autoReset: true,
  13755. draggable: true,
  13756. onok: function (){},
  13757. oncancel: function (){},
  13758. onclose: function (t, ok){
  13759. return ok ? this.onok() : this.oncancel();
  13760. }
  13761. },options));
  13762. this.initDialog();
  13763. };
  13764. var modalMask;
  13765. var dragMask;
  13766. Dialog.prototype = {
  13767. draggable: false,
  13768. uiName: 'dialog',
  13769. initDialog: function (){
  13770. var me = this;
  13771. this.initUIBase();
  13772. this.modalMask = (modalMask || (modalMask = new Mask({
  13773. className: 'edui-dialog-modalmask'
  13774. })));
  13775. this.dragMask = (dragMask || (dragMask = new Mask({
  13776. className: 'edui-dialog-dragmask'
  13777. })));
  13778. this.closeButton = new Button({
  13779. className: 'edui-dialog-closebutton',
  13780. title: me.closeDialog,
  13781. onclick: function (){
  13782. me.close(false);
  13783. }
  13784. });
  13785. if (this.buttons) {
  13786. for (var i=0; i<this.buttons.length; i++) {
  13787. if (!(this.buttons[i] instanceof Button)) {
  13788. this.buttons[i] = new Button(this.buttons[i]);
  13789. }
  13790. }
  13791. }
  13792. },
  13793. fitSize: function (){
  13794. var popBodyEl = this.getDom('body');
  13795. // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
  13796. // uiUtils.removeStyle(popBodyEl, 'width');
  13797. // uiUtils.removeStyle(popBodyEl, 'height');
  13798. // }
  13799. var size = this.mesureSize();
  13800. popBodyEl.style.width = size.width + 'px';
  13801. popBodyEl.style.height = size.height + 'px';
  13802. return size;
  13803. },
  13804. safeSetOffset: function (offset){
  13805. var me = this;
  13806. var el = me.getDom();
  13807. var vpRect = uiUtils.getViewportRect();
  13808. var rect = uiUtils.getClientRect(el);
  13809. var left = offset.left;
  13810. if (left + rect.width > vpRect.right) {
  13811. left = vpRect.right - rect.width;
  13812. }
  13813. var top = offset.top;
  13814. if (top + rect.height > vpRect.bottom) {
  13815. top = vpRect.bottom - rect.height;
  13816. }
  13817. el.style.left = Math.max(left, 0) + 'px';
  13818. el.style.top = Math.max(top, 0) + 'px';
  13819. },
  13820. showAtCenter: function (){
  13821. this.getDom().style.display = '';
  13822. var vpRect = uiUtils.getViewportRect();
  13823. var popSize = this.fitSize();
  13824. var titleHeight = this.getDom('titlebar').offsetHeight | 0;
  13825. var left = vpRect.width / 2 - popSize.width / 2;
  13826. var top = vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
  13827. var popEl = this.getDom();
  13828. this.safeSetOffset({
  13829. left: Math.max(left | 0, 0),
  13830. top: Math.max(top | 0, 0)
  13831. });
  13832. if (!domUtils.hasClass(popEl, 'edui-state-centered')) {
  13833. popEl.className += ' edui-state-centered';
  13834. }
  13835. this._show();
  13836. },
  13837. getContentHtml: function (){
  13838. var contentHtml = '';
  13839. if (typeof this.content == 'string') {
  13840. contentHtml = this.content;
  13841. } else if (this.iframeUrl) {
  13842. contentHtml = '<span id="'+ this.id +'_contmask" class="dialogcontmask"></span><iframe id="'+ this.id +
  13843. '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="'+ this.iframeUrl +'"></iframe>';
  13844. }
  13845. return contentHtml;
  13846. },
  13847. getHtmlTpl: function (){
  13848. var footHtml = '';
  13849. if (this.buttons) {
  13850. var buff = [];
  13851. for (var i=0; i<this.buttons.length; i++) {
  13852. buff[i] = this.buttons[i].renderHtml();
  13853. }
  13854. footHtml = '<div class="%%-foot">' +
  13855. '<div id="##_buttons" class="%%-buttons">' + buff.join('') + '</div>' +
  13856. '</div>';
  13857. }
  13858. return '<div id="##" class="%%"><div class="%%-wrap"><div id="##_body" class="%%-body">' +
  13859. '<div class="%%-shadow"></div>' +
  13860. '<div id="##_titlebar" class="%%-titlebar">' +
  13861. '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
  13862. '<span class="%%-caption">' + (this.title || '') + '</span>' +
  13863. '</div>' +
  13864. this.closeButton.renderHtml() +
  13865. '</div>' +
  13866. '<div id="##_content" class="%%-content">'+ ( this.autoReset ? '' : this.getContentHtml()) +'</div>' +
  13867. footHtml +
  13868. '</div></div></div>';
  13869. },
  13870. postRender: function (){
  13871. // todo: 保持居中/记住上次关闭位置选项
  13872. if (!this.modalMask.getDom()) {
  13873. this.modalMask.render();
  13874. this.modalMask.hide();
  13875. }
  13876. if (!this.dragMask.getDom()) {
  13877. this.dragMask.render();
  13878. this.dragMask.hide();
  13879. }
  13880. var me = this;
  13881. this.addListener('show', function (){
  13882. me.modalMask.show(this.getDom().style.zIndex - 2);
  13883. });
  13884. this.addListener('hide', function (){
  13885. me.modalMask.hide();
  13886. });
  13887. if (this.buttons) {
  13888. for (var i=0; i<this.buttons.length; i++) {
  13889. this.buttons[i].postRender();
  13890. }
  13891. }
  13892. domUtils.on(window, 'resize', function (){
  13893. setTimeout(function (){
  13894. if (!me.isHidden()) {
  13895. me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
  13896. }
  13897. });
  13898. });
  13899. this._hide();
  13900. },
  13901. mesureSize: function (){
  13902. var body = this.getDom('body');
  13903. var width = uiUtils.getClientRect(this.getDom('content')).width;
  13904. var dialogBodyStyle = body.style;
  13905. dialogBodyStyle.width = width;
  13906. return uiUtils.getClientRect(body);
  13907. },
  13908. _onTitlebarMouseDown: function (evt, el){
  13909. if (this.draggable) {
  13910. var rect;
  13911. var vpRect = uiUtils.getViewportRect();
  13912. var me = this;
  13913. uiUtils.startDrag(evt, {
  13914. ondragstart: function (){
  13915. rect = uiUtils.getClientRect(me.getDom());
  13916. me.getDom('contmask').style.visibility = 'visible';
  13917. me.dragMask.show(me.getDom().style.zIndex - 1);
  13918. },
  13919. ondragmove: function (x, y){
  13920. var left = rect.left + x;
  13921. var top = rect.top + y;
  13922. me.safeSetOffset({
  13923. left: left,
  13924. top: top
  13925. });
  13926. },
  13927. ondragstop: function (){
  13928. me.getDom('contmask').style.visibility = 'hidden';
  13929. domUtils.removeClasses(me.getDom(), ['edui-state-centered']);
  13930. me.dragMask.hide();
  13931. }
  13932. });
  13933. }
  13934. },
  13935. reset: function (){
  13936. this.getDom('content').innerHTML = this.getContentHtml();
  13937. },
  13938. _show: function (){
  13939. if (this._hidden) {
  13940. this.getDom().style.display = '';
  13941. //要高过编辑器的zindxe
  13942. this.editor.container.style.zIndex && (this.getDom().style.zIndex = this.editor.container.style.zIndex * 1 + 10);
  13943. this._hidden = false;
  13944. this.fireEvent('show');
  13945. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = this.getDom().style.zIndex - 4;
  13946. }
  13947. },
  13948. isHidden: function (){
  13949. return this._hidden;
  13950. },
  13951. _hide: function (){
  13952. if (!this._hidden) {
  13953. this.getDom().style.display = 'none';
  13954. this.getDom().style.zIndex = '';
  13955. this._hidden = true;
  13956. this.fireEvent('hide');
  13957. }
  13958. },
  13959. open: function (){
  13960. if (this.autoReset) {
  13961. //有可能还没有渲染
  13962. try{
  13963. this.reset();
  13964. }catch(e){
  13965. this.render();
  13966. this.open()
  13967. }
  13968. }
  13969. this.showAtCenter();
  13970. if (this.iframeUrl) {
  13971. try {
  13972. this.getDom('iframe').focus();
  13973. } catch(ex){}
  13974. }
  13975. },
  13976. _onCloseButtonClick: function (evt, el){
  13977. this.close(false);
  13978. },
  13979. close: function (ok){
  13980. if (this.fireEvent('close', ok) !== false) {
  13981. this._hide();
  13982. }
  13983. }
  13984. };
  13985. utils.inherits(Dialog, UIBase);
  13986. })();
  13987. ///import core
  13988. ///import uicore
  13989. ///import ui/menu.js
  13990. ///import ui/splitbutton.js
  13991. (function (){
  13992. var utils = baidu.editor.utils,
  13993. Menu = baidu.editor.ui.Menu,
  13994. SplitButton = baidu.editor.ui.SplitButton,
  13995. MenuButton = baidu.editor.ui.MenuButton = function (options){
  13996. this.initOptions(options);
  13997. this.initMenuButton();
  13998. };
  13999. MenuButton.prototype = {
  14000. initMenuButton: function (){
  14001. var me = this;
  14002. this.uiName = "menubutton";
  14003. this.popup = new Menu({
  14004. items: me.items,
  14005. className: me.className,
  14006. editor:me.editor
  14007. });
  14008. this.popup.addListener('show', function (){
  14009. var list = this;
  14010. for (var i=0; i<list.items.length; i++) {
  14011. list.items[i].removeState('checked');
  14012. if (list.items[i].value == me._value) {
  14013. list.items[i].addState('checked');
  14014. this.value = me._value;
  14015. }
  14016. }
  14017. });
  14018. this.initSplitButton();
  14019. },
  14020. setValue : function(value){
  14021. this._value = value;
  14022. }
  14023. };
  14024. utils.inherits(MenuButton, SplitButton);
  14025. })();
  14026. //ui跟编辑器的适配層
  14027. //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
  14028. //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据editor_config中的toolbars找到相应的进行实例化
  14029. (function () {
  14030. var utils = baidu.editor.utils;
  14031. var editorui = baidu.editor.ui;
  14032. var _Dialog = editorui.Dialog;
  14033. editorui.Dialog = function ( options ) {
  14034. var dialog = new _Dialog( options );
  14035. dialog.addListener( 'hide', function () {
  14036. if ( dialog.editor ) {
  14037. var editor = dialog.editor;
  14038. try {
  14039. if(browser.gecko){
  14040. var y = editor.window.scrollY,
  14041. x = editor.window.scrollX;
  14042. editor.body.focus();
  14043. editor.window.scrollTo(x,y);
  14044. }else{
  14045. editor.focus();
  14046. }
  14047. } catch ( ex ) {
  14048. }
  14049. }
  14050. } );
  14051. return dialog;
  14052. };
  14053. var iframeUrlMap = {
  14054. 'anchor':'~/dialogs/anchor/anchor.html',
  14055. 'insertimage':'~/dialogs/image/image.html',
  14056. 'inserttable':'~/dialogs/table/table.html',
  14057. 'link':'~/dialogs/link/link.html',
  14058. 'spechars':'~/dialogs/spechars/spechars.html',
  14059. 'searchreplace':'~/dialogs/searchreplace/searchreplace.html',
  14060. 'map':'~/dialogs/map/map.html',
  14061. 'gmap':'~/dialogs/gmap/gmap.html',
  14062. 'insertvideo':'~/dialogs/video/video.html',
  14063. 'help':'~/dialogs/help/help.html',
  14064. 'highlightcode':'~/dialogs/highlightcode/highlightcode.html',
  14065. 'emotion':'~/dialogs/emotion/emotion.html',
  14066. 'wordimage':'~/dialogs/wordimage/wordimage.html',
  14067. 'attachment':'~/dialogs/attachment/attachment.html',
  14068. 'insertframe':'~/dialogs/insertframe/insertframe.html',
  14069. 'edittd':'~/dialogs/table/edittd.html',
  14070. 'webapp':'~/dialogs/webapp/webapp.html',
  14071. 'snapscreen':'~/dialogs/snapscreen/snapscreen.html',
  14072. 'scrawl':'~/dialogs/scrawl/scrawl.html',
  14073. 'template':'~/dialogs/template/template.html',
  14074. 'background':'~/dialogs/background/background.html'
  14075. };
  14076. //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  14077. var btnCmds = ['undo', 'redo', 'formatmatch',
  14078. 'bold', 'italic', 'underline', 'touppercase', 'tolowercase',
  14079. 'strikethrough', 'subscript', 'superscript', 'source', 'indent', 'outdent',
  14080. 'blockquote', 'pasteplain', 'pagebreak',
  14081. 'selectall', 'print', 'preview', 'horizontal', 'removeformat', 'time', 'date', 'unlink',
  14082. 'insertparagraphbeforetable', 'insertrow', 'insertcol', 'mergeright', 'mergedown', 'deleterow',
  14083. 'deletecol', 'splittorows', 'splittocols', 'splittocells', 'mergecells', 'deletetable'];
  14084. for ( var i = 0, ci; ci = btnCmds[i++]; ) {
  14085. ci = ci.toLowerCase();
  14086. editorui[ci] = function ( cmd ) {
  14087. return function ( editor ) {
  14088. var ui = new editorui.Button( {
  14089. className:'edui-for-' + cmd,
  14090. title:editor.options.labelMap[cmd] || editor.getLang( "labelMap." + cmd ) || '',
  14091. onclick:function () {
  14092. editor.execCommand( cmd );
  14093. },
  14094. showText:false
  14095. } );
  14096. editor.addListener( 'selectionchange', function ( type, causeByUi, uiReady ) {
  14097. var state = editor.queryCommandState( cmd );
  14098. if ( state == -1 ) {
  14099. ui.setDisabled( true );
  14100. ui.setChecked( false );
  14101. } else {
  14102. if ( !uiReady ) {
  14103. ui.setDisabled( false );
  14104. ui.setChecked( state );
  14105. }
  14106. }
  14107. } );
  14108. return ui;
  14109. };
  14110. }( ci );
  14111. }
  14112. //清除文档
  14113. editorui.cleardoc = function ( editor ) {
  14114. var ui = new editorui.Button( {
  14115. className:'edui-for-cleardoc',
  14116. title:editor.options.labelMap.cleardoc || editor.getLang( "labelMap.cleardoc" ) || '',
  14117. onclick:function () {
  14118. if ( confirm( editor.getLang( "confirmClear" ) ) ) {
  14119. editor.execCommand( 'cleardoc' );
  14120. }
  14121. }
  14122. } );
  14123. editor.addListener( 'selectionchange', function () {
  14124. ui.setDisabled( editor.queryCommandState( 'cleardoc' ) == -1 );
  14125. } );
  14126. return ui;
  14127. };
  14128. //排版,图片排版,文字方向
  14129. var typeset = {
  14130. 'justify':['left', 'right', 'center', 'justify'],
  14131. 'imagefloat':['none', 'left', 'center', 'right'],
  14132. 'directionality':['ltr', 'rtl']
  14133. };
  14134. for ( var p in typeset ) {
  14135. (function ( cmd, val ) {
  14136. for ( var i = 0, ci; ci = val[i++]; ) {
  14137. (function ( cmd2 ) {
  14138. editorui[cmd.replace( 'float', '' ) + cmd2] = function ( editor ) {
  14139. var ui = new editorui.Button( {
  14140. className:'edui-for-' + cmd.replace( 'float', '' ) + cmd2,
  14141. title:editor.options.labelMap[cmd.replace( 'float', '' ) + cmd2] || editor.getLang( "labelMap." + cmd.replace( 'float', '' ) + cmd2 ) || '',
  14142. onclick:function () {
  14143. editor.execCommand( cmd, cmd2 );
  14144. }
  14145. } );
  14146. editor.addListener( 'selectionchange', function ( type, causeByUi, uiReady ) {
  14147. ui.setDisabled( editor.queryCommandState( cmd ) == -1 );
  14148. ui.setChecked( editor.queryCommandValue( cmd ) == cmd2 && !uiReady );
  14149. } );
  14150. return ui;
  14151. };
  14152. })( ci )
  14153. }
  14154. })( p, typeset[p] )
  14155. }
  14156. //字体颜色和背景颜色
  14157. for ( var i = 0, ci; ci = ['backcolor', 'forecolor'][i++]; ) {
  14158. editorui[ci] = function ( cmd ) {
  14159. return function ( editor ) {
  14160. var ui = new editorui.ColorButton( {
  14161. className:'edui-for-' + cmd,
  14162. color:'default',
  14163. title:editor.options.labelMap[cmd] || editor.getLang( "labelMap." + cmd ) || '',
  14164. editor:editor,
  14165. onpickcolor:function ( t, color ) {
  14166. editor.execCommand( cmd, color );
  14167. },
  14168. onpicknocolor:function () {
  14169. editor.execCommand( cmd, 'default' );
  14170. this.setColor( 'transparent' );
  14171. this.color = 'default';
  14172. },
  14173. onbuttonclick:function () {
  14174. editor.execCommand( cmd, this.color );
  14175. }
  14176. } );
  14177. editor.addListener( 'selectionchange', function () {
  14178. ui.setDisabled( editor.queryCommandState( cmd ) == -1 );
  14179. } );
  14180. return ui;
  14181. };
  14182. }( ci );
  14183. }
  14184. var dialogBtns = {
  14185. noOk:['searchreplace', 'help', 'spechars', 'webapp'],
  14186. ok:['attachment', 'anchor', 'link', 'insertimage', 'map', 'gmap', 'insertframe', 'wordimage',
  14187. 'insertvideo', 'highlightcode', 'insertframe', 'edittd', 'scrawl', 'template','background']
  14188. };
  14189. for ( var p in dialogBtns ) {
  14190. (function ( type, vals ) {
  14191. for ( var i = 0, ci; ci = vals[i++]; ) {
  14192. //todo opera下存在问题
  14193. if(browser.opera &&ci === "searchreplace"){
  14194. continue;
  14195. }
  14196. (function ( cmd ) {
  14197. editorui[cmd] = function ( editor, iframeUrl, title ) {
  14198. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})[cmd] || iframeUrlMap[cmd];
  14199. title = editor.options.labelMap[cmd] || editor.getLang( "labelMap." + cmd ) || '';
  14200. var dialog;
  14201. //没有iframeUrl不创建dialog
  14202. if ( iframeUrl ) {
  14203. dialog = new editorui.Dialog( utils.extend( {
  14204. iframeUrl:editor.ui.mapUrl( iframeUrl ),
  14205. editor:editor,
  14206. className:'edui-for-' + cmd,
  14207. title:title,
  14208. closeDialog:editor.getLang( "closeDialog" )
  14209. }, type == 'ok' ? {
  14210. buttons:[
  14211. {
  14212. className:'edui-okbutton',
  14213. label:editor.getLang( "ok" ),
  14214. onclick:function () {
  14215. dialog.close( true );
  14216. }
  14217. },
  14218. {
  14219. className:'edui-cancelbutton',
  14220. label:editor.getLang( "cancel" ),
  14221. onclick:function () {
  14222. dialog.close( false );
  14223. }
  14224. }
  14225. ]
  14226. } : {} ) );
  14227. editor.ui._dialogs[cmd + "Dialog"] = dialog;
  14228. }
  14229. var ui = new editorui.Button( {
  14230. className:'edui-for-' + cmd,
  14231. title:title,
  14232. onclick:function () {
  14233. if ( dialog ) {
  14234. switch ( cmd ) {
  14235. case "wordimage":
  14236. editor.execCommand( "wordimage", "word_img" );
  14237. if ( editor.word_img ) {
  14238. dialog.render();
  14239. dialog.open();
  14240. }
  14241. break;
  14242. case "scrawl":
  14243. if ( editor.queryCommandState( "scrawl" ) != -1 ) {
  14244. dialog.render();
  14245. dialog.open();
  14246. }
  14247. break;
  14248. default:
  14249. dialog.render();
  14250. dialog.open();
  14251. }
  14252. }
  14253. },
  14254. disabled:cmd == 'scrawl' && editor.queryCommandState( "scrawl" ) == -1
  14255. } );
  14256. editor.addListener( 'selectionchange', function () {
  14257. //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
  14258. var unNeedCheckState = {'edittd':1, 'edittable':1};
  14259. if ( cmd in unNeedCheckState )return;
  14260. var state = editor.queryCommandState( cmd );
  14261. ui.setDisabled( state == -1 );
  14262. ui.setChecked( state );
  14263. } );
  14264. return ui;
  14265. };
  14266. })( ci.toLowerCase() )
  14267. }
  14268. })( p, dialogBtns[p] )
  14269. }
  14270. editorui.snapscreen = function ( editor, iframeUrl, title ) {
  14271. title = editor.options.labelMap['snapscreen'] || editor.getLang( "labelMap.snapscreen" ) || '';
  14272. var ui = new editorui.Button( {
  14273. className:'edui-for-snapscreen',
  14274. title:title,
  14275. onclick:function () {
  14276. editor.execCommand( "snapscreen" );
  14277. },
  14278. disabled:!browser.ie
  14279. } );
  14280. if ( browser.ie ) {
  14281. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})["snapscreen"] || iframeUrlMap["snapscreen"];
  14282. if ( iframeUrl ) {
  14283. var dialog = new editorui.Dialog( {
  14284. iframeUrl:editor.ui.mapUrl( iframeUrl ),
  14285. editor:editor,
  14286. className:'edui-for-snapscreen',
  14287. title:title,
  14288. buttons:[
  14289. {
  14290. className:'edui-okbutton',
  14291. label:editor.getLang( "ok" ),
  14292. onclick:function () {
  14293. dialog.close( true );
  14294. }
  14295. },
  14296. {
  14297. className:'edui-cancelbutton',
  14298. label:editor.getLang( "cancel" ),
  14299. onclick:function () {
  14300. dialog.close( false );
  14301. }
  14302. }
  14303. ]
  14304. } );
  14305. dialog.render();
  14306. editor.ui._dialogs["snapscreenDialog"] = dialog;
  14307. }
  14308. }
  14309. editor.addListener( 'selectionchange', function () {
  14310. ui.setDisabled( editor.queryCommandState( 'snapscreen' ) == -1 );
  14311. } );
  14312. return ui;
  14313. };
  14314. editorui.fontfamily = function ( editor, list, title ) {
  14315. list = editor.options['fontfamily'] || [];
  14316. title = editor.options.labelMap['fontfamily'] ||editor.getLang("labelMap.fontfamily")||'';
  14317. for ( var i = 0, ci, items = []; ci = list[i]; i++ ) {
  14318. var langLabel = editor.getLang( 'fontfamily' )[ci.name]||"";
  14319. (function ( key, val ) {
  14320. items.push( {
  14321. label:key,
  14322. value:val,
  14323. renderLabelHtml:function () {
  14324. return '<div class="edui-label %%-label" style="font-family:' +
  14325. utils.unhtml( this.value ) + '">' + (this.label || '') + '</div>';
  14326. }
  14327. } );
  14328. })( ci.label || langLabel, ci.val )
  14329. }
  14330. var ui = new editorui.Combox( {
  14331. editor:editor,
  14332. items:items,
  14333. onselect:function ( t, index ) {
  14334. editor.execCommand( 'FontFamily', this.items[index].value );
  14335. },
  14336. onbuttonclick:function () {
  14337. this.showPopup();
  14338. },
  14339. title:title,
  14340. initValue:title,
  14341. className:'edui-for-fontfamily',
  14342. indexByValue:function ( value ) {
  14343. if ( value ) {
  14344. for ( var i = 0, ci; ci = this.items[i]; i++ ) {
  14345. if ( ci.value.indexOf( value ) != -1 )
  14346. return i;
  14347. }
  14348. }
  14349. return -1;
  14350. }
  14351. } );
  14352. editor.addListener( 'selectionchange', function ( type, causeByUi, uiReady ) {
  14353. if ( !uiReady ) {
  14354. var state = editor.queryCommandState( 'FontFamily' );
  14355. if ( state == -1 ) {
  14356. ui.setDisabled( true );
  14357. } else {
  14358. ui.setDisabled( false );
  14359. var value = editor.queryCommandValue( 'FontFamily' );
  14360. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  14361. value && (value = value.replace( /['"]/g, '' ).split( ',' )[0]);
  14362. ui.setValue( value );
  14363. }
  14364. }
  14365. } );
  14366. return ui;
  14367. };
  14368. editorui.fontsize = function ( editor, list, title ) {
  14369. title = editor.options.labelMap['fontsize'] || editor.getLang( "labelMap.fontsize" ) || '';
  14370. list = list || editor.options['fontsize'] || [];
  14371. var items = [];
  14372. for ( var i = 0; i < list.length; i++ ) {
  14373. var size = list[i] + 'px';
  14374. items.push( {
  14375. label:size,
  14376. value:size,
  14377. renderLabelHtml:function () {
  14378. return '<div class="edui-label %%-label" style="line-height:1;font-size:' +
  14379. this.value + '">' + (this.label || '') + '</div>';
  14380. }
  14381. } );
  14382. }
  14383. var ui = new editorui.Combox( {
  14384. editor:editor,
  14385. items:items,
  14386. title:title,
  14387. initValue:title,
  14388. onselect:function ( t, index ) {
  14389. editor.execCommand( 'FontSize', this.items[index].value );
  14390. },
  14391. onbuttonclick:function () {
  14392. this.showPopup();
  14393. },
  14394. className:'edui-for-fontsize'
  14395. } );
  14396. editor.addListener( 'selectionchange', function ( type, causeByUi, uiReady ) {
  14397. if ( !uiReady ) {
  14398. var state = editor.queryCommandState( 'FontSize' );
  14399. if ( state == -1 ) {
  14400. ui.setDisabled( true );
  14401. } else {
  14402. ui.setDisabled( false );
  14403. ui.setValue( editor.queryCommandValue( 'FontSize' ) );
  14404. }
  14405. }
  14406. } );
  14407. return ui;
  14408. };
  14409. editorui.paragraph = function ( editor, list, title ) {
  14410. title = editor.options.labelMap['paragraph'] || editor.getLang( "labelMap.paragraph" ) || '';
  14411. list = editor.options['paragraph'] || [];
  14412. var items = [];
  14413. for ( var i in list ) {
  14414. items.push( {
  14415. value:i,
  14416. label:list[i] || editor.getLang( "paragraph" )[i],
  14417. renderLabelHtml:function () {
  14418. return '<div class="edui-label %%-label"><span class="edui-for-' + this.value + '">' + (this.label || '') + '</span></div>';
  14419. }
  14420. } )
  14421. }
  14422. var ui = new editorui.Combox( {
  14423. editor:editor,
  14424. items:items,
  14425. title:title,
  14426. initValue:title,
  14427. className:'edui-for-paragraph',
  14428. onselect:function ( t, index ) {
  14429. editor.execCommand( 'Paragraph', this.items[index].value );
  14430. },
  14431. onbuttonclick:function () {
  14432. this.showPopup();
  14433. }
  14434. } );
  14435. editor.addListener( 'selectionchange', function ( type, causeByUi, uiReady ) {
  14436. if ( !uiReady ) {
  14437. var state = editor.queryCommandState( 'Paragraph' );
  14438. if ( state == -1 ) {
  14439. ui.setDisabled( true );
  14440. } else {
  14441. ui.setDisabled( false );
  14442. var value = editor.queryCommandValue( 'Paragraph' );
  14443. var index = ui.indexByValue( value );
  14444. if ( index != -1 ) {
  14445. ui.setValue( value );
  14446. } else {
  14447. ui.setValue( ui.initValue );
  14448. }
  14449. }
  14450. }
  14451. } );
  14452. return ui;
  14453. };
  14454. //自定义标题
  14455. editorui.customstyle = function ( editor ) {
  14456. var list = editor.options['customstyle'] || [],
  14457. title = editor.options.labelMap['customstyle'] || editor.getLang( "labelMap.customstyle" ) || '';
  14458. if ( !list )return;
  14459. var langCs = editor.getLang( 'customstyle' );
  14460. for ( var i = 0, items = [], t; t = list[i++]; ) {
  14461. (function ( t ){
  14462. var ck ={};
  14463. ck.label = t.label? t.label:langCs[t.name];
  14464. ck.style = t.style;
  14465. ck.className = t.className;
  14466. ck.tag = t.tag;
  14467. items.push( {
  14468. label:ck.label,
  14469. value:ck,
  14470. renderLabelHtml:function () {
  14471. return '<div class="edui-label %%-label">' + '<' + ck.tag + ' ' + (ck.className ? ' class="' + ck.className + '"' : "")
  14472. + (ck.style ? ' style="' + ck.style + '"' : "") + '>' + ck.label + "<\/" + ck.tag + ">"
  14473. + '</div>';
  14474. }
  14475. } );
  14476. })( t );
  14477. }
  14478. var ui = new editorui.Combox( {
  14479. editor:editor,
  14480. items:items,
  14481. title:title,
  14482. initValue:title,
  14483. className:'edui-for-customstyle',
  14484. onselect:function ( t, index ) {
  14485. editor.execCommand( 'customstyle', this.items[index].value );
  14486. },
  14487. onbuttonclick:function () {
  14488. this.showPopup();
  14489. },
  14490. indexByValue:function ( value ) {
  14491. for ( var i = 0, ti; ti = this.items[i++]; ) {
  14492. if ( ti.label == value ) {
  14493. return i - 1
  14494. }
  14495. }
  14496. return -1;
  14497. }
  14498. } );
  14499. editor.addListener( 'selectionchange', function ( type, causeByUi, uiReady ) {
  14500. if ( !uiReady ) {
  14501. var state = editor.queryCommandState( 'customstyle' );
  14502. if ( state == -1 ) {
  14503. ui.setDisabled( true );
  14504. } else {
  14505. ui.setDisabled( false );
  14506. var value = editor.queryCommandValue( 'customstyle' );
  14507. var index = ui.indexByValue( value );
  14508. if ( index != -1 ) {
  14509. ui.setValue( value );
  14510. } else {
  14511. ui.setValue( ui.initValue );
  14512. }
  14513. }
  14514. }
  14515. } );
  14516. return ui;
  14517. };
  14518. editorui.inserttable = function ( editor, iframeUrl, title ) {
  14519. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})['inserttable'] || iframeUrlMap['inserttable'];
  14520. title = editor.options.labelMap['inserttable'] || editor.getLang( "labelMap.inserttable" ) || '';
  14521. if ( iframeUrl ) {
  14522. var dialog = new editorui.Dialog( {
  14523. iframeUrl:editor.ui.mapUrl( iframeUrl ),
  14524. editor:editor,
  14525. className:'edui-for-inserttable',
  14526. title:title,
  14527. buttons:[
  14528. {
  14529. className:'edui-okbutton',
  14530. label:editor.getLang( "ok" ),
  14531. onclick:function () {
  14532. dialog.close( true );
  14533. }
  14534. },
  14535. {
  14536. className:'edui-cancelbutton',
  14537. label:editor.getLang( "cancel" ),
  14538. onclick:function () {
  14539. dialog.close( false );
  14540. }
  14541. }
  14542. ]
  14543. } );
  14544. dialog.render();
  14545. editor.ui._dialogs['inserttableDialog'] = dialog;
  14546. }
  14547. var openDialog = function(){
  14548. if(dialog){
  14549. //打开后再关闭再打开是为了解决fieldset文字错位问题
  14550. if(browser.webkit){
  14551. dialog.open();
  14552. dialog.close();
  14553. }
  14554. dialog.open();
  14555. }
  14556. };
  14557. var ui = new editorui.TableButton( {
  14558. editor:editor,
  14559. title:title,
  14560. className:'edui-for-inserttable',
  14561. onpicktable:function ( t, numCols, numRows ) {
  14562. editor.execCommand( 'InsertTable', {numRows:numRows, numCols:numCols, border:1} );
  14563. },
  14564. onmore:openDialog,
  14565. onbuttonclick:openDialog
  14566. } );
  14567. editor.addListener( 'selectionchange', function () {
  14568. ui.setDisabled( editor.queryCommandState( 'inserttable' ) == -1 );
  14569. } );
  14570. return ui;
  14571. };
  14572. editorui.lineheight = function ( editor ) {
  14573. var val = editor.options.lineheight;
  14574. for ( var i = 0, ci, items = []; ci = val[i++]; ) {
  14575. items.push( {
  14576. //todo:写死了
  14577. label:ci,
  14578. value:ci,
  14579. onclick:function () {
  14580. editor.execCommand( "lineheight", this.value );
  14581. }
  14582. } )
  14583. }
  14584. var ui = new editorui.MenuButton( {
  14585. editor:editor,
  14586. className:'edui-for-lineheight',
  14587. title:editor.options.labelMap['lineheight'] || editor.getLang( "labelMap.lineheight" ) || '',
  14588. items:items,
  14589. onbuttonclick:function () {
  14590. var value = editor.queryCommandValue( 'LineHeight' ) || this.value;
  14591. editor.execCommand( "LineHeight", value );
  14592. }
  14593. } );
  14594. editor.addListener( 'selectionchange', function () {
  14595. var state = editor.queryCommandState( 'LineHeight' );
  14596. if ( state == -1 ) {
  14597. ui.setDisabled( true );
  14598. } else {
  14599. ui.setDisabled( false );
  14600. var value = editor.queryCommandValue( 'LineHeight' );
  14601. value && ui.setValue( (value + '').replace( /cm/, '' ) );
  14602. ui.setChecked( state )
  14603. }
  14604. } );
  14605. return ui;
  14606. };
  14607. var rowspacings = ['top', 'bottom'];
  14608. for ( var r = 0, ri; ri = rowspacings[r++]; ) {
  14609. (function ( cmd ) {
  14610. editorui['rowspacing' + cmd] = function ( editor ) {
  14611. var val = editor.options['rowspacing' + cmd];
  14612. for ( var i = 0, ci, items = []; ci = val[i++]; ) {
  14613. items.push( {
  14614. label:ci,
  14615. value:ci,
  14616. onclick:function () {
  14617. editor.execCommand( "rowspacing", this.value, cmd );
  14618. }
  14619. } )
  14620. }
  14621. var ui = new editorui.MenuButton( {
  14622. editor:editor,
  14623. className:'edui-for-rowspacing' + cmd,
  14624. title:editor.options.labelMap['rowspacing' + cmd] || editor.getLang( "labelMap.rowspacing" + cmd ) || '',
  14625. items:items,
  14626. onbuttonclick:function () {
  14627. var value = editor.queryCommandValue( 'rowspacing', cmd ) || this.value;
  14628. editor.execCommand( "rowspacing", value, cmd );
  14629. }
  14630. } );
  14631. editor.addListener( 'selectionchange', function () {
  14632. var state = editor.queryCommandState( 'rowspacing', cmd );
  14633. if ( state == -1 ) {
  14634. ui.setDisabled( true );
  14635. } else {
  14636. ui.setDisabled( false );
  14637. var value = editor.queryCommandValue( 'rowspacing', cmd );
  14638. value && ui.setValue( (value + '').replace( /%/, '' ) );
  14639. ui.setChecked( state )
  14640. }
  14641. } );
  14642. return ui;
  14643. }
  14644. })( ri )
  14645. }
  14646. //有序,无序列表
  14647. var lists = ['insertorderedlist', 'insertunorderedlist'];
  14648. for ( var l = 0, cl; cl = lists[l++]; ) {
  14649. (function ( cmd ) {
  14650. editorui[cmd] = function ( editor ) {
  14651. var vals = editor.options[cmd],
  14652. _onMenuClick = function () {
  14653. editor.execCommand( cmd, this.value );
  14654. }, items = [];
  14655. for ( var i in vals ) {
  14656. items.push( {
  14657. label:vals[i] || editor.getLang()[cmd][i] || "",
  14658. value:i,
  14659. onclick:_onMenuClick
  14660. } )
  14661. }
  14662. var ui = new editorui.MenuButton( {
  14663. editor:editor,
  14664. className:'edui-for-' + cmd,
  14665. title:editor.getLang( "labelMap." + cmd ) || '',
  14666. 'items':items,
  14667. onbuttonclick:function () {
  14668. var value = editor.queryCommandValue( cmd ) || this.value;
  14669. editor.execCommand( cmd, value );
  14670. }
  14671. } );
  14672. editor.addListener( 'selectionchange', function () {
  14673. var state = editor.queryCommandState( cmd );
  14674. if ( state == -1 ) {
  14675. ui.setDisabled( true );
  14676. } else {
  14677. ui.setDisabled( false );
  14678. var value = editor.queryCommandValue( cmd );
  14679. ui.setValue( value );
  14680. ui.setChecked( state )
  14681. }
  14682. } );
  14683. return ui;
  14684. };
  14685. })( cl )
  14686. }
  14687. editorui.fullscreen = function ( editor, title ) {
  14688. title = editor.options.labelMap['fullscreen'] || editor.getLang( "labelMap.fullscreen" ) || '';
  14689. var ui = new editorui.Button( {
  14690. className:'edui-for-fullscreen',
  14691. title:title,
  14692. onclick:function () {
  14693. if ( editor.ui ) {
  14694. editor.ui.setFullScreen( !editor.ui.isFullScreen() );
  14695. }
  14696. this.setChecked( editor.ui.isFullScreen() );
  14697. }
  14698. } );
  14699. editor.addListener( 'selectionchange', function () {
  14700. var state = editor.queryCommandState( 'fullscreen' );
  14701. ui.setDisabled( state == -1 );
  14702. ui.setChecked( editor.ui.isFullScreen() );
  14703. } );
  14704. return ui;
  14705. };
  14706. // 表情
  14707. editorui.emotion = function ( editor, iframeUrl ) {
  14708. var ui = new editorui.MultiMenuPop( {
  14709. title:editor.options.labelMap['emotion'] || editor.getLang( "labelMap.emotion" ) || '',
  14710. editor:editor,
  14711. className:'edui-for-emotion',
  14712. iframeUrl:editor.ui.mapUrl( iframeUrl || (editor.options.iframeUrlMap || {})['emotion'] || iframeUrlMap['emotion'] )
  14713. } );
  14714. editor.addListener( 'selectionchange', function () {
  14715. ui.setDisabled( editor.queryCommandState( 'emotion' ) == -1 )
  14716. } );
  14717. return ui;
  14718. };
  14719. editorui.autotypeset = function ( editor ) {
  14720. var ui = new editorui.AutoTypeSetButton( {
  14721. editor:editor,
  14722. title:editor.options.labelMap['autotypeset'] || editor.getLang( "labelMap.autotypeset" ) || '',
  14723. className:'edui-for-autotypeset',
  14724. onbuttonclick:function () {
  14725. editor.execCommand( 'autotypeset' )
  14726. }
  14727. } );
  14728. editor.addListener( 'selectionchange', function () {
  14729. ui.setDisabled( editor.queryCommandState( 'autotypeset' ) == -1 );
  14730. } );
  14731. return ui;
  14732. };
  14733. })();
  14734. ///import core
  14735. ///commands 全屏
  14736. ///commandsName FullScreen
  14737. ///commandsTitle 全屏
  14738. (function () {
  14739. var utils = baidu.editor.utils,
  14740. uiUtils = baidu.editor.ui.uiUtils,
  14741. UIBase = baidu.editor.ui.UIBase,
  14742. domUtils = baidu.editor.dom.domUtils;
  14743. function EditorUI( options ) {
  14744. this.initOptions( options );
  14745. this.initEditorUI();
  14746. }
  14747. EditorUI.prototype = {
  14748. uiName:'editor',
  14749. initEditorUI:function () {
  14750. this.editor.ui = this;
  14751. this._dialogs = {};
  14752. this.initUIBase();
  14753. this._initToolbars();
  14754. var editor = this.editor,
  14755. me = this;
  14756. editor.addListener( 'ready', function () {
  14757. //提供getDialog方法
  14758. editor.getDialog = function(name){
  14759. return editor.ui._dialogs[name+"Dialog"];
  14760. };
  14761. domUtils.on( editor.window, 'scroll', function () {
  14762. baidu.editor.ui.Popup.postHide();
  14763. } );
  14764. //display bottom-bar label based on config
  14765. if ( editor.options.elementPathEnabled ) {
  14766. editor.ui.getDom( 'elementpath' ).innerHTML = '<div class="edui-editor-breadcrumb">'+editor.getLang("elementPathTip")+':</div>';
  14767. }
  14768. if ( editor.options.wordCount ) {
  14769. editor.ui.getDom( 'wordcount' ).innerHTML = editor.getLang("wordCountTip");
  14770. //为wordcount捕获中文输入法的空格
  14771. editor.addListener( 'keyup', function ( type, evt ) {
  14772. var keyCode = evt.keyCode || evt.which;
  14773. if ( keyCode == 32 ) {
  14774. me._wordCount();
  14775. }
  14776. } );
  14777. }
  14778. if ( !editor.options.elementPathEnabled && !editor.options.wordCount ) {
  14779. editor.ui.getDom( 'elementpath' ).style.display = "none";
  14780. editor.ui.getDom( 'wordcount' ).style.display = "none";
  14781. }
  14782. if ( !editor.selection.isFocus() )return;
  14783. editor.fireEvent( 'selectionchange', false, true );
  14784. } );
  14785. editor.addListener( 'mousedown', function ( t, evt ) {
  14786. var el = evt.target || evt.srcElement;
  14787. baidu.editor.ui.Popup.postHide( el );
  14788. } );
  14789. editor.addListener( 'contextmenu', function ( t, evt ) {
  14790. baidu.editor.ui.Popup.postHide();
  14791. } );
  14792. editor.addListener( 'selectionchange', function () {
  14793. //if(!editor.selection.isFocus())return;
  14794. if ( editor.options.elementPathEnabled ) {
  14795. me[(editor.queryCommandState( 'elementpath' ) == -1 ? 'dis' : 'en') + 'ableElementPath']()
  14796. }
  14797. if ( editor.options.wordCount ) {
  14798. me[(editor.queryCommandState( 'wordcount' ) == -1 ? 'dis' : 'en') + 'ableWordCount']()
  14799. }
  14800. } );
  14801. var popup = new baidu.editor.ui.Popup( {
  14802. editor:editor,
  14803. content:'',
  14804. className:'edui-bubble',
  14805. _onEditButtonClick:function () {
  14806. this.hide();
  14807. editor.ui._dialogs.linkDialog.open();
  14808. },
  14809. _onImgEditButtonClick:function ( name ) {
  14810. this.hide();
  14811. editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
  14812. },
  14813. _onImgSetFloat:function ( value ) {
  14814. this.hide();
  14815. editor.execCommand( "imagefloat", value );
  14816. },
  14817. _setIframeAlign:function ( value ) {
  14818. var frame = popup.anchorEl;
  14819. var newFrame = frame.cloneNode( true );
  14820. switch ( value ) {
  14821. case -2:
  14822. newFrame.setAttribute( "align", "" );
  14823. break;
  14824. case -1:
  14825. newFrame.setAttribute( "align", "left" );
  14826. break;
  14827. case 1:
  14828. newFrame.setAttribute( "align", "right" );
  14829. break;
  14830. case 2:
  14831. newFrame.setAttribute( "align", "middle" );
  14832. break;
  14833. }
  14834. frame.parentNode.insertBefore( newFrame, frame );
  14835. domUtils.remove( frame );
  14836. popup.anchorEl = newFrame;
  14837. popup.showAnchor( popup.anchorEl );
  14838. },
  14839. _updateIframe:function () {
  14840. editor._iframe = popup.anchorEl;
  14841. editor.ui._dialogs.insertframeDialog.open();
  14842. popup.hide();
  14843. },
  14844. _onRemoveButtonClick:function ( cmdName ) {
  14845. editor.execCommand( cmdName );
  14846. this.hide();
  14847. },
  14848. queryAutoHide:function ( el ) {
  14849. if ( el && el.ownerDocument == editor.document ) {
  14850. if ( el.tagName.toLowerCase() == 'img' || domUtils.findParentByTagName( el, 'a', true ) ) {
  14851. return el !== popup.anchorEl;
  14852. }
  14853. }
  14854. return baidu.editor.ui.Popup.prototype.queryAutoHide.call( this, el );
  14855. }
  14856. } );
  14857. popup.render();
  14858. if ( editor.options.imagePopup ) {
  14859. editor.addListener( 'mouseover', function ( t, evt ) {
  14860. evt = evt || window.event;
  14861. var el = evt.target || evt.srcElement;
  14862. if ( editor.ui._dialogs.insertframeDialog && /iframe/ig.test( el.tagName ) ) {
  14863. var html = popup.formatHtml(
  14864. '<nobr>'+editor.getLang("property")+': <span onclick=$$._setIframeAlign(-2) class="edui-clickable">'+editor.getLang("default")+'</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(-1) class="edui-clickable">'+editor.getLang("justifyleft")+'</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(1) class="edui-clickable">'+editor.getLang("justifyright")+'</span>&nbsp;&nbsp;' +
  14865. '<span onclick=$$._setIframeAlign(2) class="edui-clickable">'+editor.getLang("justifycenter")+'</span>' +
  14866. ' <span onclick="$$._updateIframe( this);" class="edui-clickable">'+editor.getLang("modify")+'</span></nobr>' );
  14867. if ( html ) {
  14868. popup.getDom( 'content' ).innerHTML = html;
  14869. popup.anchorEl = el;
  14870. popup.showAnchor( popup.anchorEl );
  14871. } else {
  14872. popup.hide();
  14873. }
  14874. }
  14875. } );
  14876. editor.addListener( 'selectionchange', function ( t, causeByUi ) {
  14877. if ( !causeByUi ) return;
  14878. var html = '',
  14879. img = editor.selection.getRange().getClosedNode(),
  14880. dialogs = editor.ui._dialogs;
  14881. if ( img && img.tagName == 'IMG' ) {
  14882. var dialogName = 'insertimageDialog';
  14883. if ( img.className.indexOf( "edui-faked-video" ) != -1 ) {
  14884. dialogName = "insertvideoDialog"
  14885. }
  14886. if ( img.className.indexOf( "edui-faked-webapp" ) != -1 ) {
  14887. dialogName = "webappDialog"
  14888. }
  14889. if ( img.src.indexOf( "http://api.map.baidu.com" ) != -1 ) {
  14890. dialogName = "mapDialog"
  14891. }
  14892. if ( img.src.indexOf( "http://maps.google.com/maps/api/staticmap" ) != -1 ) {
  14893. dialogName = "gmapDialog"
  14894. }
  14895. if ( img.getAttribute( "anchorname" ) ) {
  14896. dialogName = "anchorDialog";
  14897. html = popup.formatHtml(
  14898. '<nobr>'+editor.getLang("property")+': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">'+editor.getLang("modify")+'</span>&nbsp;&nbsp;' +
  14899. '<span onclick=$$._onRemoveButtonClick(\'anchor\') class="edui-clickable">'+editor.getLang("delete")+'</span></nobr>' );
  14900. }
  14901. if ( img.getAttribute( "word_img" ) ) {
  14902. //todo 放到dialog去做查询
  14903. editor.word_img = [img.getAttribute( "word_img" )];
  14904. dialogName = "wordimageDialog"
  14905. }
  14906. if ( !dialogs[dialogName] ) {
  14907. return;
  14908. }
  14909. !html && (html = popup.formatHtml(
  14910. '<nobr>'+editor.getLang("property")+': <span onclick=$$._onImgSetFloat("none") class="edui-clickable">'+editor.getLang("default")+'</span>&nbsp;&nbsp;' +
  14911. '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">'+editor.getLang("justifyleft")+'</span>&nbsp;&nbsp;' +
  14912. '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">'+editor.getLang("justifyright")+'</span>&nbsp;&nbsp;' +
  14913. '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">'+editor.getLang("justifycenter")+'</span>&nbsp;&nbsp;' +
  14914. '<span onclick="$$._onImgEditButtonClick(\'' + dialogName + '\');" class="edui-clickable">'+editor.getLang("modify")+'</span></nobr>' ))
  14915. }
  14916. if ( editor.ui._dialogs.linkDialog ) {
  14917. var link = domUtils.findParentByTagName( editor.selection.getStart(), "a", true );
  14918. var url;
  14919. if ( link && (url = (link.getAttribute( 'data_ue_src' ) || link.getAttribute( 'href', 2 ))) ) {
  14920. var txt = url;
  14921. if ( url.length > 30 ) {
  14922. txt = url.substring( 0, 20 ) + "...";
  14923. }
  14924. if ( html ) {
  14925. html += '<div style="height:5px;"></div>'
  14926. }
  14927. html += popup.formatHtml(
  14928. '<nobr>'+editor.getLang("anthorMsg")+': <a target="_blank" href="' + url + '" title="' + url + '" >' + txt + '</a>' +
  14929. ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">'+editor.getLang("modify")+'</span>' +
  14930. ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> '+editor.getLang("clear")+'</span></nobr>' );
  14931. popup.showAnchor( link );
  14932. }
  14933. }
  14934. if ( html ) {
  14935. popup.getDom( 'content' ).innerHTML = html;
  14936. popup.anchorEl = img || link;
  14937. popup.showAnchor( popup.anchorEl );
  14938. } else {
  14939. popup.hide();
  14940. }
  14941. } );
  14942. }
  14943. },
  14944. _initToolbars:function () {
  14945. var editor = this.editor;
  14946. var toolbars = this.toolbars || [];
  14947. var toolbarUis = [];
  14948. for ( var i = 0; i < toolbars.length; i++ ) {
  14949. var toolbar = toolbars[i];
  14950. var toolbarUi = new baidu.editor.ui.Toolbar();
  14951. for ( var j = 0; j < toolbar.length; j++ ) {
  14952. var toolbarItem = toolbar[j];
  14953. var toolbarItemUi = null;
  14954. if ( typeof toolbarItem == 'string' ) {
  14955. toolbarItem = toolbarItem.toLowerCase();
  14956. if ( toolbarItem == '|' ) {
  14957. toolbarItem = 'Separator';
  14958. }
  14959. if ( baidu.editor.ui[toolbarItem] ) {
  14960. toolbarItemUi = new baidu.editor.ui[toolbarItem]( editor );
  14961. }
  14962. //fullscreen这里单独处理一下,放到首行去
  14963. if ( toolbarItem == 'fullscreen' ) {
  14964. if ( toolbarUis && toolbarUis[0] ) {
  14965. toolbarUis[0].items.splice( 0, 0, toolbarItemUi );
  14966. } else {
  14967. toolbarItemUi && toolbarUi.items.splice( 0, 0, toolbarItemUi );
  14968. }
  14969. continue;
  14970. }
  14971. } else {
  14972. toolbarItemUi = toolbarItem;
  14973. }
  14974. if ( toolbarItemUi ) {
  14975. toolbarUi.add( toolbarItemUi );
  14976. }
  14977. }
  14978. toolbarUis[i] = toolbarUi;
  14979. }
  14980. this.toolbars = toolbarUis;
  14981. },
  14982. getHtmlTpl:function () {
  14983. return '<div id="##" class="%%">' +
  14984. '<div id="##_toolbarbox" class="%%-toolbarbox">' +
  14985. (this.toolbars.length ?
  14986. '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
  14987. this.renderToolbarBoxHtml() +
  14988. '</div></div>' : '') +
  14989. '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
  14990. '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">'+this.editor.getLang("clickToUpload")+'</div>' +
  14991. '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
  14992. '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
  14993. '<div style="height:0;overflow:hidden;clear:both;"></div>' +
  14994. '</div>' +
  14995. '</div>' +
  14996. '<div id="##_iframeholder" class="%%-iframeholder"></div>' +
  14997. //modify wdcount by matao
  14998. '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
  14999. '<td id="##_elementpath" class="%%-bottombar"></td>' +
  15000. '<td id="##_wordcount" class="%%-wordcount"></td>' +
  15001. '</tr></table></div>' +
  15002. '</div>';
  15003. },
  15004. showWordImageDialog:function () {
  15005. this.editor.execCommand( "wordimage", "word_img" );
  15006. this._dialogs['wordimageDialog'].open();
  15007. },
  15008. renderToolbarBoxHtml:function () {
  15009. var buff = [];
  15010. for ( var i = 0; i < this.toolbars.length; i++ ) {
  15011. buff.push( this.toolbars[i].renderHtml() );
  15012. }
  15013. return buff.join( '' );
  15014. },
  15015. setFullScreen:function ( fullscreen ) {
  15016. if ( this._fullscreen != fullscreen ) {
  15017. this._fullscreen = fullscreen;
  15018. this.editor.fireEvent( 'beforefullscreenchange', fullscreen );
  15019. var editor = this.editor;
  15020. if ( baidu.editor.browser.gecko ) {
  15021. var bk = editor.selection.getRange().createBookmark();
  15022. }
  15023. if ( fullscreen ) {
  15024. this._bakHtmlOverflow = document.documentElement.style.overflow;
  15025. this._bakBodyOverflow = document.body.style.overflow;
  15026. this._bakAutoHeight = this.editor.autoHeightEnabled;
  15027. this._bakScrollTop = Math.max( document.documentElement.scrollTop, document.body.scrollTop );
  15028. if ( this._bakAutoHeight ) {
  15029. //当全屏时不能执行自动长高
  15030. editor.autoHeightEnabled = false;
  15031. this.editor.disableAutoHeight();
  15032. }
  15033. document.documentElement.style.overflow = 'hidden';
  15034. document.body.style.overflow = 'hidden';
  15035. this._bakCssText = this.getDom().style.cssText;
  15036. this._bakCssText1 = this.getDom( 'iframeholder' ).style.cssText;
  15037. this._updateFullScreen();
  15038. } else {
  15039. this.getDom().style.cssText = this._bakCssText;
  15040. this.getDom( 'iframeholder' ).style.cssText = this._bakCssText1;
  15041. if ( this._bakAutoHeight ) {
  15042. editor.autoHeightEnabled = true;
  15043. this.editor.enableAutoHeight();
  15044. }
  15045. document.documentElement.style.overflow = this._bakHtmlOverflow;
  15046. document.body.style.overflow = this._bakBodyOverflow;
  15047. window.scrollTo( 0, this._bakScrollTop );
  15048. }
  15049. if ( baidu.editor.browser.gecko ) {
  15050. var input = document.createElement( 'input' );
  15051. document.body.appendChild( input );
  15052. editor.body.contentEditable = false;
  15053. setTimeout( function () {
  15054. input.focus();
  15055. setTimeout( function () {
  15056. editor.body.contentEditable = true;
  15057. editor.selection.getRange().moveToBookmark( bk ).select( true );
  15058. baidu.editor.dom.domUtils.remove( input );
  15059. fullscreen && window.scroll( 0, 0 );
  15060. } )
  15061. } )
  15062. }
  15063. this.editor.fireEvent( 'fullscreenchanged', fullscreen );
  15064. this.triggerLayout();
  15065. }
  15066. },
  15067. _wordCount:function () {
  15068. var wdcount = this.getDom( 'wordcount' );
  15069. if ( !this.editor.options.wordCount ) {
  15070. wdcount.style.display = "none";
  15071. return;
  15072. }
  15073. wdcount.innerHTML = this.editor.queryCommandValue( "wordcount" );
  15074. },
  15075. disableWordCount:function () {
  15076. var w = this.getDom( 'wordcount' );
  15077. w.innerHTML = '';
  15078. w.style.display = 'none';
  15079. this.wordcount = false;
  15080. },
  15081. enableWordCount:function () {
  15082. var w = this.getDom( 'wordcount' );
  15083. w.style.display = '';
  15084. this.wordcount = true;
  15085. this._wordCount();
  15086. },
  15087. _updateFullScreen:function () {
  15088. if ( this._fullscreen ) {
  15089. var vpRect = uiUtils.getViewportRect();
  15090. this.getDom().style.cssText = 'border:0;position:absolute;left:0;top:'+(this.editor.options.topOffset||0)+'px;width:' + vpRect.width + 'px;height:' + vpRect.height + 'px;z-index:' + (this.getDom().style.zIndex * 1 + 100);
  15091. uiUtils.setViewportOffset( this.getDom(), { left:0, top:this.editor.options.topOffset||0 } );
  15092. this.editor.setHeight( vpRect.height - this.getDom( 'toolbarbox' ).offsetHeight - this.getDom( 'bottombar' ).offsetHeight - (this.editor.options.topOffset||0) );
  15093. }
  15094. },
  15095. _updateElementPath:function () {
  15096. var bottom = this.getDom( 'elementpath' ), list;
  15097. if ( this.elementPathEnabled && (list = this.editor.queryCommandValue( 'elementpath' )) ) {
  15098. var buff = [];
  15099. for ( var i = 0, ci; ci = list[i]; i++ ) {
  15100. buff[i] = this.formatHtml( '<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' + i + '&quot;);">' + ci + '</span>' );
  15101. }
  15102. bottom.innerHTML = '<div class="edui-editor-breadcrumb" onmousedown="return false;">'+this.editor.getLang("elementPathTip")+': ' + buff.join( ' &gt; ' ) + '</div>';
  15103. } else {
  15104. bottom.style.display = 'none'
  15105. }
  15106. },
  15107. disableElementPath:function () {
  15108. var bottom = this.getDom( 'elementpath' );
  15109. bottom.innerHTML = '';
  15110. bottom.style.display = 'none';
  15111. this.elementPathEnabled = false;
  15112. },
  15113. enableElementPath:function () {
  15114. var bottom = this.getDom( 'elementpath' );
  15115. bottom.style.display = '';
  15116. this.elementPathEnabled = true;
  15117. this._updateElementPath();
  15118. },
  15119. isFullScreen:function () {
  15120. return this._fullscreen;
  15121. },
  15122. postRender:function () {
  15123. UIBase.prototype.postRender.call( this );
  15124. for ( var i = 0; i < this.toolbars.length; i++ ) {
  15125. this.toolbars[i].postRender();
  15126. }
  15127. var me = this;
  15128. var timerId,
  15129. domUtils = baidu.editor.dom.domUtils,
  15130. updateFullScreenTime = function () {
  15131. clearTimeout( timerId );
  15132. timerId = setTimeout( function () {
  15133. me._updateFullScreen();
  15134. } );
  15135. };
  15136. domUtils.on( window, 'resize', updateFullScreenTime );
  15137. me.addListener( 'destroy', function () {
  15138. domUtils.un( window, 'resize', updateFullScreenTime );
  15139. clearTimeout( timerId );
  15140. } )
  15141. },
  15142. showToolbarMsg:function ( msg, flag ) {
  15143. this.getDom( 'toolbarmsg_label' ).innerHTML = msg;
  15144. this.getDom( 'toolbarmsg' ).style.display = '';
  15145. //
  15146. if ( !flag ) {
  15147. var w = this.getDom( 'upload_dialog' );
  15148. w.style.display = 'none';
  15149. }
  15150. },
  15151. hideToolbarMsg:function () {
  15152. this.getDom( 'toolbarmsg' ).style.display = 'none';
  15153. },
  15154. mapUrl:function ( url ) {
  15155. return url ? url.replace( '~/', this.editor.options.UEDITOR_HOME_URL || '' ) : ''
  15156. },
  15157. triggerLayout:function () {
  15158. var dom = this.getDom();
  15159. if ( dom.style.zoom == '1' ) {
  15160. dom.style.zoom = '100%';
  15161. } else {
  15162. dom.style.zoom = '1';
  15163. }
  15164. }
  15165. };
  15166. utils.inherits( EditorUI, baidu.editor.ui.UIBase );
  15167. baidu.editor.ui.Editor = function ( options ) {
  15168. var editor = new baidu.editor.Editor( options );
  15169. editor.options.editor = editor;
  15170. var oldRender = editor.render;
  15171. editor.render = function ( holder ) {
  15172. utils.domReady( function () {
  15173. editor.langIsReady ? renderUI() : editor.addListener( "langReady", renderUI );
  15174. function renderUI() {
  15175. editor.setOpt({
  15176. labelMap:editor.options.labelMap||UE.I18N[editor.options.lang].labelMap
  15177. });
  15178. new EditorUI( editor.options );
  15179. if ( holder ) {
  15180. if ( holder.constructor === String ) {
  15181. holder = document.getElementById( holder );
  15182. }
  15183. holder && holder.getAttribute( 'name' ) && ( editor.options.textarea = holder.getAttribute( 'name' ));
  15184. if ( holder && /script|textarea/ig.test( holder.tagName ) ) {
  15185. var newDiv = document.createElement( 'div' );
  15186. holder.parentNode.insertBefore( newDiv, holder );
  15187. var cont = holder.value || holder.innerHTML;
  15188. editor.options.initialContent = /^[\t\r\n ]*$/.test( cont ) ? editor.options.initialContent :
  15189. cont.replace( />[\n\r\t]+([ ]{4})+/g, '>' )
  15190. .replace( /[\n\r\t]+([ ]{4})+</g, '<' )
  15191. .replace( />[\n\r\t]+</g, '><' );
  15192. holder.id && (newDiv.id = holder.id);
  15193. holder.className && (newDiv.className = holder.className);
  15194. holder.style.cssText && (newDiv.style.cssText = holder.style.cssText);
  15195. if ( /textarea/i.test( holder.tagName ) ) {
  15196. editor.textarea = holder;
  15197. editor.textarea.style.display = 'none'
  15198. } else {
  15199. holder.parentNode.removeChild( holder )
  15200. }
  15201. holder = newDiv;
  15202. holder.innerHTML = '';
  15203. }
  15204. }
  15205. editor.ui.render( holder );
  15206. var iframeholder = editor.ui.getDom( 'iframeholder' );
  15207. //给实例添加一个编辑器的容器引用
  15208. editor.container = editor.ui.getDom();
  15209. editor.container.style.zIndex = editor.options.zIndex;
  15210. oldRender.call( editor, iframeholder );
  15211. }
  15212. } )
  15213. };
  15214. return editor;
  15215. };
  15216. })();
  15217. ///import core
  15218. ///import uicore
  15219. ///commands 表情
  15220. (function(){
  15221. var utils = baidu.editor.utils,
  15222. Popup = baidu.editor.ui.Popup,
  15223. SplitButton = baidu.editor.ui.SplitButton,
  15224. MultiMenuPop = baidu.editor.ui.MultiMenuPop = function(options){
  15225. this.initOptions(options);
  15226. this.initMultiMenu();
  15227. };
  15228. MultiMenuPop.prototype = {
  15229. initMultiMenu: function (){
  15230. var me = this;
  15231. this.popup = new Popup({
  15232. content: '',
  15233. editor : me.editor,
  15234. iframe_rendered: false,
  15235. onshow: function (){
  15236. if (!this.iframe_rendered) {
  15237. this.iframe_rendered = true;
  15238. this.getDom('content').innerHTML = '<iframe id="'+me.id+'_iframe" src="'+ me.iframeUrl +'" frameborder="0"></iframe>';
  15239. me.editor.container.style.zIndex && (this.getDom().style.zIndex = me.editor.container.style.zIndex * 1 + 1);
  15240. }
  15241. }
  15242. // canSideUp:false,
  15243. // canSideLeft:false
  15244. });
  15245. this.onbuttonclick = function(){
  15246. this.showPopup();
  15247. };
  15248. this.initSplitButton();
  15249. }
  15250. };
  15251. utils.inherits(MultiMenuPop, SplitButton);
  15252. })();
  15253. })();