ueditor.all.js 921 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114
  1. (function () {
  2. UEDITOR_CONFIG = window.UEDITOR_CONFIG || {};
  3. var baidu = window.baidu || {};
  4. window.baidu = baidu;
  5. window.UE = baidu.editor = {};
  6. UE.plugins = {};
  7. UE.commands = {};
  8. UE.instants = {};
  9. UE.I18N = {};
  10. UE.version = "1.2.6.1";
  11. var dom = UE.dom = {};
  12. /**
  13. * @file
  14. * @name UE.browser
  15. * @short Browser
  16. * @desc UEditor中采用的浏览器判断模块
  17. */
  18. var browser = UE.browser = function () {
  19. var agent = navigator.userAgent.toLowerCase(),
  20. opera = window.opera,
  21. browser = {
  22. /**
  23. * 检测浏览器是否为IE
  24. * @name ie
  25. * @grammar UE.browser.ie => true|false
  26. */
  27. ie: !!window.ActiveXObject,
  28. /**
  29. * 检测浏览器是否为Opera
  30. * @name opera
  31. * @grammar UE.browser.opera => true|false
  32. */
  33. opera: ( !!opera && opera.version ),
  34. /**
  35. * 检测浏览器是否为webkit内核
  36. * @name webkit
  37. * @grammar UE.browser.webkit => true|false
  38. */
  39. webkit: ( agent.indexOf(' applewebkit/') > -1 ),
  40. /**
  41. * 检测浏览器是否为mac系统下的浏览器
  42. * @name mac
  43. * @grammar UE.browser.mac => true|false
  44. */
  45. mac: ( agent.indexOf('macintosh') > -1 ),
  46. /**
  47. * 检测浏览器是否处于怪异模式
  48. * @name quirks
  49. * @grammar UE.browser.quirks => true|false
  50. */
  51. quirks: ( document.compatMode == 'BackCompat' )
  52. };
  53. /**
  54. * 检测浏览器是否处为gecko内核
  55. * @name gecko
  56. * @grammar UE.browser.gecko => true|false
  57. */
  58. browser.gecko = ( navigator.product == 'Gecko' && !browser.webkit && !browser.opera );
  59. var version = 0;
  60. // Internet Explorer 6.0+
  61. if (browser.ie) {
  62. version = parseFloat(agent.match(/msie (\d+)/)[1]);
  63. /**
  64. * 检测浏览器是否为 IE9 模式
  65. * @name ie9Compat
  66. * @grammar UE.browser.ie9Compat => true|false
  67. */
  68. browser.ie9Compat = document.documentMode == 9;
  69. /**
  70. * 检测浏览器是否为 IE8 浏览器
  71. * @name ie8
  72. * @grammar UE.browser.ie8 => true|false
  73. */
  74. browser.ie8 = !!document.documentMode;
  75. /**
  76. * 检测浏览器是否为 IE8 模式
  77. * @name ie8Compat
  78. * @grammar UE.browser.ie8Compat => true|false
  79. */
  80. browser.ie8Compat = document.documentMode == 8;
  81. /**
  82. * 检测浏览器是否运行在 兼容IE7模式
  83. * @name ie7Compat
  84. * @grammar UE.browser.ie7Compat => true|false
  85. */
  86. browser.ie7Compat = ( ( version == 7 && !document.documentMode )
  87. || document.documentMode == 7 );
  88. /**
  89. * 检测浏览器是否IE6模式或怪异模式
  90. * @name ie6Compat
  91. * @grammar UE.browser.ie6Compat => true|false
  92. */
  93. browser.ie6Compat = ( version < 7 || browser.quirks );
  94. }
  95. // Gecko.
  96. if (browser.gecko) {
  97. var geckoRelease = agent.match(/rv:([\d\.]+)/);
  98. if (geckoRelease) {
  99. geckoRelease = geckoRelease[1].split('.');
  100. version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1;
  101. }
  102. }
  103. /**
  104. * 检测浏览器是否为chrome
  105. * @name chrome
  106. * @grammar UE.browser.chrome => true|false
  107. */
  108. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  109. browser.chrome = +RegExp['\x241'];
  110. }
  111. /**
  112. * 检测浏览器是否为safari
  113. * @name safari
  114. * @grammar UE.browser.safari => true|false
  115. */
  116. if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) {
  117. browser.safari = +(RegExp['\x241'] || RegExp['\x242']);
  118. }
  119. // Opera 9.50+
  120. if (browser.opera)
  121. version = parseFloat(opera.version());
  122. // WebKit 522+ (Safari 3+)
  123. if (browser.webkit)
  124. version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);
  125. /**
  126. * 浏览器版本判断
  127. * IE系列返回值为5,6,7,8,9,10等
  128. * gecko系列会返回10900,158900等.
  129. * webkit系列会返回其build号 (如 522等).
  130. * @name version
  131. * @grammar UE.browser.version => number
  132. * @example
  133. * if ( UE.browser.ie && UE.browser.version == 6 ){
  134. * alert( "Ouch!居然是万恶的IE6!" );
  135. * }
  136. */
  137. browser.version = version;
  138. /**
  139. * 是否是兼容模式的浏览器
  140. * @name isCompatible
  141. * @grammar UE.browser.isCompatible => true|false
  142. * @example
  143. * if ( UE.browser.isCompatible ){
  144. * alert( "你的浏览器相当不错哦!" );
  145. * }
  146. */
  147. browser.isCompatible =
  148. !browser.mobile && (
  149. ( browser.ie && version >= 6 ) ||
  150. ( browser.gecko && version >= 10801 ) ||
  151. ( browser.opera && version >= 9.5 ) ||
  152. ( browser.air && version >= 1 ) ||
  153. ( browser.webkit && version >= 522 ) ||
  154. false );
  155. return browser;
  156. }();
  157. //快捷方式
  158. var ie = browser.ie,
  159. webkit = browser.webkit,
  160. gecko = browser.gecko,
  161. opera = browser.opera;
  162. /**
  163. * @file
  164. * @name UE.Utils
  165. * @short Utils
  166. * @desc UEditor封装使用的静态工具函数
  167. * @import editor.js
  168. */
  169. var utils = UE.utils = {
  170. /**
  171. * 遍历数组,对象,nodeList
  172. * @name each
  173. * @grammar UE.utils.each(obj,iterator,[context])
  174. * @since 1.2.4+
  175. * @desc
  176. * * obj 要遍历的对象
  177. * * iterator 遍历的方法,方法的第一个是遍历的值,第二个是索引,第三个是obj
  178. * * context iterator的上下文
  179. * @example
  180. * UE.utils.each([1,2],function(v,i){
  181. * console.log(v)//值
  182. * console.log(i)//索引
  183. * })
  184. * UE.utils.each(document.getElementsByTagName('*'),function(n){
  185. * console.log(n.tagName)
  186. * })
  187. */
  188. each: function (obj, iterator, context) {
  189. if (obj == null) return;
  190. if (obj.length === +obj.length) {
  191. for (var i = 0, l = obj.length; i < l; i++) {
  192. if (iterator.call(context, obj[i], i, obj) === false)
  193. return false;
  194. }
  195. } else {
  196. for (var key in obj) {
  197. if (obj.hasOwnProperty(key)) {
  198. if (iterator.call(context, obj[key], key, obj) === false)
  199. return false;
  200. }
  201. }
  202. }
  203. },
  204. makeInstance: function (obj) {
  205. var noop = new Function();
  206. noop.prototype = obj;
  207. obj = new noop;
  208. noop.prototype = null;
  209. return obj;
  210. },
  211. /**
  212. * 将source对象中的属性扩展到target对象上
  213. * @name extend
  214. * @grammar UE.utils.extend(target,source) => Object //覆盖扩展
  215. * @grammar UE.utils.extend(target,source,true) ==> Object //保留扩展
  216. */
  217. extend: function (t, s, b) {
  218. if (s) {
  219. for (var k in s) {
  220. if (!b || !t.hasOwnProperty(k)) {
  221. t[k] = s[k];
  222. }
  223. }
  224. }
  225. return t;
  226. },
  227. extend2: function (t) {
  228. var a = arguments;
  229. for (var i = 1; i < a.length; i++) {
  230. var x = a[i];
  231. for (var k in x) {
  232. if (!t.hasOwnProperty(k)) {
  233. t[k] = x[k];
  234. }
  235. }
  236. }
  237. return t;
  238. },
  239. /**
  240. * 模拟继承机制,subClass继承superClass
  241. * @name inherits
  242. * @grammar UE.utils.inherits(subClass,superClass) => subClass
  243. * @example
  244. * function SuperClass(){
  245. * this.name = "小李";
  246. * }
  247. * SuperClass.prototype = {
  248. * hello:function(str){
  249. * console.log(this.name + str);
  250. * }
  251. * }
  252. * function SubClass(){
  253. * this.name = "小张";
  254. * }
  255. * UE.utils.inherits(SubClass,SuperClass);
  256. * var sub = new SubClass();
  257. * sub.hello("早上好!"); ==> "小张早上好!"
  258. */
  259. inherits: function (subClass, superClass) {
  260. var oldP = subClass.prototype,
  261. newP = utils.makeInstance(superClass.prototype);
  262. utils.extend(newP, oldP, true);
  263. subClass.prototype = newP;
  264. return (newP.constructor = subClass);
  265. },
  266. /**
  267. * 用指定的context作为fn上下文,也就是this
  268. * @name bind
  269. * @grammar UE.utils.bind(fn,context) => fn
  270. */
  271. bind: function (fn, context) {
  272. return function () {
  273. return fn.apply(context, arguments);
  274. };
  275. },
  276. /**
  277. * 创建延迟delay执行的函数fn
  278. * @name defer
  279. * @grammar UE.utils.defer(fn,delay) =>fn //延迟delay毫秒执行fn,返回fn
  280. * @grammar UE.utils.defer(fn,delay,exclusion) =>fn //延迟delay毫秒执行fn,若exclusion为真,则互斥执行fn
  281. * @example
  282. * function test(){
  283. * console.log("延迟输出!");
  284. * }
  285. * //非互斥延迟执行
  286. * var testDefer = UE.utils.defer(test,1000);
  287. * testDefer(); => "延迟输出!";
  288. * testDefer(); => "延迟输出!";
  289. * //互斥延迟执行
  290. * var testDefer1 = UE.utils.defer(test,1000,true);
  291. * testDefer1(); => //本次不执行
  292. * testDefer1(); => "延迟输出!";
  293. */
  294. defer: function (fn, delay, exclusion) {
  295. var timerID;
  296. return function () {
  297. if (exclusion) {
  298. clearTimeout(timerID);
  299. }
  300. timerID = setTimeout(fn, delay);
  301. };
  302. },
  303. /**
  304. * 查找元素item在数组array中的索引, 若找不到返回-1
  305. * @name indexOf
  306. * @grammar UE.utils.indexOf(array,item) => index|-1 //默认从数组开头部开始搜索
  307. * @grammar UE.utils.indexOf(array,item,start) => index|-1 //start指定开始查找的位置
  308. */
  309. indexOf: function (array, item, start) {
  310. var index = -1;
  311. start = this.isNumber(start) ? start : 0;
  312. this.each(array, function (v, i) {
  313. if (i >= start && v === item) {
  314. index = i;
  315. return false;
  316. }
  317. });
  318. return index;
  319. },
  320. /**
  321. * 移除数组array中的元素item
  322. * @name removeItem
  323. * @grammar UE.utils.removeItem(array,item)
  324. */
  325. removeItem: function (array, item) {
  326. for (var i = 0, l = array.length; i < l; i++) {
  327. if (array[i] === item) {
  328. array.splice(i, 1);
  329. i--;
  330. }
  331. }
  332. },
  333. /**
  334. * 删除字符串str的首尾空格
  335. * @name trim
  336. * @grammar UE.utils.trim(str) => String
  337. */
  338. trim: function (str) {
  339. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
  340. },
  341. /**
  342. * 将字符串list(以','分隔)或者数组list转成哈希对象
  343. * @name listToMap
  344. * @grammar UE.utils.listToMap(list) => Object //Object形如{test:1,br:1,textarea:1}
  345. */
  346. listToMap: function (list) {
  347. if (!list)return {};
  348. list = utils.isArray(list) ? list : list.split(',');
  349. for (var i = 0, ci, obj = {}; ci = list[i++];) {
  350. obj[ci.toUpperCase()] = obj[ci] = 1;
  351. }
  352. return obj;
  353. },
  354. /**
  355. * 将str中的html符号转义,默认将转义''&<">''四个字符,可自定义reg来确定需要转义的字符
  356. * @name unhtml
  357. * @grammar UE.utils.unhtml(str); => String
  358. * @grammar UE.utils.unhtml(str,reg) => String
  359. * @example
  360. * var html = '<body>You say:"你好!Baidu & UEditor!"</body>';
  361. * UE.utils.unhtml(html); ==> &lt;body&gt;You say:&quot;你好!Baidu &amp; UEditor!&quot;&lt;/body&gt;
  362. * UE.utils.unhtml(html,/[<>]/g) ==> &lt;body&gt;You say:"你好!Baidu & UEditor!"&lt;/body&gt;
  363. */
  364. unhtml: function (str, reg) {
  365. return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function (a, b) {
  366. if (b) {
  367. return a;
  368. } else {
  369. return {
  370. '<': '&lt;',
  371. '&': '&amp;',
  372. '"': '&quot;',
  373. '>': '&gt;',
  374. "'": '&#39;'
  375. }[a]
  376. }
  377. }) : '';
  378. },
  379. /**
  380. * 将str中的转义字符还原成html字符
  381. * @name html
  382. * @grammar UE.utils.html(str) => String //详细参见<code><a href = '#unhtml'>unhtml</a></code>
  383. */
  384. html: function (str) {
  385. return str ? str.replace(/&((g|l|quo)t|amp|#39);/g, function (m) {
  386. return {
  387. '&lt;': '<',
  388. '&amp;': '&',
  389. '&quot;': '"',
  390. '&gt;': '>',
  391. '&#39;': "'"
  392. }[m]
  393. }) : '';
  394. },
  395. /**
  396. * 将css样式转换为驼峰的形式。如font-size => fontSize
  397. * @name cssStyleToDomStyle
  398. * @grammar UE.utils.cssStyleToDomStyle(cssName) => String
  399. */
  400. cssStyleToDomStyle: function () {
  401. var test = document.createElement('div').style,
  402. cache = {
  403. 'float': test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat' : 'float'
  404. };
  405. return function (cssName) {
  406. return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) {
  407. return match.charAt(1).toUpperCase();
  408. }));
  409. };
  410. }(),
  411. /**
  412. * 动态加载文件到doc中,并依据obj来设置属性,加载成功后执行回调函数fn
  413. * @name loadFile
  414. * @grammar UE.utils.loadFile(doc,obj)
  415. * @grammar UE.utils.loadFile(doc,obj,fn)
  416. * @example
  417. * //指定加载到当前document中一个script文件,加载成功后执行function
  418. * utils.loadFile( document, {
  419. * src:"test.js",
  420. * tag:"script",
  421. * type:"text/javascript",
  422. * defer:"defer"
  423. * }, function () {
  424. * console.log('加载成功!')
  425. * });
  426. */
  427. loadFile: function () {
  428. var tmpList = [];
  429. function getItem(doc, obj) {
  430. try {
  431. for (var i = 0, ci; ci = tmpList[i++];) {
  432. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  433. return ci;
  434. }
  435. }
  436. } catch (e) {
  437. return null;
  438. }
  439. }
  440. return function (doc, obj, fn) {
  441. var item = getItem(doc, obj);
  442. if (item) {
  443. if (item.ready) {
  444. fn && fn();
  445. } else {
  446. item.funs.push(fn)
  447. }
  448. return;
  449. }
  450. tmpList.push({
  451. doc: doc,
  452. url: obj.src || obj.href,
  453. funs: [fn]
  454. });
  455. if (!doc.body) {
  456. var html = [];
  457. for (var p in obj) {
  458. if (p == 'tag')continue;
  459. html.push(p + '="' + obj[p] + '"')
  460. }
  461. doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
  462. return;
  463. }
  464. if (obj.id && doc.getElementById(obj.id)) {
  465. return;
  466. }
  467. var element = doc.createElement(obj.tag);
  468. delete obj.tag;
  469. for (var p in obj) {
  470. element.setAttribute(p, obj[p]);
  471. }
  472. element.onload = element.onreadystatechange = function () {
  473. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  474. item = getItem(doc, obj);
  475. if (item.funs.length > 0) {
  476. item.ready = 1;
  477. for (var fi; fi = item.funs.pop();) {
  478. fi();
  479. }
  480. }
  481. element.onload = element.onreadystatechange = null;
  482. }
  483. };
  484. element.onerror = function () {
  485. throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file ueditor.config.js ')
  486. };
  487. doc.getElementsByTagName("head")[0].appendChild(element);
  488. }
  489. }(),
  490. /**
  491. * 判断obj对象是否为空
  492. * @name isEmptyObject
  493. * @grammar UE.utils.isEmptyObject(obj) => true|false
  494. * @example
  495. * UE.utils.isEmptyObject({}) ==>true
  496. * UE.utils.isEmptyObject([]) ==>true
  497. * UE.utils.isEmptyObject("") ==>true
  498. */
  499. isEmptyObject: function (obj) {
  500. if (obj == null) return true;
  501. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
  502. for (var key in obj) if (obj.hasOwnProperty(key)) return false;
  503. return true;
  504. },
  505. /**
  506. * 统一将颜色值使用16进制形式表示
  507. * @name fixColor
  508. * @grammar UE.utils.fixColor(name,value) => value
  509. * @example
  510. * rgb(255,255,255) => "#ffffff"
  511. */
  512. fixColor: function (name, value) {
  513. if (/color/i.test(name) && /rgba?/.test(value)) {
  514. var array = value.split(",");
  515. if (array.length > 3)
  516. return "";
  517. value = "#";
  518. for (var i = 0, color; color = array[i++];) {
  519. color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
  520. value += color.length == 1 ? "0" + color : color;
  521. }
  522. value = value.toUpperCase();
  523. }
  524. return value;
  525. },
  526. /**
  527. * 只针对border,padding,margin做了处理,因为性能问题
  528. * @public
  529. * @function
  530. * @param {String} val style字符串
  531. */
  532. optCss: function (val) {
  533. var padding, margin, border;
  534. val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function (str, key, name, val) {
  535. if (val.split(' ').length == 1) {
  536. switch (key) {
  537. case 'padding':
  538. !padding && (padding = {});
  539. padding[name] = val;
  540. return '';
  541. case 'margin':
  542. !margin && (margin = {});
  543. margin[name] = val;
  544. return '';
  545. case 'border':
  546. return val == 'initial' ? '' : str;
  547. }
  548. }
  549. return str;
  550. });
  551. function opt(obj, name) {
  552. if (!obj) {
  553. return '';
  554. }
  555. var t = obj.top , b = obj.bottom, l = obj.left, r = obj.right, val = '';
  556. if (!t || !l || !b || !r) {
  557. for (var p in obj) {
  558. val += ';' + name + '-' + p + ':' + obj[p] + ';';
  559. }
  560. } else {
  561. val += ';' + name + ':' +
  562. (t == b && b == l && l == r ? t :
  563. t == b && l == r ? (t + ' ' + l) :
  564. l == r ? (t + ' ' + l + ' ' + b) : (t + ' ' + r + ' ' + b + ' ' + l)) + ';'
  565. }
  566. return val;
  567. }
  568. val += opt(padding, 'padding') + opt(margin, 'margin');
  569. return val.replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, '').replace(/;([ \n\r\t]+)|\1;/g, ';')
  570. .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function (a, b) {
  571. return b ? b + ";;" : ';'
  572. });
  573. },
  574. /**
  575. * 深度克隆对象,从source到target
  576. * @name clone
  577. * @grammar UE.utils.clone(source) => anthorObj 新的对象是完整的source的副本
  578. * @grammar UE.utils.clone(source,target) => target包含了source的所有内容,重名会覆盖
  579. */
  580. clone: function (source, target) {
  581. var tmp;
  582. target = target || {};
  583. for (var i in source) {
  584. if (source.hasOwnProperty(i)) {
  585. tmp = source[i];
  586. if (typeof tmp == 'object') {
  587. target[i] = utils.isArray(tmp) ? [] : {};
  588. utils.clone(source[i], target[i])
  589. } else {
  590. target[i] = tmp;
  591. }
  592. }
  593. }
  594. return target;
  595. },
  596. /**
  597. * 转换cm/pt到px
  598. * @name transUnitToPx
  599. * @grammar UE.utils.transUnitToPx('20pt') => '27px'
  600. * @grammar UE.utils.transUnitToPx('0pt') => '0'
  601. */
  602. transUnitToPx: function (val) {
  603. if (!/(pt|cm)/.test(val)) {
  604. return val
  605. }
  606. var unit;
  607. val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
  608. val = v;
  609. unit = u;
  610. });
  611. switch (unit) {
  612. case 'cm':
  613. val = parseFloat(val) * 25;
  614. break;
  615. case 'pt':
  616. val = Math.round(parseFloat(val) * 96 / 72);
  617. }
  618. return val + (val ? 'px' : '');
  619. },
  620. /**
  621. * DomReady方法,回调函数将在dom树ready完成后执行
  622. * @name domReady
  623. * @grammar UE.utils.domReady(fn) => fn //返回一个延迟执行的方法
  624. */
  625. domReady: function () {
  626. var fnArr = [];
  627. function doReady(doc) {
  628. //确保onready只执行一次
  629. doc.isReady = true;
  630. for (var ci; ci = fnArr.pop(); ci()) {
  631. }
  632. }
  633. return function (onready, win) {
  634. win = win || window;
  635. var doc = win.document;
  636. onready && fnArr.push(onready);
  637. if (doc.readyState === "complete") {
  638. doReady(doc);
  639. } else {
  640. doc.isReady && doReady(doc);
  641. if (browser.ie) {
  642. (function () {
  643. if (doc.isReady) return;
  644. try {
  645. doc.documentElement.doScroll("left");
  646. } catch (error) {
  647. setTimeout(arguments.callee, 0);
  648. return;
  649. }
  650. doReady(doc);
  651. })();
  652. win.attachEvent('onload', function () {
  653. doReady(doc)
  654. });
  655. } else {
  656. doc.addEventListener("DOMContentLoaded", function () {
  657. doc.removeEventListener("DOMContentLoaded", arguments.callee, false);
  658. doReady(doc);
  659. }, false);
  660. win.addEventListener('load', function () {
  661. doReady(doc)
  662. }, false);
  663. }
  664. }
  665. }
  666. }(),
  667. /**
  668. * 动态添加css样式
  669. * @name cssRule
  670. * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  671. * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  672. * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  673. * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  674. */
  675. cssRule: browser.ie ? function (key, style, doc) {
  676. var indexList, index;
  677. doc = doc || document;
  678. if (doc.indexList) {
  679. indexList = doc.indexList;
  680. } else {
  681. indexList = doc.indexList = {};
  682. }
  683. var sheetStyle;
  684. if (!indexList[key]) {
  685. if (style === undefined) {
  686. return ''
  687. }
  688. sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length);
  689. indexList[key] = index;
  690. } else {
  691. sheetStyle = doc.styleSheets[indexList[key]];
  692. }
  693. if (style === undefined) {
  694. return sheetStyle.cssText
  695. }
  696. sheetStyle.cssText = style || ''
  697. } : function (key, style, doc) {
  698. doc = doc || document;
  699. var head = doc.getElementsByTagName('head')[0], node;
  700. if (!(node = doc.getElementById(key))) {
  701. if (style === undefined) {
  702. return ''
  703. }
  704. node = doc.createElement('style');
  705. node.id = key;
  706. head.appendChild(node)
  707. }
  708. if (style === undefined) {
  709. return node.innerHTML
  710. }
  711. if (style !== '') {
  712. node.innerHTML = style;
  713. } else {
  714. head.removeChild(node)
  715. }
  716. },
  717. sort: function (array, compareFn) {
  718. compareFn = compareFn || function (item1, item2) {
  719. return item1.localeCompare(item2);
  720. };
  721. for (var i = 0, len = array.length; i < len; i++) {
  722. for (var j = i, length = array.length; j < length; j++) {
  723. if (compareFn(array[i], array[j]) > 0) {
  724. var t = array[i];
  725. array[i] = array[j];
  726. array[j] = t;
  727. }
  728. }
  729. }
  730. return array;
  731. }
  732. };
  733. /**
  734. * 判断str是否为字符串
  735. * @name isString
  736. * @grammar UE.utils.isString(str) => true|false
  737. */
  738. /**
  739. * 判断array是否为数组
  740. * @name isArray
  741. * @grammar UE.utils.isArray(obj) => true|false
  742. */
  743. /**
  744. * 判断obj对象是否为方法
  745. * @name isFunction
  746. * @grammar UE.utils.isFunction(obj) => true|false
  747. */
  748. /**
  749. * 判断obj对象是否为数字
  750. * @name isNumber
  751. * @grammar UE.utils.isNumber(obj) => true|false
  752. */
  753. utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function (v) {
  754. UE.utils['is' + v] = function (obj) {
  755. return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
  756. }
  757. });
  758. /**
  759. * @file
  760. * @name UE.EventBase
  761. * @short EventBase
  762. * @import editor.js,core/utils.js
  763. * @desc UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
  764. * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
  765. */
  766. var EventBase = UE.EventBase = function () {
  767. };
  768. EventBase.prototype = {
  769. /**
  770. * 注册事件监听器
  771. * @name addListener
  772. * @grammar editor.addListener(types,fn) //types为事件名称,多个可用空格分隔
  773. * @example
  774. * editor.addListener('selectionchange',function(){
  775. * console.log("选区已经变化!");
  776. * })
  777. * editor.addListener('beforegetcontent aftergetcontent',function(type){
  778. * if(type == 'beforegetcontent'){
  779. * //do something
  780. * }else{
  781. * //do something
  782. * }
  783. * console.log(this.getContent) // this是注册的事件的编辑器实例
  784. * })
  785. */
  786. addListener: function (types, listener) {
  787. types = utils.trim(types).split(' ');
  788. for (var i = 0, ti; ti = types[i++];) {
  789. getListener(this, ti, true).push(listener);
  790. }
  791. },
  792. /**
  793. * 移除事件监听器
  794. * @name removeListener
  795. * @grammar editor.removeListener(types,fn) //types为事件名称,多个可用空格分隔
  796. * @example
  797. * //changeCallback为方法体
  798. * editor.removeListener("selectionchange",changeCallback);
  799. */
  800. removeListener: function (types, listener) {
  801. types = utils.trim(types).split(' ');
  802. for (var i = 0, ti; ti = types[i++];) {
  803. utils.removeItem(getListener(this, ti) || [], listener);
  804. }
  805. },
  806. /**
  807. * 触发事件
  808. * @name fireEvent
  809. * @grammar editor.fireEvent(types) //types为事件名称,多个可用空格分隔
  810. * @example
  811. * editor.fireEvent("selectionchange");
  812. */
  813. fireEvent: function () {
  814. var types = arguments[0];
  815. types = utils.trim(types).split(' ');
  816. for (var i = 0, ti; ti = types[i++];) {
  817. var listeners = getListener(this, ti),
  818. r, t, k;
  819. if (listeners) {
  820. k = listeners.length;
  821. while (k--) {
  822. if (!listeners[k])continue;
  823. t = listeners[k].apply(this, arguments);
  824. if (t === true) {
  825. return t;
  826. }
  827. if (t !== undefined) {
  828. r = t;
  829. }
  830. }
  831. }
  832. if (t = this['on' + ti.toLowerCase()]) {
  833. r = t.apply(this, arguments);
  834. }
  835. }
  836. return r;
  837. }
  838. };
  839. /**
  840. * 获得对象所拥有监听类型的所有监听器
  841. * @public
  842. * @function
  843. * @param {Object} obj 查询监听器的对象
  844. * @param {String} type 事件类型
  845. * @param {Boolean} force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  846. * @returns {Array} 监听器数组
  847. */
  848. function getListener(obj, type, force) {
  849. var allListeners;
  850. type = type.toLowerCase();
  851. return ( ( allListeners = ( obj.__allListeners || force && ( obj.__allListeners = {} ) ) )
  852. && ( allListeners[type] || force && ( allListeners[type] = [] ) ) );
  853. }
  854. ///import editor.js
  855. ///import core/dom/dom.js
  856. ///import core/utils.js
  857. /**
  858. * dtd html语义化的体现类
  859. * @constructor
  860. * @namespace dtd
  861. */
  862. var dtd = dom.dtd = (function () {
  863. function _(s) {
  864. for (var k in s) {
  865. s[k.toUpperCase()] = s[k];
  866. }
  867. return s;
  868. }
  869. var X = utils.extend2;
  870. var A = _({isindex: 1, fieldset: 1}),
  871. B = _({input: 1, button: 1, select: 1, textarea: 1, label: 1}),
  872. C = X(_({a: 1}), B),
  873. D = X({iframe: 1}, C),
  874. 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}),
  875. F = _({ins: 1, del: 1, script: 1, style: 1}),
  876. 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),
  877. 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),
  878. I = X(_({p: 1}), H),
  879. J = X(_({iframe: 1}), H, B),
  880. 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}),
  881. L = X(_({a: 0}), J),//a不能被切开,所以把他
  882. M = _({tr: 1}),
  883. N = _({'#': 1}),
  884. O = X(_({param: 1}), K),
  885. P = X(_({form: 1}), A, D, E, I),
  886. Q = _({li: 1, ol: 1, ul: 1}),
  887. R = _({style: 1, script: 1}),
  888. S = _({base: 1, link: 1, meta: 1, title: 1}),
  889. T = X(S, R),
  890. U = _({head: 1, body: 1}),
  891. V = _({html: 1});
  892. 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}),
  893. empty = _({area: 1, base: 1, basefont: 1, br: 1, col: 1, command: 1, dialog: 1, embed: 1, hr: 1, img: 1, input: 1, isindex: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, track: 1, wbr: 1});
  894. return _({
  895. // $ 表示自定的属性
  896. // body外的元素列表.
  897. $nonBodyContent: X(V, U, S),
  898. //块结构元素列表
  899. $block: block,
  900. //内联元素列表
  901. $inline: L,
  902. $inlineWithA: X(_({a: 1}), L),
  903. $body: X(_({script: 1, style: 1}), block),
  904. $cdata: _({script: 1, style: 1}),
  905. //自闭和元素
  906. $empty: empty,
  907. //不是自闭合,但不能让range选中里边
  908. $nonChild: _({iframe: 1, textarea: 1}),
  909. //列表元素列表
  910. $listItem: _({dd: 1, dt: 1, li: 1}),
  911. //列表根元素列表
  912. $list: _({ul: 1, ol: 1, dl: 1}),
  913. //不能认为是空的元素
  914. $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, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1}),
  915. //如果没有子节点就可以删除的元素列表,像span,a
  916. $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}),
  917. $removeEmptyBlock: _({'p': 1, 'div': 1}),
  918. //在table元素里的元素列表
  919. $tableContent: _({caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1, table: 1}),
  920. //不转换的标签
  921. $notTransContent: _({pre: 1, script: 1, style: 1, textarea: 1}),
  922. html: U,
  923. head: T,
  924. style: N,
  925. script: N,
  926. body: P,
  927. base: {},
  928. link: {},
  929. meta: {},
  930. title: N,
  931. col: {},
  932. tr: _({td: 1, th: 1}),
  933. img: {},
  934. embed: {},
  935. colgroup: _({thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1}),
  936. noscript: P,
  937. td: P,
  938. br: {},
  939. th: P,
  940. center: P,
  941. kbd: L,
  942. button: X(I, E),
  943. basefont: {},
  944. h5: L,
  945. h4: L,
  946. samp: L,
  947. h6: L,
  948. ol: Q,
  949. h1: L,
  950. h3: L,
  951. option: N,
  952. h2: L,
  953. form: X(A, D, E, I),
  954. select: _({optgroup: 1, option: 1}),
  955. font: L,
  956. ins: L,
  957. menu: Q,
  958. abbr: L,
  959. label: L,
  960. table: _({thead: 1, col: 1, tbody: 1, tr: 1, colgroup: 1, caption: 1, tfoot: 1}),
  961. code: L,
  962. tfoot: M,
  963. cite: L,
  964. li: P,
  965. input: {},
  966. iframe: P,
  967. strong: L,
  968. textarea: N,
  969. noframes: P,
  970. big: L,
  971. small: L,
  972. //trace:
  973. span: _({'#': 1, br: 1, b: 1, strong: 1, u: 1, i: 1, em: 1, sub: 1, sup: 1, strike: 1, span: 1}),
  974. hr: L,
  975. dt: L,
  976. sub: L,
  977. optgroup: _({option: 1}),
  978. param: {},
  979. bdo: L,
  980. 'var': L,
  981. div: P,
  982. object: O,
  983. sup: L,
  984. dd: P,
  985. strike: L,
  986. area: {},
  987. dir: Q,
  988. map: X(_({area: 1, form: 1, p: 1}), A, F, E),
  989. applet: O,
  990. dl: _({dt: 1, dd: 1}),
  991. del: L,
  992. isindex: {},
  993. fieldset: X(_({legend: 1}), K),
  994. thead: M,
  995. ul: Q,
  996. acronym: L,
  997. b: L,
  998. a: X(_({a: 1}), J),
  999. blockquote: X(_({td: 1, tr: 1, tbody: 1, li: 1}), P),
  1000. caption: L,
  1001. i: L,
  1002. u: L,
  1003. tbody: M,
  1004. s: L,
  1005. address: X(D, I),
  1006. tt: L,
  1007. legend: L,
  1008. q: L,
  1009. pre: X(G, C),
  1010. p: X(_({'a': 1}), L),
  1011. em: L,
  1012. dfn: L
  1013. });
  1014. })();
  1015. /**
  1016. * @file
  1017. * @name UE.dom.domUtils
  1018. * @short DomUtils
  1019. * @import editor.js, core/utils.js,core/browser.js,core/dom/dtd.js
  1020. * @desc UEditor封装的底层dom操作库
  1021. */
  1022. function getDomNode(node, start, ltr, startFromChild, fn, guard) {
  1023. var tmpNode = startFromChild && node[start],
  1024. parent;
  1025. !tmpNode && (tmpNode = node[ltr]);
  1026. while (!tmpNode && (parent = (parent || node).parentNode)) {
  1027. if (parent.tagName == 'BODY' || guard && !guard(parent)) {
  1028. return null;
  1029. }
  1030. tmpNode = parent[ltr];
  1031. }
  1032. if (tmpNode && fn && !fn(tmpNode)) {
  1033. return getDomNode(tmpNode, start, ltr, false, fn);
  1034. }
  1035. return tmpNode;
  1036. }
  1037. var attrFix = ie && browser.version < 9 ? {
  1038. tabindex: "tabIndex",
  1039. readonly: "readOnly",
  1040. "for": "htmlFor",
  1041. "class": "className",
  1042. maxlength: "maxLength",
  1043. cellspacing: "cellSpacing",
  1044. cellpadding: "cellPadding",
  1045. rowspan: "rowSpan",
  1046. colspan: "colSpan",
  1047. usemap: "useMap",
  1048. frameborder: "frameBorder"
  1049. } : {
  1050. tabindex: "tabIndex",
  1051. readonly: "readOnly"
  1052. },
  1053. styleBlock = utils.listToMap([
  1054. '-webkit-box', '-moz-box', 'block' ,
  1055. 'list-item' , 'table' , 'table-row-group' ,
  1056. 'table-header-group', 'table-footer-group' ,
  1057. 'table-row' , 'table-column-group' , 'table-column' ,
  1058. 'table-cell' , 'table-caption'
  1059. ]);
  1060. var domUtils = dom.domUtils = {
  1061. //节点常量
  1062. NODE_ELEMENT: 1,
  1063. NODE_DOCUMENT: 9,
  1064. NODE_TEXT: 3,
  1065. NODE_COMMENT: 8,
  1066. NODE_DOCUMENT_FRAGMENT: 11,
  1067. //位置关系
  1068. POSITION_IDENTICAL: 0,
  1069. POSITION_DISCONNECTED: 1,
  1070. POSITION_FOLLOWING: 2,
  1071. POSITION_PRECEDING: 4,
  1072. POSITION_IS_CONTAINED: 8,
  1073. POSITION_CONTAINS: 16,
  1074. //ie6使用其他的会有一段空白出现
  1075. fillChar: ie && browser.version == '6' ? '\ufeff' : '\u200B',
  1076. //-------------------------Node部分--------------------------------
  1077. keys: {
  1078. /*Backspace*/ 8: 1, /*Delete*/ 46: 1,
  1079. /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1,
  1080. 37: 1, 38: 1, 39: 1, 40: 1,
  1081. 13: 1 /*enter*/
  1082. },
  1083. /**
  1084. * 获取节点A相对于节点B的位置关系
  1085. * @name getPosition
  1086. * @grammar UE.dom.domUtils.getPosition(nodeA,nodeB) => Number
  1087. * @example
  1088. * switch (returnValue) {
  1089. * case 0: //相等,同一节点
  1090. * case 1: //无关,节点不相连
  1091. * case 2: //跟随,即节点A头部位于节点B头部的后面
  1092. * case 4: //前置,即节点A头部位于节点B头部的前面
  1093. * case 8: //被包含,即节点A被节点B包含
  1094. * case 10://组合类型,即节点A满足跟随节点B且被节点B包含。实际上,如果被包含,必定跟随,所以returnValue事实上不会存在8的情况。
  1095. * case 16://包含,即节点A包含节点B
  1096. * case 20://组合类型,即节点A满足前置节点A且包含节点B。同样,如果包含,必定前置,所以returnValue事实上也不会存在16的情况
  1097. * }
  1098. */
  1099. getPosition: function (nodeA, nodeB) {
  1100. // 如果两个节点是同一个节点
  1101. if (nodeA === nodeB) {
  1102. // domUtils.POSITION_IDENTICAL
  1103. return 0;
  1104. }
  1105. var node,
  1106. parentsA = [nodeA],
  1107. parentsB = [nodeB];
  1108. node = nodeA;
  1109. while (node = node.parentNode) {
  1110. // 如果nodeB是nodeA的祖先节点
  1111. if (node === nodeB) {
  1112. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  1113. return 10;
  1114. }
  1115. parentsA.push(node);
  1116. }
  1117. node = nodeB;
  1118. while (node = node.parentNode) {
  1119. // 如果nodeA是nodeB的祖先节点
  1120. if (node === nodeA) {
  1121. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  1122. return 20;
  1123. }
  1124. parentsB.push(node);
  1125. }
  1126. parentsA.reverse();
  1127. parentsB.reverse();
  1128. if (parentsA[0] !== parentsB[0]) {
  1129. // domUtils.POSITION_DISCONNECTED
  1130. return 1;
  1131. }
  1132. var i = -1;
  1133. while (i++, parentsA[i] === parentsB[i]) {
  1134. }
  1135. nodeA = parentsA[i];
  1136. nodeB = parentsB[i];
  1137. while (nodeA = nodeA.nextSibling) {
  1138. if (nodeA === nodeB) {
  1139. // domUtils.POSITION_PRECEDING
  1140. return 4
  1141. }
  1142. }
  1143. // domUtils.POSITION_FOLLOWING
  1144. return 2;
  1145. },
  1146. /**
  1147. * 返回节点node在父节点中的索引位置
  1148. * @name getNodeIndex
  1149. * @grammar UE.dom.domUtils.getNodeIndex(node) => Number //索引值从0开始
  1150. */
  1151. getNodeIndex: function (node, ignoreTextNode) {
  1152. var preNode = node,
  1153. i = 0;
  1154. while (preNode = preNode.previousSibling) {
  1155. if (ignoreTextNode && preNode.nodeType == 3) {
  1156. if (preNode.nodeType != preNode.nextSibling.nodeType) {
  1157. i++;
  1158. }
  1159. continue;
  1160. }
  1161. i++;
  1162. }
  1163. return i;
  1164. },
  1165. /**
  1166. * 检测节点node是否在节点doc的树上,实质上是检测是否被doc包含
  1167. * @name inDoc
  1168. * @grammar UE.dom.domUtils.inDoc(node,doc) => true|false
  1169. */
  1170. inDoc: function (node, doc) {
  1171. return domUtils.getPosition(node, doc) == 10;
  1172. },
  1173. /**
  1174. * 查找node节点的祖先节点
  1175. * @name findParent
  1176. * @grammar UE.dom.domUtils.findParent(node) => Element // 直接返回node节点的父节点
  1177. * @grammar UE.dom.domUtils.findParent(node,filterFn) => Element //filterFn为过滤函数,node作为参数,返回true时才会将node作为符合要求的节点返回
  1178. * @grammar UE.dom.domUtils.findParent(node,filterFn,includeSelf) => Element //includeSelf指定是否包含自身
  1179. */
  1180. findParent: function (node, filterFn, includeSelf) {
  1181. if (node && !domUtils.isBody(node)) {
  1182. node = includeSelf ? node : node.parentNode;
  1183. while (node) {
  1184. if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
  1185. return filterFn && !filterFn(node) && domUtils.isBody(node) ? null : node;
  1186. }
  1187. node = node.parentNode;
  1188. }
  1189. }
  1190. return null;
  1191. },
  1192. /**
  1193. * 通过tagName查找node节点的祖先节点
  1194. * @name findParentByTagName
  1195. * @grammar UE.dom.domUtils.findParentByTagName(node,tagNames) => Element //tagNames支持数组,区分大小写
  1196. * @grammar UE.dom.domUtils.findParentByTagName(node,tagNames,includeSelf) => Element //includeSelf指定是否包含自身
  1197. * @grammar UE.dom.domUtils.findParentByTagName(node,tagNames,includeSelf,excludeFn) => Element //excludeFn指定例外过滤条件,返回true时忽略该节点
  1198. */
  1199. findParentByTagName: function (node, tagNames, includeSelf, excludeFn) {
  1200. tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
  1201. return domUtils.findParent(node, function (node) {
  1202. return tagNames[node.tagName] && !(excludeFn && excludeFn(node));
  1203. }, includeSelf);
  1204. },
  1205. /**
  1206. * 查找节点node的祖先节点集合
  1207. * @name findParents
  1208. * @grammar UE.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
  1209. * @grammar UE.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
  1210. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
  1211. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
  1212. */
  1213. findParents: function (node, includeSelf, filterFn, closerFirst) {
  1214. var parents = includeSelf && ( filterFn && filterFn(node) || !filterFn ) ? [node] : [];
  1215. while (node = domUtils.findParent(node, filterFn)) {
  1216. parents.push(node);
  1217. }
  1218. return closerFirst ? parents : parents.reverse();
  1219. },
  1220. /**
  1221. * 在节点node后面插入新节点newNode
  1222. * @name insertAfter
  1223. * @grammar UE.dom.domUtils.insertAfter(node,newNode) => newNode
  1224. */
  1225. insertAfter: function (node, newNode) {
  1226. return node.parentNode.insertBefore(newNode, node.nextSibling);
  1227. },
  1228. /**
  1229. * 删除节点node,并根据keepChildren指定是否保留子节点
  1230. * @name remove
  1231. * @grammar UE.dom.domUtils.remove(node) => node
  1232. * @grammar UE.dom.domUtils.remove(node,keepChildren) => node
  1233. */
  1234. remove: function (node, keepChildren) {
  1235. var parent = node.parentNode,
  1236. child;
  1237. if (parent) {
  1238. if (keepChildren && node.hasChildNodes()) {
  1239. while (child = node.firstChild) {
  1240. parent.insertBefore(child, node);
  1241. }
  1242. }
  1243. parent.removeChild(node);
  1244. }
  1245. return node;
  1246. },
  1247. /**
  1248. * 取得node节点在dom树上的下一个节点,即多叉树遍历
  1249. * @name getNextDomNode
  1250. * @grammar UE.dom.domUtils.getNextDomNode(node) => Element
  1251. * @example
  1252. */
  1253. getNextDomNode: function (node, startFromChild, filterFn, guard) {
  1254. return getDomNode(node, 'firstChild', 'nextSibling', startFromChild, filterFn, guard);
  1255. },
  1256. /**
  1257. * 检测节点node是否属于bookmark节点
  1258. * @name isBookmarkNode
  1259. * @grammar UE.dom.domUtils.isBookmarkNode(node) => true|false
  1260. */
  1261. isBookmarkNode: function (node) {
  1262. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id);
  1263. },
  1264. /**
  1265. * 获取节点node所在的window对象
  1266. * @name getWindow
  1267. * @grammar UE.dom.domUtils.getWindow(node) => window对象
  1268. */
  1269. getWindow: function (node) {
  1270. var doc = node.ownerDocument || node;
  1271. return doc.defaultView || doc.parentWindow;
  1272. },
  1273. /**
  1274. * 得到nodeA与nodeB公共的祖先节点
  1275. * @name getCommonAncestor
  1276. * @grammar UE.dom.domUtils.getCommonAncestor(nodeA,nodeB) => Element
  1277. */
  1278. getCommonAncestor: function (nodeA, nodeB) {
  1279. if (nodeA === nodeB)
  1280. return nodeA;
  1281. var parentsA = [nodeA] , parentsB = [nodeB], parent = nodeA, i = -1;
  1282. while (parent = parent.parentNode) {
  1283. if (parent === nodeB) {
  1284. return parent;
  1285. }
  1286. parentsA.push(parent);
  1287. }
  1288. parent = nodeB;
  1289. while (parent = parent.parentNode) {
  1290. if (parent === nodeA)
  1291. return parent;
  1292. parentsB.push(parent);
  1293. }
  1294. parentsA.reverse();
  1295. parentsB.reverse();
  1296. while (i++, parentsA[i] === parentsB[i]) {
  1297. }
  1298. return i == 0 ? null : parentsA[i - 1];
  1299. },
  1300. /**
  1301. * 清除node节点左右兄弟为空的inline节点
  1302. * @name clearEmptySibling
  1303. * @grammar UE.dom.domUtils.clearEmptySibling(node)
  1304. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
  1305. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
  1306. * @example
  1307. * <b></b><i></i>xxxx<b>bb</b> --> xxxx<b>bb</b>
  1308. */
  1309. clearEmptySibling: function (node, ignoreNext, ignorePre) {
  1310. function clear(next, dir) {
  1311. var tmpNode;
  1312. while (next && !domUtils.isBookmarkNode(next) && (domUtils.isEmptyInlineElement(next)
  1313. //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
  1314. || !new RegExp('[^\t\n\r' + domUtils.fillChar + ']').test(next.nodeValue) )) {
  1315. tmpNode = next[dir];
  1316. domUtils.remove(next);
  1317. next = tmpNode;
  1318. }
  1319. }
  1320. !ignoreNext && clear(node.nextSibling, 'nextSibling');
  1321. !ignorePre && clear(node.previousSibling, 'previousSibling');
  1322. },
  1323. /**
  1324. * 将一个文本节点node拆分成两个文本节点,offset指定拆分位置
  1325. * @name split
  1326. * @grammar UE.dom.domUtils.split(node,offset) => TextNode //返回从切分位置开始的后一个文本节点
  1327. */
  1328. split: function (node, offset) {
  1329. var doc = node.ownerDocument;
  1330. if (browser.ie && offset == node.nodeValue.length) {
  1331. var next = doc.createTextNode('');
  1332. return domUtils.insertAfter(node, next);
  1333. }
  1334. var retval = node.splitText(offset);
  1335. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  1336. if (browser.ie8) {
  1337. var tmpNode = doc.createTextNode('');
  1338. domUtils.insertAfter(retval, tmpNode);
  1339. domUtils.remove(tmpNode);
  1340. }
  1341. return retval;
  1342. },
  1343. /**
  1344. * 检测节点node是否为空节点(包括空格、换行、占位符等字符)
  1345. * @name isWhitespace
  1346. * @grammar UE.dom.domUtils.isWhitespace(node) => true|false
  1347. */
  1348. isWhitespace: function (node) {
  1349. return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(node.nodeValue);
  1350. },
  1351. /**
  1352. * 获取元素element相对于viewport的位置坐标
  1353. * @name getXY
  1354. * @grammar UE.dom.domUtils.getXY(element) => Object //返回坐标对象{x:left,y:top}
  1355. */
  1356. getXY: function (element) {
  1357. var x = 0, y = 0;
  1358. while (element.offsetParent) {
  1359. y += element.offsetTop;
  1360. x += element.offsetLeft;
  1361. element = element.offsetParent;
  1362. }
  1363. return { 'x': x, 'y': y};
  1364. },
  1365. /**
  1366. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  1367. * @name on
  1368. * @grammar UE.dom.domUtils.on(element,type,handler) //type支持数组传入
  1369. * @example
  1370. * UE.dom.domUtils.on(document.body,"click",function(e){
  1371. * //e为事件对象,this为被点击元素对戏那个
  1372. * })
  1373. * @example
  1374. * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
  1375. * //evt为事件对象,this为被点击元素对象
  1376. * })
  1377. */
  1378. on: function (element, type, handler) {
  1379. var types = utils.isArray(type) ? type : [type],
  1380. k = types.length;
  1381. if (k) while (k--) {
  1382. type = types[k];
  1383. if (element.addEventListener) {
  1384. element.addEventListener(type, handler, false);
  1385. } else {
  1386. if (!handler._d) {
  1387. handler._d = {
  1388. els: []
  1389. };
  1390. }
  1391. var key = type + handler.toString(), index = utils.indexOf(handler._d.els, element);
  1392. if (!handler._d[key] || index == -1) {
  1393. if (index == -1) {
  1394. handler._d.els.push(element);
  1395. }
  1396. if (!handler._d[key]) {
  1397. handler._d[key] = function (evt) {
  1398. return handler.call(evt.srcElement, evt || window.event);
  1399. };
  1400. }
  1401. element.attachEvent('on' + type, handler._d[key]);
  1402. }
  1403. }
  1404. }
  1405. element = null;
  1406. },
  1407. /**
  1408. * 解除原生DOM事件绑定
  1409. * @name un
  1410. * @grammar UE.dom.donUtils.un(element,type,handler) //参见<code><a href="#on">on</a></code>
  1411. */
  1412. un: function (element, type, handler) {
  1413. var types = utils.isArray(type) ? type : [type],
  1414. k = types.length;
  1415. if (k) while (k--) {
  1416. type = types[k];
  1417. if (element.removeEventListener) {
  1418. element.removeEventListener(type, handler, false);
  1419. } else {
  1420. var key = type + handler.toString();
  1421. try {
  1422. element.detachEvent('on' + type, handler._d ? handler._d[key] : handler);
  1423. } catch (e) {
  1424. }
  1425. if (handler._d && handler._d[key]) {
  1426. var index = utils.indexOf(handler._d.els, element);
  1427. if (index != -1) {
  1428. handler._d.els.splice(index, 1);
  1429. }
  1430. handler._d.els.length == 0 && delete handler._d[key];
  1431. }
  1432. }
  1433. }
  1434. },
  1435. /**
  1436. * 比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值
  1437. * @name isSameElement
  1438. * @grammar UE.dom.domUtils.isSameElement(nodeA,nodeB) => true|false
  1439. * @example
  1440. * <span style="font-size:12px">ssss</span> and <span style="font-size:12px">bbbbb</span> => true
  1441. * <span style="font-size:13px">ssss</span> and <span style="font-size:12px">bbbbb</span> => false
  1442. */
  1443. isSameElement: function (nodeA, nodeB) {
  1444. if (nodeA.tagName != nodeB.tagName) {
  1445. return false;
  1446. }
  1447. var thisAttrs = nodeA.attributes,
  1448. otherAttrs = nodeB.attributes;
  1449. if (!ie && thisAttrs.length != otherAttrs.length) {
  1450. return false;
  1451. }
  1452. var attrA, attrB, al = 0, bl = 0;
  1453. for (var i = 0; attrA = thisAttrs[i++];) {
  1454. if (attrA.nodeName == 'style') {
  1455. if (attrA.specified) {
  1456. al++;
  1457. }
  1458. if (domUtils.isSameStyle(nodeA, nodeB)) {
  1459. continue;
  1460. } else {
  1461. return false;
  1462. }
  1463. }
  1464. if (ie) {
  1465. if (attrA.specified) {
  1466. al++;
  1467. attrB = otherAttrs.getNamedItem(attrA.nodeName);
  1468. } else {
  1469. continue;
  1470. }
  1471. } else {
  1472. attrB = nodeB.attributes[attrA.nodeName];
  1473. }
  1474. if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) {
  1475. return false;
  1476. }
  1477. }
  1478. // 有可能attrB的属性包含了attrA的属性之外还有自己的属性
  1479. if (ie) {
  1480. for (i = 0; attrB = otherAttrs[i++];) {
  1481. if (attrB.specified) {
  1482. bl++;
  1483. }
  1484. }
  1485. if (al != bl) {
  1486. return false;
  1487. }
  1488. }
  1489. return true;
  1490. },
  1491. /**
  1492. * 判断节点nodeA与节点nodeB的元素属性是否一致
  1493. * @name isSameStyle
  1494. * @grammar UE.dom.domUtils.isSameStyle(nodeA,nodeB) => true|false
  1495. */
  1496. isSameStyle: function (nodeA, nodeB) {
  1497. var styleA = nodeA.style.cssText.replace(/( ?; ?)/g, ';').replace(/( ?: ?)/g, ':'),
  1498. styleB = nodeB.style.cssText.replace(/( ?; ?)/g, ';').replace(/( ?: ?)/g, ':');
  1499. if (browser.opera) {
  1500. styleA = nodeA.style;
  1501. styleB = nodeB.style;
  1502. if (styleA.length != styleB.length)
  1503. return false;
  1504. for (var p in styleA) {
  1505. if (/^(\d+|csstext)$/i.test(p)) {
  1506. continue;
  1507. }
  1508. if (styleA[p] != styleB[p]) {
  1509. return false;
  1510. }
  1511. }
  1512. return true;
  1513. }
  1514. if (!styleA || !styleB) {
  1515. return styleA == styleB;
  1516. }
  1517. styleA = styleA.split(';');
  1518. styleB = styleB.split(';');
  1519. if (styleA.length != styleB.length) {
  1520. return false;
  1521. }
  1522. for (var i = 0, ci; ci = styleA[i++];) {
  1523. if (utils.indexOf(styleB, ci) == -1) {
  1524. return false;
  1525. }
  1526. }
  1527. return true;
  1528. },
  1529. /**
  1530. * 检查节点node是否为块元素
  1531. * @name isBlockElm
  1532. * @grammar UE.dom.domUtils.isBlockElm(node) => true|false
  1533. */
  1534. isBlockElm: function (node) {
  1535. return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName];
  1536. },
  1537. /**
  1538. * 检测node节点是否为body节点
  1539. * @name isBody
  1540. * @grammar UE.dom.domUtils.isBody(node) => true|false
  1541. */
  1542. isBody: function (node) {
  1543. return node && node.nodeType == 1 && node.tagName.toLowerCase() == 'body';
  1544. },
  1545. /**
  1546. * 以node节点为中心,将该节点的指定祖先节点parent拆分成2块
  1547. * @name breakParent
  1548. * @grammar UE.dom.domUtils.breakParent(node,parent) => node
  1549. * @desc
  1550. * <code type="html"><b>ooo</b>是node节点
  1551. * <p>xxxx<b>ooo</b>xxx</p> ==> <p>xxx</p><b>ooo</b><p>xxx</p>
  1552. * <p>xxxxx<span>xxxx<b>ooo</b>xxxxxx</span></p> => <p>xxxxx<span>xxxx</span></p><b>ooo</b><p><span>xxxxxx</span></p></code>
  1553. */
  1554. breakParent: function (node, parent) {
  1555. var tmpNode,
  1556. parentClone = node,
  1557. clone = node,
  1558. leftNodes,
  1559. rightNodes;
  1560. do {
  1561. parentClone = parentClone.parentNode;
  1562. if (leftNodes) {
  1563. tmpNode = parentClone.cloneNode(false);
  1564. tmpNode.appendChild(leftNodes);
  1565. leftNodes = tmpNode;
  1566. tmpNode = parentClone.cloneNode(false);
  1567. tmpNode.appendChild(rightNodes);
  1568. rightNodes = tmpNode;
  1569. } else {
  1570. leftNodes = parentClone.cloneNode(false);
  1571. rightNodes = leftNodes.cloneNode(false);
  1572. }
  1573. while (tmpNode = clone.previousSibling) {
  1574. leftNodes.insertBefore(tmpNode, leftNodes.firstChild);
  1575. }
  1576. while (tmpNode = clone.nextSibling) {
  1577. rightNodes.appendChild(tmpNode);
  1578. }
  1579. clone = parentClone;
  1580. } while (parent !== parentClone);
  1581. tmpNode = parent.parentNode;
  1582. tmpNode.insertBefore(leftNodes, parent);
  1583. tmpNode.insertBefore(rightNodes, parent);
  1584. tmpNode.insertBefore(node, rightNodes);
  1585. domUtils.remove(parent);
  1586. return node;
  1587. },
  1588. /**
  1589. * 检查节点node是否是空inline节点
  1590. * @name isEmptyInlineElement
  1591. * @grammar UE.dom.domUtils.isEmptyInlineElement(node) => 1|0
  1592. * @example
  1593. * <b><i></i></b> => 1
  1594. * <b><i></i><u></u></b> => 1
  1595. * <b></b> => 1
  1596. * <b>xx<i></i></b> => 0
  1597. */
  1598. isEmptyInlineElement: function (node) {
  1599. if (node.nodeType != 1 || !dtd.$removeEmpty[ node.tagName ]) {
  1600. return 0;
  1601. }
  1602. node = node.firstChild;
  1603. while (node) {
  1604. //如果是创建的bookmark就跳过
  1605. if (domUtils.isBookmarkNode(node)) {
  1606. return 0;
  1607. }
  1608. if (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node) ||
  1609. node.nodeType == 3 && !domUtils.isWhitespace(node)
  1610. ) {
  1611. return 0;
  1612. }
  1613. node = node.nextSibling;
  1614. }
  1615. return 1;
  1616. },
  1617. /**
  1618. * 删除node节点下的左右空白文本子节点
  1619. * @name trimWhiteTextNode
  1620. * @grammar UE.dom.domUtils.trimWhiteTextNode(node)
  1621. */
  1622. trimWhiteTextNode: function (node) {
  1623. function remove(dir) {
  1624. var child;
  1625. while ((child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace(child)) {
  1626. node.removeChild(child);
  1627. }
  1628. }
  1629. remove('firstChild');
  1630. remove('lastChild');
  1631. },
  1632. /**
  1633. * 合并node节点下相同的子节点
  1634. * @name mergeChild
  1635. * @desc
  1636. * UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签
  1637. * @example
  1638. * <p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xx</span></p>
  1639. * ==> UE.dom.domUtils.mergeChild(node,'span')
  1640. * <p><span style="font-size:12px;">xxaaxx</span></p>
  1641. */
  1642. mergeChild: function (node, tagName, attrs) {
  1643. var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase());
  1644. for (var i = 0, ci; ci = list[i++];) {
  1645. if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
  1646. continue;
  1647. }
  1648. //span单独处理
  1649. if (ci.tagName.toLowerCase() == 'span') {
  1650. if (node === ci.parentNode) {
  1651. domUtils.trimWhiteTextNode(node);
  1652. if (node.childNodes.length == 1) {
  1653. node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
  1654. domUtils.remove(ci, true);
  1655. continue;
  1656. }
  1657. }
  1658. ci.style.cssText = node.style.cssText + ';' + ci.style.cssText;
  1659. if (attrs) {
  1660. var style = attrs.style;
  1661. if (style) {
  1662. style = style.split(';');
  1663. for (var j = 0, s; s = style[j++];) {
  1664. ci.style[utils.cssStyleToDomStyle(s.split(':')[0])] = s.split(':')[1];
  1665. }
  1666. }
  1667. }
  1668. if (domUtils.isSameStyle(ci, node)) {
  1669. domUtils.remove(ci, true);
  1670. }
  1671. continue;
  1672. }
  1673. if (domUtils.isSameElement(node, ci)) {
  1674. domUtils.remove(ci, true);
  1675. }
  1676. }
  1677. },
  1678. /**
  1679. * 原生方法getElementsByTagName的封装
  1680. * @name getElementsByTagName
  1681. * @grammar UE.dom.domUtils.getElementsByTagName(node,tagName) => Array //节点集合数组
  1682. */
  1683. getElementsByTagName: function (node, name, filter) {
  1684. if (filter && utils.isString(filter)) {
  1685. var className = filter;
  1686. filter = function (node) {
  1687. return domUtils.hasClass(node, className)
  1688. }
  1689. }
  1690. name = utils.trim(name).replace(/[ ]{2,}/g, ' ').split(' ');
  1691. var arr = [];
  1692. for (var n = 0, ni; ni = name[n++];) {
  1693. var list = node.getElementsByTagName(ni);
  1694. for (var i = 0, ci; ci = list[i++];) {
  1695. if (!filter || filter(ci))
  1696. arr.push(ci);
  1697. }
  1698. }
  1699. return arr;
  1700. },
  1701. /**
  1702. * 将节点node合并到父节点上
  1703. * @name mergeToParent
  1704. * @grammar UE.dom.domUtils.mergeToParent(node)
  1705. * @example
  1706. * <span style="color:#fff"><span style="font-size:12px">xxx</span></span> ==> <span style="color:#fff;font-size:12px">xxx</span>
  1707. */
  1708. mergeToParent: function (node) {
  1709. var parent = node.parentNode;
  1710. while (parent && dtd.$removeEmpty[parent.tagName]) {
  1711. if (parent.tagName == node.tagName || parent.tagName == 'A') {//针对a标签单独处理
  1712. domUtils.trimWhiteTextNode(parent);
  1713. //span需要特殊处理 不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
  1714. if (parent.tagName == 'SPAN' && !domUtils.isSameStyle(parent, node)
  1715. || (parent.tagName == 'A' && node.tagName == 'SPAN')) {
  1716. if (parent.childNodes.length > 1 || parent !== node.parentNode) {
  1717. node.style.cssText = parent.style.cssText + ";" + node.style.cssText;
  1718. parent = parent.parentNode;
  1719. continue;
  1720. } else {
  1721. parent.style.cssText += ";" + node.style.cssText;
  1722. //trace:952 a标签要保持下划线
  1723. if (parent.tagName == 'A') {
  1724. parent.style.textDecoration = 'underline';
  1725. }
  1726. }
  1727. }
  1728. if (parent.tagName != 'A') {
  1729. parent === node.parentNode && domUtils.remove(node, true);
  1730. break;
  1731. }
  1732. }
  1733. parent = parent.parentNode;
  1734. }
  1735. },
  1736. /**
  1737. * 合并节点node的左右兄弟节点
  1738. * @name mergeSibling
  1739. * @grammar UE.dom.domUtils.mergeSibling(node)
  1740. * @grammar UE.dom.domUtils.mergeSibling(node,ignorePre) //ignorePre指定是否忽略左兄弟
  1741. * @grammar UE.dom.domUtils.mergeSibling(node,ignorePre,ignoreNext) //ignoreNext指定是否忽略右兄弟
  1742. * @example
  1743. * <b>xxxx</b><b>ooo</b><b>xxxx</b> ==> <b>xxxxoooxxxx</b>
  1744. */
  1745. mergeSibling: function (node, ignorePre, ignoreNext) {
  1746. function merge(rtl, start, node) {
  1747. var next;
  1748. if ((next = node[rtl]) && !domUtils.isBookmarkNode(next) && next.nodeType == 1 && domUtils.isSameElement(node, next)) {
  1749. while (next.firstChild) {
  1750. if (start == 'firstChild') {
  1751. node.insertBefore(next.lastChild, node.firstChild);
  1752. } else {
  1753. node.appendChild(next.firstChild);
  1754. }
  1755. }
  1756. domUtils.remove(next);
  1757. }
  1758. }
  1759. !ignorePre && merge('previousSibling', 'firstChild', node);
  1760. !ignoreNext && merge('nextSibling', 'lastChild', node);
  1761. },
  1762. /**
  1763. * 设置节点node及其子节点不会被选中
  1764. * @name unSelectable
  1765. * @grammar UE.dom.domUtils.unSelectable(node)
  1766. */
  1767. unSelectable: ie || browser.opera ? function (node) {
  1768. //for ie9
  1769. node.onselectstart = function () {
  1770. return false;
  1771. };
  1772. node.onclick = node.onkeyup = node.onkeydown = function () {
  1773. return false;
  1774. };
  1775. node.unselectable = 'on';
  1776. node.setAttribute("unselectable", "on");
  1777. for (var i = 0, ci; ci = node.all[i++];) {
  1778. switch (ci.tagName.toLowerCase()) {
  1779. case 'iframe' :
  1780. case 'textarea' :
  1781. case 'input' :
  1782. case 'select' :
  1783. break;
  1784. default :
  1785. ci.unselectable = 'on';
  1786. node.setAttribute("unselectable", "on");
  1787. }
  1788. }
  1789. } : function (node) {
  1790. node.style.MozUserSelect =
  1791. node.style.webkitUserSelect =
  1792. node.style.KhtmlUserSelect = 'none';
  1793. },
  1794. /**
  1795. * 删除节点node上的属性attrNames,attrNames为属性名称数组
  1796. * @name removeAttributes
  1797. * @grammar UE.dom.domUtils.removeAttributes(node,attrNames)
  1798. * @example
  1799. * //Before remove
  1800. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  1801. * //Remove
  1802. * UE.dom.domUtils.removeAttributes(node,["id","name"]);
  1803. * //After remove
  1804. * <span style="font-size:14px;">xxxxx</span>
  1805. */
  1806. removeAttributes: function (node, attrNames) {
  1807. attrNames = utils.isArray(attrNames) ? attrNames : utils.trim(attrNames).replace(/[ ]{2,}/g, ' ').split(' ');
  1808. for (var i = 0, ci; ci = attrNames[i++];) {
  1809. ci = attrFix[ci] || ci;
  1810. switch (ci) {
  1811. case 'className':
  1812. node[ci] = '';
  1813. break;
  1814. case 'style':
  1815. node.style.cssText = '';
  1816. if (node.getAttributeNode('style') !== null) {
  1817. !browser.ie && node.removeAttributeNode(node.getAttributeNode('style'))
  1818. }
  1819. }
  1820. node.removeAttribute(ci);
  1821. }
  1822. },
  1823. /**
  1824. * 在doc下创建一个标签名为tag,属性为attrs的元素
  1825. * @name createElement
  1826. * @grammar UE.dom.domUtils.createElement(doc,tag,attrs) => Node //返回创建的节点
  1827. */
  1828. createElement: function (doc, tag, attrs) {
  1829. return domUtils.setAttributes(doc.createElement(tag), attrs)
  1830. },
  1831. /**
  1832. * 为节点node添加属性attrs,attrs为属性键值对
  1833. * @name setAttributes
  1834. * @grammar UE.dom.domUtils.setAttributes(node,attrs) => node
  1835. */
  1836. setAttributes: function (node, attrs) {
  1837. for (var attr in attrs) {
  1838. if (attrs.hasOwnProperty(attr)) {
  1839. var value = attrs[attr];
  1840. switch (attr) {
  1841. case 'class':
  1842. //ie下要这样赋值,setAttribute不起作用
  1843. node.className = value;
  1844. break;
  1845. case 'style' :
  1846. node.style.cssText = node.style.cssText + ";" + value;
  1847. break;
  1848. case 'innerHTML':
  1849. node[attr] = value;
  1850. break;
  1851. case 'value':
  1852. node.value = value;
  1853. break;
  1854. default:
  1855. node.setAttribute(attrFix[attr] || attr, value);
  1856. }
  1857. }
  1858. }
  1859. return node;
  1860. },
  1861. /**
  1862. * 获取元素element的计算样式
  1863. * @name getComputedStyle
  1864. * @grammar UE.dom.domUtils.getComputedStyle(element,styleName) => String //返回对应样式名称的样式值
  1865. * @example
  1866. * getComputedStyle(document.body,"font-size") => "15px"
  1867. * getComputedStyle(form,"color") => "#ffccdd"
  1868. */
  1869. getComputedStyle: function (element, styleName) {
  1870. //一下的属性单独处理
  1871. var pros = 'width height top left';
  1872. if (pros.indexOf(styleName) > -1) {
  1873. return element['offset' + styleName.replace(/^\w/, function (s) {
  1874. return s.toUpperCase()
  1875. })] + 'px';
  1876. }
  1877. //忽略文本节点
  1878. if (element.nodeType == 3) {
  1879. element = element.parentNode;
  1880. }
  1881. //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改.
  1882. if (browser.ie && browser.version < 9 && styleName == 'font-size' && !element.style.fontSize && !dtd.$empty[element.tagName] && !dtd.$nonChild[element.tagName]) {
  1883. var span = element.ownerDocument.createElement('span');
  1884. span.style.cssText = 'padding:0;border:0;font-family:simsun;';
  1885. span.innerHTML = '.';
  1886. element.appendChild(span);
  1887. var result = span.offsetHeight;
  1888. element.removeChild(span);
  1889. span = null;
  1890. return result + 'px';
  1891. }
  1892. try {
  1893. var value = domUtils.getStyle(element, styleName) ||
  1894. (window.getComputedStyle ? domUtils.getWindow(element).getComputedStyle(element, '').getPropertyValue(styleName) :
  1895. ( element.currentStyle || element.style )[utils.cssStyleToDomStyle(styleName)]);
  1896. } catch (e) {
  1897. return "";
  1898. }
  1899. return utils.transUnitToPx(utils.fixColor(styleName, value));
  1900. },
  1901. /**
  1902. * 在元素element上删除classNames,支持同时删除多个
  1903. * @name removeClasses
  1904. * @grammar UE.dom.domUtils.removeClasses(element,classNames)
  1905. * @example
  1906. * //执行方法前的dom结构
  1907. * <span class="test1 test2 test3">xxx</span>
  1908. * //执行方法
  1909. * UE.dom.domUtils.removeClasses(element,["test1","test3"])
  1910. * //执行方法后的dom结构
  1911. * <span class="test2">xxx</span>
  1912. */
  1913. removeClasses: function (elm, classNames) {
  1914. classNames = utils.isArray(classNames) ? classNames :
  1915. utils.trim(classNames).replace(/[ ]{2,}/g, ' ').split(' ');
  1916. for (var i = 0, ci, cls = elm.className; ci = classNames[i++];) {
  1917. cls = cls.replace(new RegExp('\\b' + ci + '\\b'), '')
  1918. }
  1919. cls = utils.trim(cls).replace(/[ ]{2,}/g, ' ');
  1920. if (cls) {
  1921. elm.className = cls;
  1922. } else {
  1923. domUtils.removeAttributes(elm, ['class']);
  1924. }
  1925. },
  1926. /**
  1927. * 在元素element上增加一个样式类className,支持以空格分开的多个类名
  1928. * 如果相同的类名将不会添加
  1929. * @name addClass
  1930. * @grammar UE.dom.domUtils.addClass(element,classNames)
  1931. */
  1932. addClass: function (elm, classNames) {
  1933. if (!elm)return;
  1934. classNames = utils.trim(classNames).replace(/[ ]{2,}/g, ' ').split(' ');
  1935. for (var i = 0, ci, cls = elm.className; ci = classNames[i++];) {
  1936. if (!new RegExp('\\b' + ci + '\\b').test(cls)) {
  1937. elm.className += ' ' + ci;
  1938. }
  1939. }
  1940. },
  1941. /**
  1942. * 判断元素element是否包含样式类名className,支持以空格分开的多个类名,多个类名顺序不同也可以比较
  1943. * @name hasClass
  1944. * @grammar UE.dom.domUtils.hasClass(element,className) =>true|false
  1945. */
  1946. hasClass: function (element, className) {
  1947. if (utils.isRegExp(className)) {
  1948. return className.test(element.className)
  1949. }
  1950. className = utils.trim(className).replace(/[ ]{2,}/g, ' ').split(' ');
  1951. for (var i = 0, ci, cls = element.className; ci = className[i++];) {
  1952. if (!new RegExp('\\b' + ci + '\\b', 'i').test(cls)) {
  1953. return false;
  1954. }
  1955. }
  1956. return i - 1 == className.length;
  1957. },
  1958. /**
  1959. * 阻止事件默认行为
  1960. * @param {Event} evt 需要组织的事件对象
  1961. */
  1962. preventDefault: function (evt) {
  1963. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  1964. },
  1965. /**
  1966. * 删除元素element的样式
  1967. * @grammar UE.dom.domUtils.removeStyle(element,name) 删除的样式名称
  1968. */
  1969. removeStyle: function (element, name) {
  1970. if (browser.ie) {
  1971. //针对color先单独处理一下
  1972. if (name == 'color') {
  1973. name = '(^|;)' + name;
  1974. }
  1975. element.style.cssText = element.style.cssText.replace(new RegExp(name + '[^:]*:[^;]+;?', 'ig'), '')
  1976. } else {
  1977. if (element.style.removeProperty) {
  1978. element.style.removeProperty(name);
  1979. } else {
  1980. element.style.removeAttribute(utils.cssStyleToDomStyle(name));
  1981. }
  1982. }
  1983. if (!element.style.cssText) {
  1984. domUtils.removeAttributes(element, ['style']);
  1985. }
  1986. },
  1987. /**
  1988. * 获取元素element的某个样式值
  1989. * @name getStyle
  1990. * @grammar UE.dom.domUtils.getStyle(element,name) => String
  1991. */
  1992. getStyle: function (element, name) {
  1993. var value = element.style[ utils.cssStyleToDomStyle(name) ];
  1994. return utils.fixColor(name, value);
  1995. },
  1996. /**
  1997. * 为元素element设置样式属性值
  1998. * @name setStyle
  1999. * @grammar UE.dom.domUtils.setStyle(element,name,value)
  2000. */
  2001. setStyle: function (element, name, value) {
  2002. element.style[utils.cssStyleToDomStyle(name)] = value;
  2003. if (!utils.trim(element.style.cssText)) {
  2004. this.removeAttributes(element, 'style')
  2005. }
  2006. },
  2007. /**
  2008. * 为元素element设置样式属性值
  2009. * @name setStyles
  2010. * @grammar UE.dom.domUtils.setStyle(element,styles) //styles为样式键值对
  2011. */
  2012. setStyles: function (element, styles) {
  2013. for (var name in styles) {
  2014. if (styles.hasOwnProperty(name)) {
  2015. domUtils.setStyle(element, name, styles[name]);
  2016. }
  2017. }
  2018. },
  2019. /**
  2020. * 删除_moz_dirty属性
  2021. * @function
  2022. */
  2023. removeDirtyAttr: function (node) {
  2024. for (var i = 0, ci, nodes = node.getElementsByTagName('*'); ci = nodes[i++];) {
  2025. ci.removeAttribute('_moz_dirty');
  2026. }
  2027. node.removeAttribute('_moz_dirty');
  2028. },
  2029. /**
  2030. * 返回子节点的数量
  2031. * @function
  2032. * @param {Node} node 父节点
  2033. * @param {Function} fn 过滤子节点的规则,若为空,则得到所有子节点的数量
  2034. * @return {Number} 符合条件子节点的数量
  2035. */
  2036. getChildCount: function (node, fn) {
  2037. var count = 0, first = node.firstChild;
  2038. fn = fn || function () {
  2039. return 1;
  2040. };
  2041. while (first) {
  2042. if (fn(first)) {
  2043. count++;
  2044. }
  2045. first = first.nextSibling;
  2046. }
  2047. return count;
  2048. },
  2049. /**
  2050. * 判断是否为空节点
  2051. * @function
  2052. * @param {Node} node 节点
  2053. * @return {Boolean} 是否为空节点
  2054. */
  2055. isEmptyNode: function (node) {
  2056. return !node.firstChild || domUtils.getChildCount(node, function (node) {
  2057. return !domUtils.isBr(node) && !domUtils.isBookmarkNode(node) && !domUtils.isWhitespace(node)
  2058. }) == 0
  2059. },
  2060. /**
  2061. * 清空节点所有的className
  2062. * @function
  2063. * @param {Array} nodes 节点数组
  2064. */
  2065. clearSelectedArr: function (nodes) {
  2066. var node;
  2067. while (node = nodes.pop()) {
  2068. domUtils.removeAttributes(node, ['class']);
  2069. }
  2070. },
  2071. /**
  2072. * 将显示区域滚动到显示节点的位置
  2073. * @function
  2074. * @param {Node} node 节点
  2075. * @param {window} win window对象
  2076. * @param {Number} offsetTop 距离上方的偏移量
  2077. */
  2078. scrollToView: function (node, win, offsetTop) {
  2079. var getViewPaneSize = function () {
  2080. var doc = win.document,
  2081. mode = doc.compatMode == 'CSS1Compat';
  2082. return {
  2083. width: ( mode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
  2084. height: ( mode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
  2085. };
  2086. },
  2087. getScrollPosition = function (win) {
  2088. if ('pageXOffset' in win) {
  2089. return {
  2090. x: win.pageXOffset || 0,
  2091. y: win.pageYOffset || 0
  2092. };
  2093. }
  2094. else {
  2095. var doc = win.document;
  2096. return {
  2097. x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
  2098. y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
  2099. };
  2100. }
  2101. };
  2102. var winHeight = getViewPaneSize().height, offset = winHeight * -1 + offsetTop;
  2103. offset += (node.offsetHeight || 0);
  2104. var elementPosition = domUtils.getXY(node);
  2105. offset += elementPosition.y;
  2106. var currentScroll = getScrollPosition(win).y;
  2107. // offset += 50;
  2108. if (offset > currentScroll || offset < currentScroll - winHeight) {
  2109. win.scrollTo(0, offset + (offset < 0 ? -20 : 20));
  2110. }
  2111. },
  2112. /**
  2113. * 判断节点是否为br
  2114. * @function
  2115. * @param {Node} node 节点
  2116. */
  2117. isBr: function (node) {
  2118. return node.nodeType == 1 && node.tagName == 'BR';
  2119. },
  2120. isFillChar: function (node, isInStart) {
  2121. return node.nodeType == 3 && !node.nodeValue.replace(new RegExp((isInStart ? '^' : '' ) + domUtils.fillChar), '').length
  2122. },
  2123. isStartInblock: function (range) {
  2124. var tmpRange = range.cloneRange(),
  2125. flag = 0,
  2126. start = tmpRange.startContainer,
  2127. tmp;
  2128. if (start.nodeType == 1 && start.childNodes[tmpRange.startOffset]) {
  2129. start = start.childNodes[tmpRange.startOffset];
  2130. var pre = start.previousSibling;
  2131. while (pre && domUtils.isFillChar(pre)) {
  2132. start = pre;
  2133. pre = pre.previousSibling;
  2134. }
  2135. }
  2136. if (this.isFillChar(start, true) && tmpRange.startOffset == 1) {
  2137. tmpRange.setStartBefore(start);
  2138. start = tmpRange.startContainer;
  2139. }
  2140. while (start && domUtils.isFillChar(start)) {
  2141. tmp = start;
  2142. start = start.previousSibling
  2143. }
  2144. if (tmp) {
  2145. tmpRange.setStartBefore(tmp);
  2146. start = tmpRange.startContainer;
  2147. }
  2148. if (start.nodeType == 1 && domUtils.isEmptyNode(start) && tmpRange.startOffset == 1) {
  2149. tmpRange.setStart(start, 0).collapse(true);
  2150. }
  2151. while (!tmpRange.startOffset) {
  2152. start = tmpRange.startContainer;
  2153. if (domUtils.isBlockElm(start) || domUtils.isBody(start)) {
  2154. flag = 1;
  2155. break;
  2156. }
  2157. var pre = tmpRange.startContainer.previousSibling,
  2158. tmpNode;
  2159. if (!pre) {
  2160. tmpRange.setStartBefore(tmpRange.startContainer);
  2161. } else {
  2162. while (pre && domUtils.isFillChar(pre)) {
  2163. tmpNode = pre;
  2164. pre = pre.previousSibling;
  2165. }
  2166. if (tmpNode) {
  2167. tmpRange.setStartBefore(tmpNode);
  2168. } else {
  2169. tmpRange.setStartBefore(tmpRange.startContainer);
  2170. }
  2171. }
  2172. }
  2173. return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0;
  2174. },
  2175. isEmptyBlock: function (node, reg) {
  2176. if (node.nodeType != 1)
  2177. return 0;
  2178. reg = reg || new RegExp('[ \t\r\n' + domUtils.fillChar + ']', 'g');
  2179. if (node[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').length > 0) {
  2180. return 0;
  2181. }
  2182. for (var n in dtd.$isNotEmpty) {
  2183. if (node.getElementsByTagName(n).length) {
  2184. return 0;
  2185. }
  2186. }
  2187. return 1;
  2188. },
  2189. setViewportOffset: function (element, offset) {
  2190. var left = parseInt(element.style.left) | 0;
  2191. var top = parseInt(element.style.top) | 0;
  2192. var rect = element.getBoundingClientRect();
  2193. var offsetLeft = offset.left - rect.left;
  2194. var offsetTop = offset.top - rect.top;
  2195. if (offsetLeft) {
  2196. element.style.left = left + offsetLeft + 'px';
  2197. }
  2198. if (offsetTop) {
  2199. element.style.top = top + offsetTop + 'px';
  2200. }
  2201. },
  2202. fillNode: function (doc, node) {
  2203. var tmpNode = browser.ie ? doc.createTextNode(domUtils.fillChar) : doc.createElement('br');
  2204. node.innerHTML = '';
  2205. node.appendChild(tmpNode);
  2206. },
  2207. moveChild: function (src, tag, dir) {
  2208. while (src.firstChild) {
  2209. if (dir && tag.firstChild) {
  2210. tag.insertBefore(src.lastChild, tag.firstChild);
  2211. } else {
  2212. tag.appendChild(src.firstChild);
  2213. }
  2214. }
  2215. },
  2216. //判断是否有额外属性
  2217. hasNoAttributes: function (node) {
  2218. return browser.ie ? /^<\w+\s*?>/.test(node.outerHTML) : node.attributes.length == 0;
  2219. },
  2220. //判断是否是编辑器自定义的参数
  2221. isCustomeNode: function (node) {
  2222. return node.nodeType == 1 && node.getAttribute('_ue_custom_node_');
  2223. },
  2224. isTagNode: function (node, tagName) {
  2225. return node.nodeType == 1 && new RegExp('^' + node.tagName + '$', 'i').test(tagName)
  2226. },
  2227. /**
  2228. * 对于nodelist用filter进行过滤
  2229. * @name filterNodeList
  2230. * @since 1.2.4+
  2231. * @grammar UE.dom.domUtils.filterNodeList(nodelist,filter,onlyFirst) => 节点
  2232. * @example
  2233. * UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),'div p') //返回第一个是div或者p的节点
  2234. * UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),function(n){return n.getAttribute('src')})
  2235. * //返回第一个带src属性的节点
  2236. * UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),'i',true) //返回数组,里边都是i节点
  2237. */
  2238. filterNodeList: function (nodelist, filter, forAll) {
  2239. var results = [];
  2240. if (!utils.isFunction(filter)) {
  2241. var str = filter;
  2242. filter = function (n) {
  2243. return utils.indexOf(utils.isArray(str) ? str : str.split(' '), n.tagName.toLowerCase()) != -1
  2244. };
  2245. }
  2246. utils.each(nodelist, function (n) {
  2247. filter(n) && results.push(n)
  2248. });
  2249. return results.length == 0 ? null : results.length == 1 || !forAll ? results[0] : results
  2250. },
  2251. isInNodeEndBoundary: function (rng, node) {
  2252. var start = rng.startContainer;
  2253. if (start.nodeType == 3 && rng.startOffset != start.nodeValue.length) {
  2254. return 0;
  2255. }
  2256. if (start.nodeType == 1 && rng.startOffset != start.childNodes.length) {
  2257. return 0;
  2258. }
  2259. while (start !== node) {
  2260. if (start.nextSibling) {
  2261. return 0
  2262. }
  2263. ;
  2264. start = start.parentNode;
  2265. }
  2266. return 1;
  2267. },
  2268. isBoundaryNode: function (node, dir) {
  2269. var tmp;
  2270. while (!domUtils.isBody(node)) {
  2271. tmp = node;
  2272. node = node.parentNode;
  2273. if (tmp !== node[dir]) {
  2274. return false;
  2275. }
  2276. }
  2277. return true;
  2278. }
  2279. };
  2280. var fillCharReg = new RegExp(domUtils.fillChar, 'g');
  2281. ///import editor.js
  2282. ///import core/utils.js
  2283. ///import core/browser.js
  2284. ///import core/dom/dom.js
  2285. ///import core/dom/dtd.js
  2286. ///import core/dom/domUtils.js
  2287. /**
  2288. * @file
  2289. * @name UE.dom.Range
  2290. * @anthor zhanyi
  2291. * @short Range
  2292. * @import editor.js,core/utils.js,core/browser.js,core/dom/domUtils.js,core/dom/dtd.js
  2293. * @desc Range范围实现类,本类是UEditor底层核心类,统一w3cRange和ieRange之间的差异,包括接口和属性
  2294. */
  2295. (function () {
  2296. var guid = 0,
  2297. fillChar = domUtils.fillChar,
  2298. fillData;
  2299. /**
  2300. * 更新range的collapse状态
  2301. * @param {Range} range range对象
  2302. */
  2303. function updateCollapse(range) {
  2304. range.collapsed =
  2305. range.startContainer && range.endContainer &&
  2306. range.startContainer === range.endContainer &&
  2307. range.startOffset == range.endOffset;
  2308. }
  2309. function selectOneNode(rng) {
  2310. return !rng.collapsed && rng.startContainer.nodeType == 1 && rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset == 1
  2311. }
  2312. function setEndPoint(toStart, node, offset, range) {
  2313. //如果node是自闭合标签要处理
  2314. if (node.nodeType == 1 && (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])) {
  2315. offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1);
  2316. node = node.parentNode;
  2317. }
  2318. if (toStart) {
  2319. range.startContainer = node;
  2320. range.startOffset = offset;
  2321. if (!range.endContainer) {
  2322. range.collapse(true);
  2323. }
  2324. } else {
  2325. range.endContainer = node;
  2326. range.endOffset = offset;
  2327. if (!range.startContainer) {
  2328. range.collapse(false);
  2329. }
  2330. }
  2331. updateCollapse(range);
  2332. return range;
  2333. }
  2334. function execContentsAction(range, action) {
  2335. //调整边界
  2336. //range.includeBookmark();
  2337. var start = range.startContainer,
  2338. end = range.endContainer,
  2339. startOffset = range.startOffset,
  2340. endOffset = range.endOffset,
  2341. doc = range.document,
  2342. frag = doc.createDocumentFragment(),
  2343. tmpStart, tmpEnd;
  2344. if (start.nodeType == 1) {
  2345. start = start.childNodes[startOffset] || (tmpStart = start.appendChild(doc.createTextNode('')));
  2346. }
  2347. if (end.nodeType == 1) {
  2348. end = end.childNodes[endOffset] || (tmpEnd = end.appendChild(doc.createTextNode('')));
  2349. }
  2350. if (start === end && start.nodeType == 3) {
  2351. frag.appendChild(doc.createTextNode(start.substringData(startOffset, endOffset - startOffset)));
  2352. //is not clone
  2353. if (action) {
  2354. start.deleteData(startOffset, endOffset - startOffset);
  2355. range.collapse(true);
  2356. }
  2357. return frag;
  2358. }
  2359. var current, currentLevel, clone = frag,
  2360. startParents = domUtils.findParents(start, true), endParents = domUtils.findParents(end, true);
  2361. for (var i = 0; startParents[i] == endParents[i];) {
  2362. i++;
  2363. }
  2364. for (var j = i, si; si = startParents[j]; j++) {
  2365. current = si.nextSibling;
  2366. if (si == start) {
  2367. if (!tmpStart) {
  2368. if (range.startContainer.nodeType == 3) {
  2369. clone.appendChild(doc.createTextNode(start.nodeValue.slice(startOffset)));
  2370. //is not clone
  2371. if (action) {
  2372. start.deleteData(startOffset, start.nodeValue.length - startOffset);
  2373. }
  2374. } else {
  2375. clone.appendChild(!action ? start.cloneNode(true) : start);
  2376. }
  2377. }
  2378. } else {
  2379. currentLevel = si.cloneNode(false);
  2380. clone.appendChild(currentLevel);
  2381. }
  2382. while (current) {
  2383. if (current === end || current === endParents[j]) {
  2384. break;
  2385. }
  2386. si = current.nextSibling;
  2387. clone.appendChild(!action ? current.cloneNode(true) : current);
  2388. current = si;
  2389. }
  2390. clone = currentLevel;
  2391. }
  2392. clone = frag;
  2393. if (!startParents[i]) {
  2394. clone.appendChild(startParents[i - 1].cloneNode(false));
  2395. clone = clone.firstChild;
  2396. }
  2397. for (var j = i, ei; ei = endParents[j]; j++) {
  2398. current = ei.previousSibling;
  2399. if (ei == end) {
  2400. if (!tmpEnd && range.endContainer.nodeType == 3) {
  2401. clone.appendChild(doc.createTextNode(end.substringData(0, endOffset)));
  2402. //is not clone
  2403. if (action) {
  2404. end.deleteData(0, endOffset);
  2405. }
  2406. }
  2407. } else {
  2408. currentLevel = ei.cloneNode(false);
  2409. clone.appendChild(currentLevel);
  2410. }
  2411. //如果两端同级,右边第一次已经被开始做了
  2412. if (j != i || !startParents[i]) {
  2413. while (current) {
  2414. if (current === start) {
  2415. break;
  2416. }
  2417. ei = current.previousSibling;
  2418. clone.insertBefore(!action ? current.cloneNode(true) : current, clone.firstChild);
  2419. current = ei;
  2420. }
  2421. }
  2422. clone = currentLevel;
  2423. }
  2424. if (action) {
  2425. range.setStartBefore(!endParents[i] ? endParents[i - 1] : !startParents[i] ? startParents[i - 1] : endParents[i]).collapse(true);
  2426. }
  2427. tmpStart && domUtils.remove(tmpStart);
  2428. tmpEnd && domUtils.remove(tmpEnd);
  2429. return frag;
  2430. }
  2431. /**
  2432. * @name Range
  2433. * @grammar new UE.dom.Range(document) => Range 实例
  2434. * @desc 创建一个跟document绑定的空的Range实例
  2435. * - ***startContainer*** 开始边界的容器节点,可以是elementNode或者是textNode
  2436. * - ***startOffset*** 容器节点中的偏移量,如果是elementNode就是childNodes中的第几个,如果是textNode就是nodeValue的第几个字符
  2437. * - ***endContainer*** 结束边界的容器节点,可以是elementNode或者是textNode
  2438. * - ***endOffset*** 容器节点中的偏移量,如果是elementNode就是childNodes中的第几个,如果是textNode就是nodeValue的第几个字符
  2439. * - ***document*** 跟range关联的document对象
  2440. * - ***collapsed*** 是否是闭合状态
  2441. */
  2442. var Range = dom.Range = function (document) {
  2443. var me = this;
  2444. me.startContainer =
  2445. me.startOffset =
  2446. me.endContainer =
  2447. me.endOffset = null;
  2448. me.document = document;
  2449. me.collapsed = true;
  2450. };
  2451. /**
  2452. * 删除fillData
  2453. * @param doc
  2454. * @param excludeNode
  2455. */
  2456. function removeFillData(doc, excludeNode) {
  2457. try {
  2458. if (fillData && domUtils.inDoc(fillData, doc)) {
  2459. if (!fillData.nodeValue.replace(fillCharReg, '').length) {
  2460. var tmpNode = fillData.parentNode;
  2461. domUtils.remove(fillData);
  2462. while (tmpNode && domUtils.isEmptyInlineElement(tmpNode) &&
  2463. //safari的contains有bug
  2464. (browser.safari ? !(domUtils.getPosition(tmpNode, excludeNode) & domUtils.POSITION_CONTAINS) : !tmpNode.contains(excludeNode))
  2465. ) {
  2466. fillData = tmpNode.parentNode;
  2467. domUtils.remove(tmpNode);
  2468. tmpNode = fillData;
  2469. }
  2470. } else {
  2471. fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, '');
  2472. }
  2473. }
  2474. } catch (e) {
  2475. }
  2476. }
  2477. /**
  2478. *
  2479. * @param node
  2480. * @param dir
  2481. */
  2482. function mergeSibling(node, dir) {
  2483. var tmpNode;
  2484. node = node[dir];
  2485. while (node && domUtils.isFillChar(node)) {
  2486. tmpNode = node[dir];
  2487. domUtils.remove(node);
  2488. node = tmpNode;
  2489. }
  2490. }
  2491. Range.prototype = {
  2492. /**
  2493. * @name cloneContents
  2494. * @grammar range.cloneContents() => DocumentFragment
  2495. * @desc 克隆选中的内容到一个fragment里,如果选区是空的将返回null
  2496. */
  2497. cloneContents: function () {
  2498. return this.collapsed ? null : execContentsAction(this, 0);
  2499. },
  2500. /**
  2501. * @name deleteContents
  2502. * @grammar range.deleteContents() => Range
  2503. * @desc 删除当前选区范围中的所有内容并返回range实例,这时的range已经变成了闭合状态
  2504. * @example
  2505. * DOM Element :
  2506. * <b>x<i>x[x<i>xx]x</b>
  2507. * //执行方法后
  2508. * <b>x<i>x<i>|x</b>
  2509. * 注意range改变了
  2510. * range.startContainer => b
  2511. * range.startOffset => 2
  2512. * range.endContainer => b
  2513. * range.endOffset => 2
  2514. * range.collapsed => true
  2515. */
  2516. deleteContents: function () {
  2517. var txt;
  2518. if (!this.collapsed) {
  2519. execContentsAction(this, 1);
  2520. }
  2521. if (browser.webkit) {
  2522. txt = this.startContainer;
  2523. if (txt.nodeType == 3 && !txt.nodeValue.length) {
  2524. this.setStartBefore(txt).collapse(true);
  2525. domUtils.remove(txt);
  2526. }
  2527. }
  2528. return this;
  2529. },
  2530. /**
  2531. * @name extractContents
  2532. * @grammar range.extractContents() => DocumentFragment
  2533. * @desc 将当前的内容放到一个fragment里并返回这个fragment,这时的range已经变成了闭合状态
  2534. * @example
  2535. * DOM Element :
  2536. * <b>x<i>x[x<i>xx]x</b>
  2537. * //执行方法后
  2538. * 返回的fragment里的 dom结构是
  2539. * <i>x<i>xx
  2540. * dom树上的结构是
  2541. * <b>x<i>x<i>|x</b>
  2542. * 注意range改变了
  2543. * range.startContainer => b
  2544. * range.startOffset => 2
  2545. * range.endContainer => b
  2546. * range.endOffset => 2
  2547. * range.collapsed => true
  2548. */
  2549. extractContents: function () {
  2550. return this.collapsed ? null : execContentsAction(this, 2);
  2551. },
  2552. /**
  2553. * @name setStart
  2554. * @grammar range.setStart(node,offset) => Range
  2555. * @desc 设置range的开始位置位于node节点内,偏移量为offset
  2556. * 如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符
  2557. */
  2558. setStart: function (node, offset) {
  2559. return setEndPoint(true, node, offset, this);
  2560. },
  2561. /**
  2562. * 设置range的结束位置位于node节点,偏移量为offset
  2563. * 如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符
  2564. * @name setEnd
  2565. * @grammar range.setEnd(node,offset) => Range
  2566. */
  2567. setEnd: function (node, offset) {
  2568. return setEndPoint(false, node, offset, this);
  2569. },
  2570. /**
  2571. * 将Range开始位置设置到node节点之后
  2572. * @name setStartAfter
  2573. * @grammar range.setStartAfter(node) => Range
  2574. * @example
  2575. * <b>xx<i>x|x</i>x</b>
  2576. * 执行setStartAfter(i)后
  2577. * range.startContainer =>b
  2578. * range.startOffset =>2
  2579. */
  2580. setStartAfter: function (node) {
  2581. return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1);
  2582. },
  2583. /**
  2584. * 将Range开始位置设置到node节点之前
  2585. * @name setStartBefore
  2586. * @grammar range.setStartBefore(node) => Range
  2587. * @example
  2588. * <b>xx<i>x|x</i>x</b>
  2589. * 执行setStartBefore(i)后
  2590. * range.startContainer =>b
  2591. * range.startOffset =>1
  2592. */
  2593. setStartBefore: function (node) {
  2594. return this.setStart(node.parentNode, domUtils.getNodeIndex(node));
  2595. },
  2596. /**
  2597. * 将Range结束位置设置到node节点之后
  2598. * @name setEndAfter
  2599. * @grammar range.setEndAfter(node) => Range
  2600. * @example
  2601. * <b>xx<i>x|x</i>x</b>
  2602. * setEndAfter(i)后
  2603. * range.endContainer =>b
  2604. * range.endtOffset =>2
  2605. */
  2606. setEndAfter: function (node) {
  2607. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1);
  2608. },
  2609. /**
  2610. * 将Range结束位置设置到node节点之前
  2611. * @name setEndBefore
  2612. * @grammar range.setEndBefore(node) => Range
  2613. * @example
  2614. * <b>xx<i>x|x</i>x</b>
  2615. * 执行setEndBefore(i)后
  2616. * range.endContainer =>b
  2617. * range.endtOffset =>1
  2618. */
  2619. setEndBefore: function (node) {
  2620. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node));
  2621. },
  2622. /**
  2623. * 将Range开始位置设置到node节点内的开始位置
  2624. * @name setStartAtFirst
  2625. * @grammar range.setStartAtFirst(node) => Range
  2626. */
  2627. setStartAtFirst: function (node) {
  2628. return this.setStart(node, 0);
  2629. },
  2630. /**
  2631. * 将Range开始位置设置到node节点内的结束位置
  2632. * @name setStartAtLast
  2633. * @grammar range.setStartAtLast(node) => Range
  2634. */
  2635. setStartAtLast: function (node) {
  2636. return this.setStart(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length);
  2637. },
  2638. /**
  2639. * 将Range结束位置设置到node节点内的开始位置
  2640. * @name setEndAtFirst
  2641. * @grammar range.setEndAtFirst(node) => Range
  2642. */
  2643. setEndAtFirst: function (node) {
  2644. return this.setEnd(node, 0);
  2645. },
  2646. /**
  2647. * 将Range结束位置设置到node节点内的结束位置
  2648. * @name setEndAtLast
  2649. * @grammar range.setEndAtLast(node) => Range
  2650. */
  2651. setEndAtLast: function (node) {
  2652. return this.setEnd(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length);
  2653. },
  2654. /**
  2655. * 选中完整的指定节点,并返回包含该节点的range
  2656. * @name selectNode
  2657. * @grammar range.selectNode(node) => Range
  2658. */
  2659. selectNode: function (node) {
  2660. return this.setStartBefore(node).setEndAfter(node);
  2661. },
  2662. /**
  2663. * 选中node内部的所有节点,并返回对应的range
  2664. * @name selectNodeContents
  2665. * @grammar range.selectNodeContents(node) => Range
  2666. * @example
  2667. * <b>xx[x<i>xxx</i>]xxx</b>
  2668. * 执行后
  2669. * <b>[xxx<i>xxx</i>xxx]</b>
  2670. * range.startContainer =>b
  2671. * range.startOffset =>0
  2672. * range.endContainer =>b
  2673. * range.endOffset =>3
  2674. */
  2675. selectNodeContents: function (node) {
  2676. return this.setStart(node, 0).setEndAtLast(node);
  2677. },
  2678. /**
  2679. * 克隆一个新的range对象
  2680. * @name cloneRange
  2681. * @grammar range.cloneRange() => Range
  2682. */
  2683. cloneRange: function () {
  2684. var me = this;
  2685. return new Range(me.document).setStart(me.startContainer, me.startOffset).setEnd(me.endContainer, me.endOffset);
  2686. },
  2687. /**
  2688. * 让选区闭合到尾部,若toStart为真,则闭合到头部
  2689. * @name collapse
  2690. * @grammar range.collapse() => Range
  2691. * @grammar range.collapse(true) => Range //闭合选区到头部
  2692. */
  2693. collapse: function (toStart) {
  2694. var me = this;
  2695. if (toStart) {
  2696. me.endContainer = me.startContainer;
  2697. me.endOffset = me.startOffset;
  2698. } else {
  2699. me.startContainer = me.endContainer;
  2700. me.startOffset = me.endOffset;
  2701. }
  2702. me.collapsed = true;
  2703. return me;
  2704. },
  2705. /**
  2706. * 调整range的边界,使其"收缩"到最小的位置
  2707. * @name shrinkBoundary
  2708. * @grammar range.shrinkBoundary() => Range //range开始位置和结束位置都调整,参见<code><a href="#adjustmentboundary">adjustmentBoundary</a></code>
  2709. * @grammar range.shrinkBoundary(true) => Range //仅调整开始位置,忽略结束位置
  2710. * @example
  2711. * <b>xx[</b>xxxxx] ==> <b>xx</b>[xxxxx]
  2712. * <b>x[xx</b><i>]xxx</i> ==> <b>x[xx]</b><i>xxx</i>
  2713. * [<b><i>xxxx</i>xxxxxxx</b>] ==> <b><i>[xxxx</i>xxxxxxx]</b>
  2714. */
  2715. shrinkBoundary: function (ignoreEnd) {
  2716. var me = this, child,
  2717. collapsed = me.collapsed;
  2718. function check(node) {
  2719. return node.nodeType == 1 && !domUtils.isBookmarkNode(node) && !dtd.$empty[node.tagName] && !dtd.$nonChild[node.tagName]
  2720. }
  2721. while (me.startContainer.nodeType == 1 //是element
  2722. && (child = me.startContainer.childNodes[me.startOffset]) //子节点也是element
  2723. && check(child)) {
  2724. me.setStart(child, 0);
  2725. }
  2726. if (collapsed) {
  2727. return me.collapse(true);
  2728. }
  2729. if (!ignoreEnd) {
  2730. while (me.endContainer.nodeType == 1//是element
  2731. && me.endOffset > 0 //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
  2732. && (child = me.endContainer.childNodes[me.endOffset - 1]) //子节点也是element
  2733. && check(child)) {
  2734. me.setEnd(child, child.childNodes.length);
  2735. }
  2736. }
  2737. return me;
  2738. },
  2739. /**
  2740. * 获取当前range所在位置的公共祖先节点,当前range位置可以位于文本节点内,也可以包含整个元素节点,也可以位于两个节点之间
  2741. * @name getCommonAncestor
  2742. * @grammar range.getCommonAncestor([includeSelf, ignoreTextNode]) => Element
  2743. * @example
  2744. * <b>xx[xx<i>xx]x</i>xxx</b> ==>getCommonAncestor() ==> b
  2745. * <b>[<img/>]</b>
  2746. * range.startContainer ==> b
  2747. * range.startOffset ==> 0
  2748. * range.endContainer ==> b
  2749. * range.endOffset ==> 1
  2750. * range.getCommonAncestor() ==> b
  2751. * range.getCommonAncestor(true) ==> img
  2752. * <b>xxx|xx</b>
  2753. * range.startContainer ==> textNode
  2754. * range.startOffset ==> 3
  2755. * range.endContainer ==> textNode
  2756. * range.endOffset ==> 3
  2757. * range.getCommonAncestor() ==> textNode
  2758. * range.getCommonAncestor(null,true) ==> b
  2759. */
  2760. getCommonAncestor: function (includeSelf, ignoreTextNode) {
  2761. var me = this,
  2762. start = me.startContainer,
  2763. end = me.endContainer;
  2764. if (start === end) {
  2765. if (includeSelf && selectOneNode(this)) {
  2766. start = start.childNodes[me.startOffset];
  2767. if (start.nodeType == 1)
  2768. return start;
  2769. }
  2770. //只有在上来就相等的情况下才会出现是文本的情况
  2771. return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start;
  2772. }
  2773. return domUtils.getCommonAncestor(start, end);
  2774. },
  2775. /**
  2776. * 调整边界容器,如果是textNode,就调整到elementNode上
  2777. * @name trimBoundary
  2778. * @grammar range.trimBoundary([ignoreEnd]) => Range //true忽略结束边界
  2779. * @example
  2780. * DOM Element :
  2781. * <b>|xxx</b>
  2782. * startContainer = xxx; startOffset = 0
  2783. * //执行后本方法后
  2784. * startContainer = <b>; startOffset = 0
  2785. * @example
  2786. * Dom Element :
  2787. * <b>xx|x</b>
  2788. * startContainer = xxx; startOffset = 2
  2789. * //执行本方法后,xxx被实实在在地切分成两个TextNode
  2790. * startContainer = <b>; startOffset = 1
  2791. */
  2792. trimBoundary: function (ignoreEnd) {
  2793. this.txtToElmBoundary();
  2794. var start = this.startContainer,
  2795. offset = this.startOffset,
  2796. collapsed = this.collapsed,
  2797. end = this.endContainer;
  2798. if (start.nodeType == 3) {
  2799. if (offset == 0) {
  2800. this.setStartBefore(start);
  2801. } else {
  2802. if (offset >= start.nodeValue.length) {
  2803. this.setStartAfter(start);
  2804. } else {
  2805. var textNode = domUtils.split(start, offset);
  2806. //跟新结束边界
  2807. if (start === end) {
  2808. this.setEnd(textNode, this.endOffset - offset);
  2809. } else if (start.parentNode === end) {
  2810. this.endOffset += 1;
  2811. }
  2812. this.setStartBefore(textNode);
  2813. }
  2814. }
  2815. if (collapsed) {
  2816. return this.collapse(true);
  2817. }
  2818. }
  2819. if (!ignoreEnd) {
  2820. offset = this.endOffset;
  2821. end = this.endContainer;
  2822. if (end.nodeType == 3) {
  2823. if (offset == 0) {
  2824. this.setEndBefore(end);
  2825. } else {
  2826. offset < end.nodeValue.length && domUtils.split(end, offset);
  2827. this.setEndAfter(end);
  2828. }
  2829. }
  2830. }
  2831. return this;
  2832. },
  2833. /**
  2834. * 如果选区在文本的边界上,就扩展选区到文本的父节点上
  2835. * @name txtToElmBoundary
  2836. * @example
  2837. * Dom Element :
  2838. * <b> |xxx</b>
  2839. * startContainer = xxx; startOffset = 0
  2840. * //本方法执行后
  2841. * startContainer = <b>; startOffset = 0
  2842. * @example
  2843. * Dom Element :
  2844. * <b> xxx| </b>
  2845. * startContainer = xxx; startOffset = 3
  2846. * //本方法执行后
  2847. * startContainer = <b>; startOffset = 1
  2848. */
  2849. txtToElmBoundary: function (ignoreCollapsed) {
  2850. function adjust(r, c) {
  2851. var container = r[c + 'Container'],
  2852. offset = r[c + 'Offset'];
  2853. if (container.nodeType == 3) {
  2854. if (!offset) {
  2855. r['set' + c.replace(/(\w)/, function (a) {
  2856. return a.toUpperCase();
  2857. }) + 'Before'](container);
  2858. } else if (offset >= container.nodeValue.length) {
  2859. r['set' + c.replace(/(\w)/, function (a) {
  2860. return a.toUpperCase();
  2861. }) + 'After' ](container);
  2862. }
  2863. }
  2864. }
  2865. if (ignoreCollapsed || !this.collapsed) {
  2866. adjust(this, 'start');
  2867. adjust(this, 'end');
  2868. }
  2869. return this;
  2870. },
  2871. /**
  2872. * 在当前选区的开始位置前插入一个节点或者fragment,range的开始位置会在插入节点的前边
  2873. * @name insertNode
  2874. * @grammar range.insertNode(node) => Range //node可以是textNode,elementNode,fragment
  2875. * @example
  2876. * Range :
  2877. * xxx[x<p>xxxx</p>xxxx]x<p>sdfsdf</p>
  2878. * 待插入Node :
  2879. * <p>ssss</p>
  2880. * 执行本方法后的Range :
  2881. * xxx[<p>ssss</p>x<p>xxxx</p>xxxx]x<p>sdfsdf</p>
  2882. */
  2883. insertNode: function (node) {
  2884. var first = node, length = 1;
  2885. if (node.nodeType == 11) {
  2886. first = node.firstChild;
  2887. length = node.childNodes.length;
  2888. }
  2889. this.trimBoundary(true);
  2890. var start = this.startContainer,
  2891. offset = this.startOffset;
  2892. var nextNode = start.childNodes[ offset ];
  2893. if (nextNode) {
  2894. start.insertBefore(node, nextNode);
  2895. } else {
  2896. start.appendChild(node);
  2897. }
  2898. if (first.parentNode === this.endContainer) {
  2899. this.endOffset = this.endOffset + length;
  2900. }
  2901. return this.setStartBefore(first);
  2902. },
  2903. /**
  2904. * 设置光标闭合位置,toEnd设置为true时光标将闭合到选区的结尾
  2905. * @name setCursor
  2906. * @grammar range.setCursor([toEnd]) => Range //toEnd为true时,光标闭合到选区的末尾
  2907. */
  2908. setCursor: function (toEnd, noFillData) {
  2909. return this.collapse(!toEnd).select(noFillData);
  2910. },
  2911. /**
  2912. * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
  2913. * @name createBookmark
  2914. * @grammar range.createBookmark([serialize]) => Object //{start:开始标记,end:结束标记,id:serialize} serialize为真时,开始结束标记是插入节点的id,否则是插入节点的引用
  2915. */
  2916. createBookmark: function (serialize, same) {
  2917. var endNode,
  2918. startNode = this.document.createElement('span');
  2919. startNode.style.cssText = 'display:none;line-height:0px;';
  2920. startNode.appendChild(this.document.createTextNode('\u200D'));
  2921. startNode.id = '_baidu_bookmark_start_' + (same ? '' : guid++);
  2922. if (!this.collapsed) {
  2923. endNode = startNode.cloneNode(true);
  2924. endNode.id = '_baidu_bookmark_end_' + (same ? '' : guid++);
  2925. }
  2926. this.insertNode(startNode);
  2927. if (endNode) {
  2928. this.collapse().insertNode(endNode).setEndBefore(endNode);
  2929. }
  2930. this.setStartAfter(startNode);
  2931. return {
  2932. start: serialize ? startNode.id : startNode,
  2933. end: endNode ? serialize ? endNode.id : endNode : null,
  2934. id: serialize
  2935. }
  2936. },
  2937. /**
  2938. * 移动边界到书签位置,并删除插入的书签节点
  2939. * @name moveToBookmark
  2940. * @grammar range.moveToBookmark(bookmark) => Range //让当前的range选到给定bookmark的位置,bookmark对象是由range.createBookmark创建的
  2941. */
  2942. moveToBookmark: function (bookmark) {
  2943. var start = bookmark.id ? this.document.getElementById(bookmark.start) : bookmark.start,
  2944. end = bookmark.end && bookmark.id ? this.document.getElementById(bookmark.end) : bookmark.end;
  2945. this.setStartBefore(start);
  2946. domUtils.remove(start);
  2947. if (end) {
  2948. this.setEndBefore(end);
  2949. domUtils.remove(end);
  2950. } else {
  2951. this.collapse(true);
  2952. }
  2953. return this;
  2954. },
  2955. /**
  2956. * 调整range的边界,使其"放大"到最近的父block节点
  2957. * @name enlarge
  2958. * @grammar range.enlarge() => Range
  2959. * @example
  2960. * <p><span>xxx</span><b>x[x</b>xxxxx]</p><p>xxx</p> ==> [<p><span>xxx</span><b>xx</b>xxxxx</p>]<p>xxx</p>
  2961. */
  2962. enlarge: function (toBlock, stopFn) {
  2963. var isBody = domUtils.isBody,
  2964. pre, node, tmp = this.document.createTextNode('');
  2965. if (toBlock) {
  2966. node = this.startContainer;
  2967. if (node.nodeType == 1) {
  2968. if (node.childNodes[this.startOffset]) {
  2969. pre = node = node.childNodes[this.startOffset]
  2970. } else {
  2971. node.appendChild(tmp);
  2972. pre = node = tmp;
  2973. }
  2974. } else {
  2975. pre = node;
  2976. }
  2977. while (1) {
  2978. if (domUtils.isBlockElm(node)) {
  2979. node = pre;
  2980. while ((pre = node.previousSibling) && !domUtils.isBlockElm(pre)) {
  2981. node = pre;
  2982. }
  2983. this.setStartBefore(node);
  2984. break;
  2985. }
  2986. pre = node;
  2987. node = node.parentNode;
  2988. }
  2989. node = this.endContainer;
  2990. if (node.nodeType == 1) {
  2991. if (pre = node.childNodes[this.endOffset]) {
  2992. node.insertBefore(tmp, pre);
  2993. } else {
  2994. node.appendChild(tmp);
  2995. }
  2996. pre = node = tmp;
  2997. } else {
  2998. pre = node;
  2999. }
  3000. while (1) {
  3001. if (domUtils.isBlockElm(node)) {
  3002. node = pre;
  3003. while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) {
  3004. node = pre;
  3005. }
  3006. this.setEndAfter(node);
  3007. break;
  3008. }
  3009. pre = node;
  3010. node = node.parentNode;
  3011. }
  3012. if (tmp.parentNode === this.endContainer) {
  3013. this.endOffset--;
  3014. }
  3015. domUtils.remove(tmp);
  3016. }
  3017. // 扩展边界到最大
  3018. if (!this.collapsed) {
  3019. while (this.startOffset == 0) {
  3020. if (stopFn && stopFn(this.startContainer)) {
  3021. break;
  3022. }
  3023. if (isBody(this.startContainer)) {
  3024. break;
  3025. }
  3026. this.setStartBefore(this.startContainer);
  3027. }
  3028. while (this.endOffset == (this.endContainer.nodeType == 1 ? this.endContainer.childNodes.length : this.endContainer.nodeValue.length)) {
  3029. if (stopFn && stopFn(this.endContainer)) {
  3030. break;
  3031. }
  3032. if (isBody(this.endContainer)) {
  3033. break;
  3034. }
  3035. this.setEndAfter(this.endContainer);
  3036. }
  3037. }
  3038. return this;
  3039. },
  3040. /**
  3041. * 调整Range的边界,使其"缩小"到最合适的位置
  3042. * @name adjustmentBoundary
  3043. * @grammar range.adjustmentBoundary() => Range //参见<code><a href="#shrinkboundary">shrinkBoundary</a></code>
  3044. * @example
  3045. * <b>xx[</b>xxxxx] ==> <b>xx</b>[xxxxx]
  3046. * <b>x[xx</b><i>]xxx</i> ==> <b>x[xx</b>]<i>xxx</i>
  3047. */
  3048. adjustmentBoundary: function () {
  3049. if (!this.collapsed) {
  3050. while (!domUtils.isBody(this.startContainer) &&
  3051. this.startOffset == this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length &&
  3052. this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  3053. ) {
  3054. this.setStartAfter(this.startContainer);
  3055. }
  3056. while (!domUtils.isBody(this.endContainer) && !this.endOffset &&
  3057. this.endContainer[this.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  3058. ) {
  3059. this.setEndBefore(this.endContainer);
  3060. }
  3061. }
  3062. return this;
  3063. },
  3064. /**
  3065. * 给range选区中的内容添加给定的标签,主要用于inline标签
  3066. * @name applyInlineStyle
  3067. * @grammar range.applyInlineStyle(tagName) => Range //tagName为需要添加的样式标签名
  3068. * @grammar range.applyInlineStyle(tagName,attrs) => Range //attrs为属性json对象
  3069. * @desc
  3070. * <code type="html"><p>xxxx[xxxx]x</p> ==> range.applyInlineStyle("strong") ==> <p>xxxx[<strong>xxxx</strong>]x</p>
  3071. * <p>xx[dd<strong>yyyy</strong>]x</p> ==> range.applyInlineStyle("strong") ==> <p>xx[<strong>ddyyyy</strong>]x</p>
  3072. * <p>xxxx[xxxx]x</p> ==> range.applyInlineStyle("strong",{"style":"font-size:12px"}) ==> <p>xxxx[<strong style="font-size:12px">xxxx</strong>]x</p></code>
  3073. */
  3074. applyInlineStyle: function (tagName, attrs, list) {
  3075. if (this.collapsed)return this;
  3076. this.trimBoundary().enlarge(false,
  3077. function (node) {
  3078. return node.nodeType == 1 && domUtils.isBlockElm(node)
  3079. }).adjustmentBoundary();
  3080. var bookmark = this.createBookmark(),
  3081. end = bookmark.end,
  3082. filterFn = function (node) {
  3083. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node);
  3084. },
  3085. current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
  3086. node,
  3087. pre,
  3088. range = this.cloneRange();
  3089. while (current && (domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING)) {
  3090. if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
  3091. range.setStartBefore(current);
  3092. node = current;
  3093. while (node && (node.nodeType == 3 || dtd[tagName][node.tagName]) && node !== end) {
  3094. pre = node;
  3095. node = domUtils.getNextDomNode(node, node.nodeType == 1, null, function (parent) {
  3096. return dtd[tagName][parent.tagName];
  3097. });
  3098. }
  3099. var frag = range.setEndAfter(pre).extractContents(), elm;
  3100. if (list && list.length > 0) {
  3101. var level, top;
  3102. top = level = list[0].cloneNode(false);
  3103. for (var i = 1, ci; ci = list[i++];) {
  3104. level.appendChild(ci.cloneNode(false));
  3105. level = level.firstChild;
  3106. }
  3107. elm = level;
  3108. } else {
  3109. elm = range.document.createElement(tagName);
  3110. }
  3111. if (attrs) {
  3112. domUtils.setAttributes(elm, attrs);
  3113. }
  3114. elm.appendChild(frag);
  3115. range.insertNode(list ? top : elm);
  3116. //处理下滑线在a上的情况
  3117. var aNode;
  3118. if (tagName == 'span' && attrs.style && /text\-decoration/.test(attrs.style) && (aNode = domUtils.findParentByTagName(elm, 'a', true))) {
  3119. domUtils.setAttributes(aNode, attrs);
  3120. domUtils.remove(elm, true);
  3121. elm = aNode;
  3122. } else {
  3123. domUtils.mergeSibling(elm);
  3124. domUtils.clearEmptySibling(elm);
  3125. }
  3126. //去除子节点相同的
  3127. domUtils.mergeChild(elm, attrs);
  3128. current = domUtils.getNextDomNode(elm, false, filterFn);
  3129. domUtils.mergeToParent(elm);
  3130. if (node === end) {
  3131. break;
  3132. }
  3133. } else {
  3134. current = domUtils.getNextDomNode(current, true, filterFn);
  3135. }
  3136. }
  3137. return this.moveToBookmark(bookmark);
  3138. },
  3139. /**
  3140. * 对当前range选中的节点,去掉给定的标签节点,但标签中的内容保留,主要用于处理inline元素
  3141. * @name removeInlineStyle
  3142. * @grammar range.removeInlineStyle(tagNames) => Range //tagNames 为需要去掉的样式标签名,支持"b"或者["b","i","u"]
  3143. * @desc
  3144. * <code type="html">xx[x<span>xxx<em>yyy</em>zz]z</span> => range.removeInlineStyle(["em"]) => xx[x<span>xxxyyyzz]z</span></code>
  3145. */
  3146. removeInlineStyle: function (tagNames) {
  3147. if (this.collapsed)return this;
  3148. tagNames = utils.isArray(tagNames) ? tagNames : [tagNames];
  3149. this.shrinkBoundary().adjustmentBoundary();
  3150. var start = this.startContainer, end = this.endContainer;
  3151. while (1) {
  3152. if (start.nodeType == 1) {
  3153. if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) {
  3154. break;
  3155. }
  3156. if (start.tagName.toLowerCase() == 'body') {
  3157. start = null;
  3158. break;
  3159. }
  3160. }
  3161. start = start.parentNode;
  3162. }
  3163. while (1) {
  3164. if (end.nodeType == 1) {
  3165. if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) {
  3166. break;
  3167. }
  3168. if (end.tagName.toLowerCase() == 'body') {
  3169. end = null;
  3170. break;
  3171. }
  3172. }
  3173. end = end.parentNode;
  3174. }
  3175. var bookmark = this.createBookmark(),
  3176. frag,
  3177. tmpRange;
  3178. if (start) {
  3179. tmpRange = this.cloneRange().setEndBefore(bookmark.start).setStartBefore(start);
  3180. frag = tmpRange.extractContents();
  3181. tmpRange.insertNode(frag);
  3182. domUtils.clearEmptySibling(start, true);
  3183. start.parentNode.insertBefore(bookmark.start, start);
  3184. }
  3185. if (end) {
  3186. tmpRange = this.cloneRange().setStartAfter(bookmark.end).setEndAfter(end);
  3187. frag = tmpRange.extractContents();
  3188. tmpRange.insertNode(frag);
  3189. domUtils.clearEmptySibling(end, false, true);
  3190. end.parentNode.insertBefore(bookmark.end, end.nextSibling);
  3191. }
  3192. var current = domUtils.getNextDomNode(bookmark.start, false, function (node) {
  3193. return node.nodeType == 1;
  3194. }), next;
  3195. while (current && current !== bookmark.end) {
  3196. next = domUtils.getNextDomNode(current, true, function (node) {
  3197. return node.nodeType == 1;
  3198. });
  3199. if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) {
  3200. domUtils.remove(current, true);
  3201. }
  3202. current = next;
  3203. }
  3204. return this.moveToBookmark(bookmark);
  3205. },
  3206. /**
  3207. * 得到一个自闭合的节点,常用于获取自闭和的节点,例如图片节点
  3208. * @name getClosedNode
  3209. * @grammar range.getClosedNode() => node|null
  3210. * @example
  3211. * <b>xxxx[<img />]xxx</b>
  3212. */
  3213. getClosedNode: function () {
  3214. var node;
  3215. if (!this.collapsed) {
  3216. var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
  3217. if (selectOneNode(range)) {
  3218. var child = range.startContainer.childNodes[range.startOffset];
  3219. if (child && child.nodeType == 1 && (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])) {
  3220. node = child;
  3221. }
  3222. }
  3223. }
  3224. return node;
  3225. },
  3226. /**
  3227. * 根据当前range选中内容节点(在页面上表现为反白显示)
  3228. * @name select
  3229. * @grammar range.select(); => Range
  3230. */
  3231. select: browser.ie ? function (noFillData, textRange) {
  3232. var nativeRange;
  3233. if (!this.collapsed)
  3234. this.shrinkBoundary();
  3235. var node = this.getClosedNode();
  3236. if (node && !textRange) {
  3237. try {
  3238. nativeRange = this.document.body.createControlRange();
  3239. nativeRange.addElement(node);
  3240. nativeRange.select();
  3241. } catch (e) {
  3242. }
  3243. return this;
  3244. }
  3245. var bookmark = this.createBookmark(),
  3246. start = bookmark.start,
  3247. end;
  3248. nativeRange = this.document.body.createTextRange();
  3249. nativeRange.moveToElementText(start);
  3250. nativeRange.moveStart('character', 1);
  3251. if (!this.collapsed) {
  3252. var nativeRangeEnd = this.document.body.createTextRange();
  3253. end = bookmark.end;
  3254. nativeRangeEnd.moveToElementText(end);
  3255. nativeRange.setEndPoint('EndToEnd', nativeRangeEnd);
  3256. } else {
  3257. if (!noFillData && this.startContainer.nodeType != 3) {
  3258. //使用<span>|x<span>固定住光标
  3259. var tmpText = this.document.createTextNode(fillChar),
  3260. tmp = this.document.createElement('span');
  3261. tmp.appendChild(this.document.createTextNode(fillChar));
  3262. start.parentNode.insertBefore(tmp, start);
  3263. start.parentNode.insertBefore(tmpText, start);
  3264. //当点b,i,u时,不能清除i上边的b
  3265. removeFillData(this.document, tmpText);
  3266. fillData = tmpText;
  3267. mergeSibling(tmp, 'previousSibling');
  3268. mergeSibling(start, 'nextSibling');
  3269. nativeRange.moveStart('character', -1);
  3270. nativeRange.collapse(true);
  3271. }
  3272. }
  3273. this.moveToBookmark(bookmark);
  3274. tmp && domUtils.remove(tmp);
  3275. //IE在隐藏状态下不支持range操作,catch一下
  3276. try {
  3277. nativeRange.select();
  3278. } catch (e) {
  3279. }
  3280. return this;
  3281. } : function (notInsertFillData) {
  3282. function checkOffset(rng) {
  3283. function check(node, offset, dir) {
  3284. if (node.nodeType == 3 && node.nodeValue.length < offset) {
  3285. rng[dir + 'Offset'] = node.nodeValue.length
  3286. }
  3287. }
  3288. check(rng.startContainer, rng.startOffset, 'start');
  3289. check(rng.endContainer, rng.endOffset, 'end');
  3290. }
  3291. var win = domUtils.getWindow(this.document),
  3292. sel = win.getSelection(),
  3293. txtNode;
  3294. //FF下关闭自动长高时滚动条在关闭dialog时会跳
  3295. //ff下如果不body.focus将不能定位闭合光标到编辑器内
  3296. browser.gecko ? this.document.body.focus() : win.focus();
  3297. if (sel) {
  3298. sel.removeAllRanges();
  3299. // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
  3300. // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
  3301. if (this.collapsed && !notInsertFillData) {
  3302. // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
  3303. // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
  3304. // var tmp = this.document.createTextNode('');
  3305. // this.insertNode(tmp).setStart(tmp, 0).collapse(true);
  3306. // }
  3307. //
  3308. //处理光标落在文本节点的情况
  3309. //处理以下的情况
  3310. //<b>|xxxx</b>
  3311. //<b>xxxx</b>|xxxx
  3312. //xxxx<b>|</b>
  3313. var start = this.startContainer, child = start;
  3314. if (start.nodeType == 1) {
  3315. child = start.childNodes[this.startOffset];
  3316. }
  3317. if (!(start.nodeType == 3 && this.startOffset) &&
  3318. (child ?
  3319. (!child.previousSibling || child.previousSibling.nodeType != 3)
  3320. :
  3321. (!start.lastChild || start.lastChild.nodeType != 3)
  3322. )
  3323. ) {
  3324. txtNode = this.document.createTextNode(fillChar);
  3325. //跟着前边走
  3326. this.insertNode(txtNode);
  3327. removeFillData(this.document, txtNode);
  3328. mergeSibling(txtNode, 'previousSibling');
  3329. mergeSibling(txtNode, 'nextSibling');
  3330. fillData = txtNode;
  3331. this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true);
  3332. }
  3333. }
  3334. var nativeRange = this.document.createRange();
  3335. if (this.collapsed && browser.opera && this.startContainer.nodeType == 1) {
  3336. var child = this.startContainer.childNodes[this.startOffset];
  3337. if (!child) {
  3338. //往前靠拢
  3339. child = this.startContainer.lastChild;
  3340. if (child && domUtils.isBr(child)) {
  3341. this.setStartBefore(child).collapse(true);
  3342. }
  3343. } else {
  3344. //向后靠拢
  3345. while (child && domUtils.isBlockElm(child)) {
  3346. if (child.nodeType == 1 && child.childNodes[0]) {
  3347. child = child.childNodes[0]
  3348. } else {
  3349. break;
  3350. }
  3351. }
  3352. child && this.setStartBefore(child).collapse(true)
  3353. }
  3354. }
  3355. //是createAddress最后一位算的不准,现在这里进行微调
  3356. checkOffset(this);
  3357. nativeRange.setStart(this.startContainer, this.startOffset);
  3358. nativeRange.setEnd(this.endContainer, this.endOffset);
  3359. sel.addRange(nativeRange);
  3360. }
  3361. return this;
  3362. },
  3363. /**
  3364. * 滚动条跳到当然range开始的位置
  3365. * @name scrollToView
  3366. * @grammar range.scrollToView([win,offset]) => Range //针对window对象,若不指定,将以编辑区域的窗口为准,offset偏移量
  3367. */
  3368. scrollToView: function (win, offset) {
  3369. win = win ? window : domUtils.getWindow(this.document);
  3370. var me = this,
  3371. span = me.document.createElement('span');
  3372. //trace:717
  3373. span.innerHTML = '&nbsp;';
  3374. me.cloneRange().insertNode(span);
  3375. domUtils.scrollToView(span, win, offset);
  3376. domUtils.remove(span);
  3377. return me;
  3378. },
  3379. inFillChar: function () {
  3380. var start = this.startContainer;
  3381. if (this.collapsed && start.nodeType == 3
  3382. && start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '').length + 1 == start.nodeValue.length
  3383. ) {
  3384. return true;
  3385. }
  3386. return false;
  3387. },
  3388. createAddress: function (ignoreEnd, ignoreTxt) {
  3389. var addr = {}, me = this;
  3390. function getAddress(isStart) {
  3391. var node = isStart ? me.startContainer : me.endContainer;
  3392. var parents = domUtils.findParents(node, true, function (node) {
  3393. return !domUtils.isBody(node)
  3394. }),
  3395. addrs = [];
  3396. for (var i = 0, ci; ci = parents[i++];) {
  3397. addrs.push(domUtils.getNodeIndex(ci, ignoreTxt));
  3398. }
  3399. var firstIndex = 0;
  3400. if (ignoreTxt) {
  3401. if (node.nodeType == 3) {
  3402. var tmpNode = node.previousSibling;
  3403. while (tmpNode && tmpNode.nodeType == 3) {
  3404. firstIndex += tmpNode.nodeValue.replace(fillCharReg, '').length;
  3405. tmpNode = tmpNode.previousSibling;
  3406. }
  3407. firstIndex += (isStart ? me.startOffset : me.endOffset)// - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
  3408. } else {
  3409. node = node.childNodes[ isStart ? me.startOffset : me.endOffset];
  3410. if (node) {
  3411. firstIndex = domUtils.getNodeIndex(node, ignoreTxt);
  3412. } else {
  3413. node = isStart ? me.startContainer : me.endContainer;
  3414. var first = node.firstChild;
  3415. while (first) {
  3416. if (domUtils.isFillChar(first)) {
  3417. first = first.nextSibling;
  3418. continue;
  3419. }
  3420. firstIndex++;
  3421. if (first.nodeType == 3) {
  3422. while (first && first.nodeType == 3) {
  3423. first = first.nextSibling;
  3424. }
  3425. } else {
  3426. first = first.nextSibling;
  3427. }
  3428. }
  3429. }
  3430. }
  3431. } else {
  3432. firstIndex = isStart ? domUtils.isFillChar(node) ? 0 : me.startOffset : me.endOffset
  3433. }
  3434. if (firstIndex < 0) {
  3435. firstIndex = 0;
  3436. }
  3437. addrs.push(firstIndex);
  3438. return addrs;
  3439. }
  3440. addr.startAddress = getAddress(true);
  3441. if (!ignoreEnd) {
  3442. addr.endAddress = me.collapsed ? [].concat(addr.startAddress) : getAddress();
  3443. }
  3444. return addr;
  3445. },
  3446. moveToAddress: function (addr, ignoreEnd) {
  3447. var me = this;
  3448. function getNode(address, isStart) {
  3449. var tmpNode = me.document.body,
  3450. parentNode, offset;
  3451. for (var i = 0, ci, l = address.length; i < l; i++) {
  3452. ci = address[i];
  3453. parentNode = tmpNode;
  3454. tmpNode = tmpNode.childNodes[ci];
  3455. if (!tmpNode) {
  3456. offset = ci;
  3457. break;
  3458. }
  3459. }
  3460. if (isStart) {
  3461. if (tmpNode) {
  3462. me.setStartBefore(tmpNode)
  3463. } else {
  3464. me.setStart(parentNode, offset)
  3465. }
  3466. } else {
  3467. if (tmpNode) {
  3468. me.setEndBefore(tmpNode)
  3469. } else {
  3470. me.setEnd(parentNode, offset)
  3471. }
  3472. }
  3473. }
  3474. getNode(addr.startAddress, true);
  3475. !ignoreEnd && addr.endAddress && getNode(addr.endAddress);
  3476. return me;
  3477. },
  3478. equals: function (rng) {
  3479. for (var p in this) {
  3480. if (this.hasOwnProperty(p)) {
  3481. if (this[p] !== rng[p])
  3482. return false
  3483. }
  3484. }
  3485. return true;
  3486. },
  3487. traversal: function (doFn, filterFn) {
  3488. if (this.collapsed)
  3489. return this;
  3490. var bookmark = this.createBookmark(),
  3491. end = bookmark.end,
  3492. current = domUtils.getNextDomNode(bookmark.start, false, filterFn);
  3493. while (current && current !== end && (domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING)) {
  3494. var tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  3495. doFn(current);
  3496. current = tmpNode;
  3497. }
  3498. return this.moveToBookmark(bookmark);
  3499. }
  3500. };
  3501. })();
  3502. ///import editor.js
  3503. ///import core/browser.js
  3504. ///import core/dom/dom.js
  3505. ///import core/dom/dtd.js
  3506. ///import core/dom/domUtils.js
  3507. ///import core/dom/Range.js
  3508. /**
  3509. * @class baidu.editor.dom.Selection Selection类
  3510. */
  3511. (function () {
  3512. function getBoundaryInformation(range, start) {
  3513. var getIndex = domUtils.getNodeIndex;
  3514. range = range.duplicate();
  3515. range.collapse(start);
  3516. var parent = range.parentElement();
  3517. //如果节点里没有子节点,直接退出
  3518. if (!parent.hasChildNodes()) {
  3519. return {container: parent, offset: 0};
  3520. }
  3521. var siblings = parent.children,
  3522. child,
  3523. testRange = range.duplicate(),
  3524. startIndex = 0, endIndex = siblings.length - 1, index = -1,
  3525. distance;
  3526. while (startIndex <= endIndex) {
  3527. index = Math.floor((startIndex + endIndex) / 2);
  3528. child = siblings[index];
  3529. testRange.moveToElementText(child);
  3530. var position = testRange.compareEndPoints('StartToStart', range);
  3531. if (position > 0) {
  3532. endIndex = index - 1;
  3533. } else if (position < 0) {
  3534. startIndex = index + 1;
  3535. } else {
  3536. //trace:1043
  3537. return {container: parent, offset: getIndex(child)};
  3538. }
  3539. }
  3540. if (index == -1) {
  3541. testRange.moveToElementText(parent);
  3542. testRange.setEndPoint('StartToStart', range);
  3543. distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length;
  3544. siblings = parent.childNodes;
  3545. if (!distance) {
  3546. child = siblings[siblings.length - 1];
  3547. return {container: child, offset: child.nodeValue.length};
  3548. }
  3549. var i = siblings.length;
  3550. while (distance > 0) {
  3551. distance -= siblings[ --i ].nodeValue.length;
  3552. }
  3553. return {container: siblings[i], offset: -distance};
  3554. }
  3555. testRange.collapse(position > 0);
  3556. testRange.setEndPoint(position > 0 ? 'StartToStart' : 'EndToStart', range);
  3557. distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length;
  3558. if (!distance) {
  3559. return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ?
  3560. {container: parent, offset: getIndex(child) + (position > 0 ? 0 : 1)} :
  3561. {container: child, offset: position > 0 ? 0 : child.childNodes.length}
  3562. }
  3563. while (distance > 0) {
  3564. try {
  3565. var pre = child;
  3566. child = child[position > 0 ? 'previousSibling' : 'nextSibling'];
  3567. distance -= child.nodeValue.length;
  3568. } catch (e) {
  3569. return {container: parent, offset: getIndex(pre)};
  3570. }
  3571. }
  3572. return {container: child, offset: position > 0 ? -distance : child.nodeValue.length + distance}
  3573. }
  3574. /**
  3575. * 将ieRange转换为Range对象
  3576. * @param {Range} ieRange ieRange对象
  3577. * @param {Range} range Range对象
  3578. * @return {Range} range 返回转换后的Range对象
  3579. */
  3580. function transformIERangeToRange(ieRange, range) {
  3581. if (ieRange.item) {
  3582. range.selectNode(ieRange.item(0));
  3583. } else {
  3584. var bi = getBoundaryInformation(ieRange, true);
  3585. range.setStart(bi.container, bi.offset);
  3586. if (ieRange.compareEndPoints('StartToEnd', ieRange) != 0) {
  3587. bi = getBoundaryInformation(ieRange, false);
  3588. range.setEnd(bi.container, bi.offset);
  3589. }
  3590. }
  3591. return range;
  3592. }
  3593. /**
  3594. * 获得ieRange
  3595. * @param {Selection} sel Selection对象
  3596. * @return {ieRange} 得到ieRange
  3597. */
  3598. function _getIERange(sel) {
  3599. var ieRange;
  3600. //ie下有可能报错
  3601. try {
  3602. ieRange = sel.getNative().createRange();
  3603. } catch (e) {
  3604. return null;
  3605. }
  3606. var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
  3607. if (( el.ownerDocument || el ) === sel.document) {
  3608. return ieRange;
  3609. }
  3610. return null;
  3611. }
  3612. var Selection = dom.Selection = function (doc) {
  3613. var me = this, iframe;
  3614. me.document = doc;
  3615. if (ie) {
  3616. iframe = domUtils.getWindow(doc).frameElement;
  3617. domUtils.on(iframe, 'beforedeactivate', function () {
  3618. me._bakIERange = me.getIERange();
  3619. });
  3620. domUtils.on(iframe, 'activate', function () {
  3621. try {
  3622. if (!_getIERange(me) && me._bakIERange) {
  3623. me._bakIERange.select();
  3624. }
  3625. } catch (ex) {
  3626. }
  3627. me._bakIERange = null;
  3628. });
  3629. }
  3630. iframe = doc = null;
  3631. };
  3632. Selection.prototype = {
  3633. /**
  3634. * 获取原生seleciton对象
  3635. * @public
  3636. * @function
  3637. * @name baidu.editor.dom.Selection.getNative
  3638. * @return {Selection} 获得selection对象
  3639. */
  3640. getNative: function () {
  3641. var doc = this.document;
  3642. try {
  3643. return !doc ? null : ie && browser.ie < 9 ? doc.selection : domUtils.getWindow(doc).getSelection();
  3644. } catch (e) {
  3645. return null;
  3646. }
  3647. },
  3648. /**
  3649. * 获得ieRange
  3650. * @public
  3651. * @function
  3652. * @name baidu.editor.dom.Selection.getIERange
  3653. * @return {ieRange} 返回ie原生的Range
  3654. */
  3655. getIERange: function () {
  3656. var ieRange = _getIERange(this);
  3657. if (!ieRange) {
  3658. if (this._bakIERange) {
  3659. return this._bakIERange;
  3660. }
  3661. }
  3662. return ieRange;
  3663. },
  3664. /**
  3665. * 缓存当前选区的range和选区的开始节点
  3666. * @public
  3667. * @function
  3668. * @name baidu.editor.dom.Selection.cache
  3669. */
  3670. cache: function () {
  3671. this.clear();
  3672. this._cachedRange = this.getRange();
  3673. this._cachedStartElement = this.getStart();
  3674. this._cachedStartElementPath = this.getStartElementPath();
  3675. },
  3676. getStartElementPath: function () {
  3677. if (this._cachedStartElementPath) {
  3678. return this._cachedStartElementPath;
  3679. }
  3680. var start = this.getStart();
  3681. if (start) {
  3682. return domUtils.findParents(start, true, null, true)
  3683. }
  3684. return [];
  3685. },
  3686. /**
  3687. * 清空缓存
  3688. * @public
  3689. * @function
  3690. * @name baidu.editor.dom.Selection.clear
  3691. */
  3692. clear: function () {
  3693. this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null;
  3694. },
  3695. /**
  3696. * 编辑器是否得到了选区
  3697. */
  3698. isFocus: function () {
  3699. try {
  3700. return browser.ie && _getIERange(this) || !browser.ie && this.getNative().rangeCount ? true : false;
  3701. } catch (e) {
  3702. return false;
  3703. }
  3704. },
  3705. /**
  3706. * 获取选区对应的Range
  3707. * @public
  3708. * @function
  3709. * @name baidu.editor.dom.Selection.getRange
  3710. * @returns {baidu.editor.dom.Range} 得到Range对象
  3711. */
  3712. getRange: function () {
  3713. var me = this;
  3714. function optimze(range) {
  3715. var child = me.document.body.firstChild,
  3716. collapsed = range.collapsed;
  3717. while (child && child.firstChild) {
  3718. range.setStart(child, 0);
  3719. child = child.firstChild;
  3720. }
  3721. if (!range.startContainer) {
  3722. range.setStart(me.document.body, 0)
  3723. }
  3724. if (collapsed) {
  3725. range.collapse(true);
  3726. }
  3727. }
  3728. if (me._cachedRange != null) {
  3729. return this._cachedRange;
  3730. }
  3731. var range = new baidu.editor.dom.Range(me.document);
  3732. if (ie && browser.ie < 9) {
  3733. var nativeRange = me.getIERange();
  3734. if (nativeRange) {
  3735. //备份的_bakIERange可能已经实效了,dom树发生了变化比如从源码模式切回来,所以try一下,实效就放到body开始位置
  3736. try {
  3737. transformIERangeToRange(nativeRange, range);
  3738. } catch (e) {
  3739. optimze(range);
  3740. }
  3741. } else {
  3742. optimze(range);
  3743. }
  3744. } else {
  3745. var sel = me.getNative();
  3746. if (sel && sel.rangeCount) {
  3747. var firstRange = sel.getRangeAt(0);
  3748. var lastRange = sel.getRangeAt(sel.rangeCount - 1);
  3749. range.setStart(firstRange.startContainer, firstRange.startOffset).setEnd(lastRange.endContainer, lastRange.endOffset);
  3750. if (range.collapsed && domUtils.isBody(range.startContainer) && !range.startOffset) {
  3751. optimze(range);
  3752. }
  3753. } else {
  3754. //trace:1734 有可能已经不在dom树上了,标识的节点
  3755. if (this._bakRange && domUtils.inDoc(this._bakRange.startContainer, this.document)) {
  3756. return this._bakRange;
  3757. }
  3758. optimze(range);
  3759. }
  3760. }
  3761. return this._bakRange = range;
  3762. },
  3763. /**
  3764. * 获取开始元素,用于状态反射
  3765. * @public
  3766. * @function
  3767. * @name baidu.editor.dom.Selection.getStart
  3768. * @return {Element} 获得开始元素
  3769. */
  3770. getStart: function () {
  3771. if (this._cachedStartElement) {
  3772. return this._cachedStartElement;
  3773. }
  3774. var range = ie ? this.getIERange() : this.getRange(),
  3775. tmpRange,
  3776. start, tmp, parent;
  3777. if (ie) {
  3778. if (!range) {
  3779. //todo 给第一个值可能会有问题
  3780. return this.document.body.firstChild;
  3781. }
  3782. //control元素
  3783. if (range.item) {
  3784. return range.item(0);
  3785. }
  3786. tmpRange = range.duplicate();
  3787. //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
  3788. tmpRange.text.length > 0 && tmpRange.moveStart('character', 1);
  3789. tmpRange.collapse(1);
  3790. start = tmpRange.parentElement();
  3791. parent = tmp = range.parentElement();
  3792. while (tmp = tmp.parentNode) {
  3793. if (tmp == start) {
  3794. start = parent;
  3795. break;
  3796. }
  3797. }
  3798. } else {
  3799. range.shrinkBoundary();
  3800. start = range.startContainer;
  3801. if (start.nodeType == 1 && start.hasChildNodes()) {
  3802. start = start.childNodes[Math.min(start.childNodes.length - 1, range.startOffset)];
  3803. }
  3804. if (start.nodeType == 3) {
  3805. return start.parentNode;
  3806. }
  3807. }
  3808. return start;
  3809. },
  3810. /**
  3811. * 得到选区中的文本
  3812. * @public
  3813. * @function
  3814. * @name baidu.editor.dom.Selection.getText
  3815. * @return {String} 选区中包含的文本
  3816. */
  3817. getText: function () {
  3818. var nativeSel, nativeRange;
  3819. if (this.isFocus() && (nativeSel = this.getNative())) {
  3820. nativeRange = browser.ie ? nativeSel.createRange() : nativeSel.getRangeAt(0);
  3821. return browser.ie ? nativeRange.text : nativeRange.toString();
  3822. }
  3823. return '';
  3824. },
  3825. clearRange: function () {
  3826. this.getNative()[browser.ie ? 'empty' : 'removeAllRanges']();
  3827. }
  3828. };
  3829. })();
  3830. /**
  3831. * @file
  3832. * @name UE.Editor
  3833. * @short Editor
  3834. * @import editor.js,core/utils.js,core/EventBase.js,core/browser.js,core/dom/dtd.js,core/dom/domUtils.js,core/dom/Range.js,core/dom/Selection.js,plugins/serialize.js
  3835. * @desc 编辑器主类,包含编辑器提供的大部分公用接口
  3836. */
  3837. (function () {
  3838. var uid = 0, _selectionChangeTimer;
  3839. /**
  3840. * @private
  3841. * @ignore
  3842. * @param form 编辑器所在的form元素
  3843. * @param editor 编辑器实例对象
  3844. */
  3845. function setValue(form, editor) {
  3846. var textarea;
  3847. if (editor.textarea) {
  3848. if (utils.isString(editor.textarea)) {
  3849. for (var i = 0, ti, tis = domUtils.getElementsByTagName(form, 'textarea'); ti = tis[i++];) {
  3850. if (ti.id == 'ueditor_textarea_' + editor.options.textarea) {
  3851. textarea = ti;
  3852. break;
  3853. }
  3854. }
  3855. } else {
  3856. textarea = editor.textarea;
  3857. }
  3858. }
  3859. if (!textarea) {
  3860. form.appendChild(textarea = domUtils.createElement(document, 'textarea', {
  3861. 'name': editor.options.textarea,
  3862. 'id': 'ueditor_textarea_' + editor.options.textarea,
  3863. 'style': "display:none"
  3864. }));
  3865. //不要产生多个textarea
  3866. editor.textarea = textarea;
  3867. }
  3868. textarea.value = editor.hasContents() ?
  3869. (editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null, null, true)) :
  3870. ''
  3871. }
  3872. function loadPlugins(me) {
  3873. //初始化插件
  3874. for (var pi in UE.plugins) {
  3875. UE.plugins[pi].call(me);
  3876. }
  3877. me.langIsReady = true;
  3878. me.fireEvent("langReady");
  3879. }
  3880. function checkCurLang(I18N) {
  3881. for (var lang in I18N) {
  3882. return lang
  3883. }
  3884. }
  3885. /**
  3886. * UEditor编辑器类
  3887. * @name Editor
  3888. * @desc 创建一个跟编辑器实例
  3889. * - ***container*** 编辑器容器对象
  3890. * - ***iframe*** 编辑区域所在的iframe对象
  3891. * - ***window*** 编辑区域所在的window
  3892. * - ***document*** 编辑区域所在的document对象
  3893. * - ***body*** 编辑区域所在的body对象
  3894. * - ***selection*** 编辑区域的选区对象
  3895. */
  3896. var Editor = UE.Editor = function (options) {
  3897. var me = this;
  3898. me.uid = uid++;
  3899. EventBase.call(me);
  3900. me.commands = {};
  3901. me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true);
  3902. me.shortcutkeys = {};
  3903. me.inputRules = [];
  3904. me.outputRules = [];
  3905. //设置默认的常用属性
  3906. me.setOpt({
  3907. isShow: true,
  3908. initialContent: '',
  3909. initialStyle: '',
  3910. autoClearinitialContent: false,
  3911. iframeCssUrl: me.options.UEDITOR_HOME_URL + 'themes/iframe.css',
  3912. textarea: 'editorValue',
  3913. focus: false,
  3914. focusInEnd: true,
  3915. autoClearEmptyNode: true,
  3916. fullscreen: false,
  3917. readonly: false,
  3918. zIndex: 999,
  3919. imagePopup: true,
  3920. enterTag: 'p',
  3921. customDomain: false,
  3922. lang: 'zh-cn',
  3923. langPath: me.options.UEDITOR_HOME_URL + 'lang/',
  3924. theme: 'default',
  3925. themePath: me.options.UEDITOR_HOME_URL + 'themes/',
  3926. allHtmlEnabled: false,
  3927. scaleEnabled: false,
  3928. tableNativeEditInFF: false,
  3929. autoSyncData: true
  3930. });
  3931. if (!utils.isEmptyObject(UE.I18N)) {
  3932. //修改默认的语言类型
  3933. me.options.lang = checkCurLang(UE.I18N);
  3934. loadPlugins(me)
  3935. } else {
  3936. utils.loadFile(document, {
  3937. src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
  3938. tag: "script",
  3939. type: "text/javascript",
  3940. defer: "defer"
  3941. }, function () {
  3942. loadPlugins(me)
  3943. });
  3944. }
  3945. UE.instants['ueditorInstant' + me.uid] = me;
  3946. };
  3947. Editor.prototype = {
  3948. /**
  3949. * 当编辑器ready后执行传入的fn,如果编辑器已经完成ready,就马上执行fn,fn的中的this是编辑器实例。
  3950. * 大部分的实例接口都需要放在该方法内部执行,否则在IE下可能会报错。
  3951. * @name ready
  3952. * @grammar editor.ready(fn) fn是当编辑器渲染好后执行的function
  3953. * @example
  3954. * var editor = new UE.ui.Editor();
  3955. * editor.render("myEditor");
  3956. * editor.ready(function(){
  3957. * editor.setContent("欢迎使用UEditor!");
  3958. * })
  3959. */
  3960. ready: function (fn) {
  3961. var me = this;
  3962. if (fn) {
  3963. me.isReady ? fn.apply(me) : me.addListener('ready', fn);
  3964. }
  3965. },
  3966. /**
  3967. * 为编辑器设置默认参数值。若用户配置为空,则以默认配置为准
  3968. * @grammar editor.setOpt(key,value); //传入一个键、值对
  3969. * @grammar editor.setOpt({ key:value}); //传入一个json对象
  3970. */
  3971. setOpt: function (key, val) {
  3972. var obj = {};
  3973. if (utils.isString(key)) {
  3974. obj[key] = val
  3975. } else {
  3976. obj = key;
  3977. }
  3978. utils.extend(this.options, obj, true);
  3979. },
  3980. /**
  3981. * 销毁编辑器实例对象
  3982. * @name destroy
  3983. * @grammar editor.destroy();
  3984. */
  3985. destroy: function () {
  3986. var me = this;
  3987. me.fireEvent('destroy');
  3988. var container = me.container.parentNode;
  3989. var textarea = me.textarea;
  3990. if (!textarea) {
  3991. textarea = document.createElement('textarea');
  3992. container.parentNode.insertBefore(textarea, container);
  3993. } else {
  3994. textarea.style.display = ''
  3995. }
  3996. textarea.style.width = me.iframe.offsetWidth + 'px';
  3997. textarea.style.height = me.iframe.offsetHeight + 'px';
  3998. textarea.value = me.getContent();
  3999. textarea.id = me.key;
  4000. container.innerHTML = '';
  4001. domUtils.remove(container);
  4002. var key = me.key;
  4003. //trace:2004
  4004. for (var p in me) {
  4005. if (me.hasOwnProperty(p)) {
  4006. delete this[p];
  4007. }
  4008. }
  4009. UE.delEditor(key);
  4010. },
  4011. /**
  4012. * 渲染编辑器的DOM到指定容器,必须且只能调用一次
  4013. * @name render
  4014. * @grammar editor.render(containerId); //可以指定一个容器ID
  4015. * @grammar editor.render(containerDom); //也可以直接指定容器对象
  4016. */
  4017. render: function (container) {
  4018. var me = this,
  4019. options = me.options,
  4020. getStyleValue = function (attr) {
  4021. return parseInt(domUtils.getComputedStyle(container, attr));
  4022. };
  4023. if (utils.isString(container)) {
  4024. container = document.getElementById(container);
  4025. }
  4026. if (container) {
  4027. if (options.initialFrameWidth) {
  4028. options.minFrameWidth = options.initialFrameWidth
  4029. } else {
  4030. options.minFrameWidth = options.initialFrameWidth = container.offsetWidth;
  4031. }
  4032. if (options.initialFrameHeight) {
  4033. options.minFrameHeight = options.initialFrameHeight
  4034. } else {
  4035. options.initialFrameHeight = options.minFrameHeight = container.offsetHeight;
  4036. }
  4037. container.style.width = /%$/.test(options.initialFrameWidth) ? '100%' : options.initialFrameWidth -
  4038. getStyleValue("padding-left") - getStyleValue("padding-right") + 'px';
  4039. container.style.height = /%$/.test(options.initialFrameHeight) ? '100%' : options.initialFrameHeight -
  4040. getStyleValue("padding-top") - getStyleValue("padding-bottom") + 'px';
  4041. container.style.zIndex = options.zIndex;
  4042. var html = ( ie && browser.version < 9 ? '' : '<!DOCTYPE html>') +
  4043. '<html xmlns=\'http://www.w3.org/1999/xhtml\' class=\'view\' ><head>' +
  4044. '<style type=\'text/css\'>' +
  4045. //设置四周的留边
  4046. '.view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n' +
  4047. //设置默认字体和字号
  4048. //font-family不能呢随便改,在safari下fillchar会有解析问题
  4049. 'body{margin:8px;font-family:sans-serif;font-size:16px;}' +
  4050. //设置段落间距
  4051. 'p{margin:5px 0;}</style>' +
  4052. ( options.iframeCssUrl ? '<link rel=\'stylesheet\' type=\'text/css\' href=\'' + utils.unhtml(options.iframeCssUrl) + '\'/>' : '' ) +
  4053. (options.initialStyle ? '<style>' + options.initialStyle + '</style>' : '') +
  4054. '</head><body class=\'view\' ></body>' +
  4055. '<script type=\'text/javascript\' ' + (ie ? 'defer=\'defer\'' : '' ) + ' id=\'_initialScript\'>' +
  4056. 'setTimeout(function(){window.parent.UE.instants[\'ueditorInstant' + me.uid + '\']._setup(document);},0);' +
  4057. 'var _tmpScript = document.getElementById(\'_initialScript\');_tmpScript.parentNode.removeChild(_tmpScript);</script></html>';
  4058. container.appendChild(domUtils.createElement(document, 'iframe', {
  4059. id: 'ueditor_' + me.uid,
  4060. width: "100%",
  4061. height: "100%",
  4062. frameborder: "0",
  4063. src: 'javascript:void(function(){document.open();' + (options.customDomain && document.domain != location.hostname ? 'document.domain="' + document.domain + '";' : '') +
  4064. 'document.write("' + html + '");document.close();}())'
  4065. }));
  4066. container.style.overflow = 'hidden';
  4067. //解决如果是给定的百分比,会导致高度算不对的问题
  4068. setTimeout(function () {
  4069. if (/%$/.test(options.initialFrameWidth)) {
  4070. options.minFrameWidth = options.initialFrameWidth = container.offsetWidth;
  4071. container.style.width = options.initialFrameWidth + 'px';
  4072. }
  4073. if (/%$/.test(options.initialFrameHeight)) {
  4074. options.minFrameHeight = options.initialFrameHeight = container.offsetHeight;
  4075. container.style.height = options.initialFrameHeight + 'px';
  4076. }
  4077. })
  4078. }
  4079. },
  4080. /**
  4081. * 编辑器初始化
  4082. * @private
  4083. * @ignore
  4084. * @param {Element} doc 编辑器Iframe中的文档对象
  4085. */
  4086. _setup: function (doc) {
  4087. var me = this,
  4088. options = me.options;
  4089. if (ie) {
  4090. doc.body.disabled = true;
  4091. doc.body.contentEditable = true;
  4092. doc.body.disabled = false;
  4093. } else {
  4094. doc.body.contentEditable = true;
  4095. }
  4096. doc.body.spellcheck = false;
  4097. me.document = doc;
  4098. me.window = doc.defaultView || doc.parentWindow;
  4099. me.iframe = me.window.frameElement;
  4100. me.body = doc.body;
  4101. me.selection = new dom.Selection(doc);
  4102. //gecko初始化就能得到range,无法判断isFocus了
  4103. var geckoSel;
  4104. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  4105. geckoSel.removeAllRanges();
  4106. }
  4107. this._initEvents();
  4108. //为form提交提供一个隐藏的textarea
  4109. for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form.parentNode) {
  4110. if (form.tagName == 'FORM') {
  4111. me.form = form;
  4112. if (me.options.autoSyncData) {
  4113. domUtils.on(me.window, 'blur', function () {
  4114. setValue(form, me);
  4115. });
  4116. } else {
  4117. domUtils.on(form, 'submit', function () {
  4118. setValue(this, me);
  4119. });
  4120. }
  4121. break;
  4122. }
  4123. }
  4124. if (options.initialContent) {
  4125. if (options.autoClearinitialContent) {
  4126. var oldExecCommand = me.execCommand;
  4127. me.execCommand = function () {
  4128. me.fireEvent('firstBeforeExecCommand');
  4129. return oldExecCommand.apply(me, arguments);
  4130. };
  4131. this._setDefaultContent(options.initialContent);
  4132. } else
  4133. this.setContent(options.initialContent, false, true);
  4134. }
  4135. //编辑器不能为空内容
  4136. if (domUtils.isEmptyNode(me.body)) {
  4137. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  4138. }
  4139. //如果要求focus, 就把光标定位到内容开始
  4140. if (options.focus) {
  4141. setTimeout(function () {
  4142. me.focus(me.options.focusInEnd);
  4143. //如果自动清除开着,就不需要做selectionchange;
  4144. !me.options.autoClearinitialContent && me._selectionChange();
  4145. }, 0);
  4146. }
  4147. if (!me.container) {
  4148. me.container = this.iframe.parentNode;
  4149. }
  4150. if (options.fullscreen && me.ui) {
  4151. me.ui.setFullScreen(true);
  4152. }
  4153. try {
  4154. me.document.execCommand('2D-position', false, false);
  4155. } catch (e) {
  4156. }
  4157. try {
  4158. me.document.execCommand('enableInlineTableEditing', false, false);
  4159. } catch (e) {
  4160. }
  4161. try {
  4162. me.document.execCommand('enableObjectResizing', false, false);
  4163. } catch (e) {
  4164. // domUtils.on(me.body,browser.ie ? 'resizestart' : 'resize', function( evt ) {
  4165. // domUtils.preventDefault(evt)
  4166. // });
  4167. }
  4168. me._bindshortcutKeys();
  4169. me.isReady = 1;
  4170. me.fireEvent('ready');
  4171. options.onready && options.onready.call(me);
  4172. if (!browser.ie) {
  4173. domUtils.on(me.window, ['blur', 'focus'], function (e) {
  4174. //chrome下会出现alt+tab切换时,导致选区位置不对
  4175. if (e.type == 'blur') {
  4176. me._bakRange = me.selection.getRange();
  4177. try {
  4178. me._bakNativeRange = me.selection.getNative().getRangeAt(0);
  4179. me.selection.getNative().removeAllRanges();
  4180. } catch (e) {
  4181. me._bakNativeRange = null;
  4182. }
  4183. } else {
  4184. try {
  4185. me._bakRange && me._bakRange.select();
  4186. } catch (e) {
  4187. }
  4188. }
  4189. });
  4190. }
  4191. //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
  4192. if (browser.gecko && browser.version <= 10902) {
  4193. //修复ff3.6初始化进来,不能点击获得焦点
  4194. me.body.contentEditable = false;
  4195. setTimeout(function () {
  4196. me.body.contentEditable = true;
  4197. }, 100);
  4198. setInterval(function () {
  4199. me.body.style.height = me.iframe.offsetHeight - 20 + 'px'
  4200. }, 100)
  4201. }
  4202. !options.isShow && me.setHide();
  4203. options.readonly && me.setDisabled();
  4204. },
  4205. /**
  4206. * 同步编辑器的数据,为提交数据做准备,主要用于你是手动提交的情况
  4207. * @name sync
  4208. * @grammar editor.sync(); //从编辑器的容器向上查找,如果找到就同步数据
  4209. * @grammar editor.sync(formID); //formID制定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
  4210. * @desc
  4211. * 后台取得数据得键值使用你容器上得''name''属性,如果没有就使用参数传入的''textarea''
  4212. * @example
  4213. * editor.sync();
  4214. * form.sumbit(); //form变量已经指向了form元素
  4215. *
  4216. */
  4217. sync: function (formId) {
  4218. var me = this,
  4219. form = formId ? document.getElementById(formId) :
  4220. domUtils.findParent(me.iframe.parentNode, function (node) {
  4221. return node.tagName == 'FORM'
  4222. }, true);
  4223. form && setValue(form, me);
  4224. },
  4225. /**
  4226. * 设置编辑器高度
  4227. * @name setHeight
  4228. * @grammar editor.setHeight(number); //纯数值,不带单位
  4229. */
  4230. setHeight: function (height, notSetHeight) {
  4231. if (height !== parseInt(this.iframe.parentNode.style.height)) {
  4232. this.iframe.parentNode.style.height = height + 'px';
  4233. }
  4234. !notSetHeight && (this.options.minFrameHeight = this.options.initialFrameHeight = height);
  4235. this.body.style.height = height + 'px';
  4236. },
  4237. addshortcutkey: function (cmd, keys) {
  4238. var obj = {};
  4239. if (keys) {
  4240. obj[cmd] = keys
  4241. } else {
  4242. obj = cmd;
  4243. }
  4244. utils.extend(this.shortcutkeys, obj)
  4245. },
  4246. _bindshortcutKeys: function () {
  4247. var me = this, shortcutkeys = this.shortcutkeys;
  4248. me.addListener('keydown', function (type, e) {
  4249. var keyCode = e.keyCode || e.which;
  4250. for (var i in shortcutkeys) {
  4251. var tmp = shortcutkeys[i].split(',');
  4252. for (var t = 0, ti; ti = tmp[t++];) {
  4253. ti = ti.split(':');
  4254. var key = ti[0], param = ti[1];
  4255. if (/^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) || /^(\d+)$/.test(key)) {
  4256. if (( (RegExp.$1 == 'ctrl' ? (e.ctrlKey || e.metaKey) : 0)
  4257. && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1)
  4258. && keyCode == RegExp.$3
  4259. ) ||
  4260. keyCode == RegExp.$1
  4261. ) {
  4262. if (me.queryCommandState(i, param) != -1)
  4263. me.execCommand(i, param);
  4264. domUtils.preventDefault(e);
  4265. }
  4266. }
  4267. }
  4268. }
  4269. });
  4270. },
  4271. /**
  4272. * 获取编辑器内容
  4273. * @name getContent
  4274. * @grammar editor.getContent() => String //若编辑器中只包含字符"&lt;p&gt;&lt;br /&gt;&lt;/p/&gt;"会返回空。
  4275. * @grammar editor.getContent(fn) => String
  4276. * @example
  4277. * getContent默认是会现调用hasContents来判断编辑器是否为空,如果是,就直接返回空字符串
  4278. * 你也可以传入一个fn来接替hasContents的工作,定制判断的规则
  4279. * editor.getContent(function(){
  4280. * return false //编辑器没有内容 ,getContent直接返回空
  4281. * })
  4282. */
  4283. getContent: function (cmd, fn, notSetCursor, ignoreBlank, formatter) {
  4284. var me = this;
  4285. if (cmd && utils.isFunction(cmd)) {
  4286. fn = cmd;
  4287. cmd = '';
  4288. }
  4289. if (fn ? !fn() : !this.hasContents()) {
  4290. return '';
  4291. }
  4292. me.fireEvent('beforegetcontent');
  4293. var root = UE.htmlparser(me.body.innerHTML, ignoreBlank);
  4294. me.filterOutputRule(root);
  4295. me.fireEvent('aftergetcontent', cmd);
  4296. return root.toHtml(formatter);
  4297. },
  4298. /**
  4299. * 取得完整的html代码,可以直接显示成完整的html文档
  4300. * @name getAllHtml
  4301. * @grammar editor.getAllHtml() => String
  4302. */
  4303. getAllHtml: function () {
  4304. var me = this,
  4305. headHtml = [],
  4306. html = '';
  4307. me.fireEvent('getAllHtml', headHtml);
  4308. if (browser.ie && browser.version > 8) {
  4309. var headHtmlForIE9 = '';
  4310. utils.each(me.document.styleSheets, function (si) {
  4311. headHtmlForIE9 += ( si.href ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />' : '<style>' + si.cssText + '</style>');
  4312. });
  4313. utils.each(me.document.getElementsByTagName('script'), function (si) {
  4314. headHtmlForIE9 += si.outerHTML;
  4315. });
  4316. }
  4317. return '<html><head>' + (me.options.charset ? '<meta http-equiv="Content-Type" content="text/html; charset=' + me.options.charset + '"/>' : '')
  4318. + (headHtmlForIE9 || me.document.getElementsByTagName('head')[0].innerHTML) + headHtml.join('\n') + '</head>'
  4319. + '<body ' + (ie && browser.version < 9 ? 'class="view"' : '') + '>' + me.getContent(null, null, true) + '</body></html>';
  4320. },
  4321. /**
  4322. * 得到编辑器的纯文本内容,但会保留段落格式
  4323. * @name getPlainTxt
  4324. * @grammar editor.getPlainTxt() => String
  4325. */
  4326. getPlainTxt: function () {
  4327. var reg = new RegExp(domUtils.fillChar, 'g'),
  4328. html = this.body.innerHTML.replace(/[\n\r]/g, '');//ie要先去了\n在处理
  4329. html = html.replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, '\n')
  4330. .replace(/<br\/?>/gi, '\n')
  4331. .replace(/<[^>/]+>/g, '')
  4332. .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
  4333. return dtd.$block[c] ? '\n' : b ? b : '';
  4334. });
  4335. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  4336. return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/&nbsp;/g, ' ');
  4337. },
  4338. /**
  4339. * 获取编辑器中的纯文本内容,没有段落格式
  4340. * @name getContentTxt
  4341. * @grammar editor.getContentTxt() => String
  4342. */
  4343. getContentTxt: function () {
  4344. var reg = new RegExp(domUtils.fillChar, 'g');
  4345. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  4346. return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' ');
  4347. },
  4348. /**
  4349. * 将html设置到编辑器中, 如果是用于初始化时给编辑器赋初值,则必须放在ready方法内部执行
  4350. * @name setContent
  4351. * @grammar editor.setContent(html)
  4352. * @example
  4353. * var editor = new UE.ui.Editor()
  4354. * editor.ready(function(){
  4355. * //需要ready后执行,否则可能报错
  4356. * editor.setContent("欢迎使用UEditor!");
  4357. * })
  4358. */
  4359. setContent: function (html, isAppendTo, notFireSelectionchange) {
  4360. var me = this;
  4361. me.fireEvent('beforesetcontent', html);
  4362. var root = UE.htmlparser(html);
  4363. me.filterInputRule(root);
  4364. html = root.toHtml();
  4365. me.body.innerHTML = (isAppendTo ? me.body.innerHTML : '') + html;
  4366. function isCdataDiv(node) {
  4367. return node.tagName == 'DIV' && node.getAttribute('cdata_tag');
  4368. }
  4369. //给文本或者inline节点套p标签
  4370. if (me.options.enterTag == 'p') {
  4371. var child = this.body.firstChild, tmpNode;
  4372. if (!child || child.nodeType == 1 &&
  4373. (dtd.$cdata[child.tagName] || isCdataDiv(child) ||
  4374. domUtils.isCustomeNode(child)
  4375. )
  4376. && child === this.body.lastChild) {
  4377. this.body.innerHTML = '<p>' + (browser.ie ? '&nbsp;' : '<br/>') + '</p>' + this.body.innerHTML;
  4378. } else {
  4379. var p = me.document.createElement('p');
  4380. while (child) {
  4381. while (child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child.tagName] && !dtd.$cdata[child.tagName])) {
  4382. tmpNode = child.nextSibling;
  4383. p.appendChild(child);
  4384. child = tmpNode;
  4385. }
  4386. if (p.firstChild) {
  4387. if (!child) {
  4388. me.body.appendChild(p);
  4389. break;
  4390. } else {
  4391. child.parentNode.insertBefore(p, child);
  4392. p = me.document.createElement('p');
  4393. }
  4394. }
  4395. child = child.nextSibling;
  4396. }
  4397. }
  4398. }
  4399. me.fireEvent('aftersetcontent');
  4400. me.fireEvent('contentchange');
  4401. !notFireSelectionchange && me._selectionChange();
  4402. //清除保存的选区
  4403. me._bakRange = me._bakIERange = me._bakNativeRange = null;
  4404. //trace:1742 setContent后gecko能得到焦点问题
  4405. var geckoSel;
  4406. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  4407. geckoSel.removeAllRanges();
  4408. }
  4409. if (me.options.autoSyncData) {
  4410. me.form && setValue(me.form, me);
  4411. }
  4412. },
  4413. /**
  4414. * 让编辑器获得焦点,toEnd确定focus位置
  4415. * @name focus
  4416. * @grammar editor.focus([toEnd]) //默认focus到编辑器头部,toEnd为true时focus到内容尾部
  4417. */
  4418. focus: function (toEnd) {
  4419. try {
  4420. var me = this,
  4421. rng = me.selection.getRange();
  4422. if (toEnd) {
  4423. rng.setStartAtLast(me.body.lastChild).setCursor(false, true);
  4424. } else {
  4425. rng.select(true);
  4426. }
  4427. this.fireEvent('focus');
  4428. } catch (e) {
  4429. }
  4430. },
  4431. /**
  4432. * 初始化UE事件及部分事件代理
  4433. * @private
  4434. * @ignore
  4435. */
  4436. _initEvents: function () {
  4437. var me = this,
  4438. doc = me.document,
  4439. win = me.window;
  4440. me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
  4441. domUtils.on(doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent);
  4442. domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent);
  4443. domUtils.on(doc, ['mouseup', 'keydown'], function (evt) {
  4444. //特殊键不触发selectionchange
  4445. if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
  4446. return;
  4447. }
  4448. if (evt.button == 2)return;
  4449. me._selectionChange(250, evt);
  4450. });
  4451. // //处理拖拽
  4452. // //ie ff不能从外边拖入
  4453. // //chrome只针对从外边拖入的内容过滤
  4454. // var innerDrag = 0, source = browser.ie ? me.body : me.document, dragoverHandler;
  4455. // domUtils.on(source, 'dragstart', function () {
  4456. // innerDrag = 1;
  4457. // });
  4458. // domUtils.on(source, browser.webkit ? 'dragover' : 'drop', function () {
  4459. // return browser.webkit ?
  4460. // function () {
  4461. // clearTimeout(dragoverHandler);
  4462. // dragoverHandler = setTimeout(function () {
  4463. // if (!innerDrag) {
  4464. // var sel = me.selection,
  4465. // range = sel.getRange();
  4466. // if (range) {
  4467. // var common = range.getCommonAncestor();
  4468. // if (common && me.serialize) {
  4469. // var f = me.serialize,
  4470. // node =
  4471. // f.filter(
  4472. // f.transformInput(
  4473. // f.parseHTML(
  4474. // f.word(common.innerHTML)
  4475. // )
  4476. // )
  4477. // );
  4478. // common.innerHTML = f.toHTML(node);
  4479. // }
  4480. // }
  4481. // }
  4482. // innerDrag = 0;
  4483. // }, 200);
  4484. // } :
  4485. // function (e) {
  4486. // if (!innerDrag) {
  4487. // e.preventDefault ? e.preventDefault() : (e.returnValue = false);
  4488. // }
  4489. // innerDrag = 0;
  4490. // }
  4491. // }());
  4492. },
  4493. /**
  4494. * 触发事件代理
  4495. * @private
  4496. * @ignore
  4497. */
  4498. _proxyDomEvent: function (evt) {
  4499. return this.fireEvent(evt.type.replace(/^on/, ''), evt);
  4500. },
  4501. /**
  4502. * 变化选区
  4503. * @private
  4504. * @ignore
  4505. */
  4506. _selectionChange: function (delay, evt) {
  4507. var me = this;
  4508. //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
  4509. // if ( !me.selection.isFocus() ){
  4510. // return;
  4511. // }
  4512. var hackForMouseUp = false;
  4513. var mouseX, mouseY;
  4514. if (browser.ie && browser.version < 9 && evt && evt.type == 'mouseup') {
  4515. var range = this.selection.getRange();
  4516. if (!range.collapsed) {
  4517. hackForMouseUp = true;
  4518. mouseX = evt.clientX;
  4519. mouseY = evt.clientY;
  4520. }
  4521. }
  4522. clearTimeout(_selectionChangeTimer);
  4523. _selectionChangeTimer = setTimeout(function () {
  4524. if (!me.selection.getNative()) {
  4525. return;
  4526. }
  4527. //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
  4528. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
  4529. var ieRange;
  4530. if (hackForMouseUp && me.selection.getNative().type == 'None') {
  4531. ieRange = me.document.body.createTextRange();
  4532. try {
  4533. ieRange.moveToPoint(mouseX, mouseY);
  4534. } catch (ex) {
  4535. ieRange = null;
  4536. }
  4537. }
  4538. var bakGetIERange;
  4539. if (ieRange) {
  4540. bakGetIERange = me.selection.getIERange;
  4541. me.selection.getIERange = function () {
  4542. return ieRange;
  4543. };
  4544. }
  4545. me.selection.cache();
  4546. if (bakGetIERange) {
  4547. me.selection.getIERange = bakGetIERange;
  4548. }
  4549. if (me.selection._cachedRange && me.selection._cachedStartElement) {
  4550. me.fireEvent('beforeselectionchange');
  4551. // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
  4552. me.fireEvent('selectionchange', !!evt);
  4553. me.fireEvent('afterselectionchange');
  4554. me.selection.clear();
  4555. }
  4556. }, delay || 50);
  4557. },
  4558. _callCmdFn: function (fnName, args) {
  4559. var cmdName = args[0].toLowerCase(),
  4560. cmd, cmdFn;
  4561. cmd = this.commands[cmdName] || UE.commands[cmdName];
  4562. cmdFn = cmd && cmd[fnName];
  4563. //没有querycommandstate或者没有command的都默认返回0
  4564. if ((!cmd || !cmdFn) && fnName == 'queryCommandState') {
  4565. return 0;
  4566. } else if (cmdFn) {
  4567. return cmdFn.apply(this, args);
  4568. }
  4569. },
  4570. /**
  4571. * 执行编辑命令cmdName,完成富文本编辑效果
  4572. * @name execCommand
  4573. * @grammar editor.execCommand(cmdName) => {*}
  4574. */
  4575. execCommand: function (cmdName) {
  4576. cmdName = cmdName.toLowerCase();
  4577. var me = this,
  4578. result,
  4579. cmd = me.commands[cmdName] || UE.commands[cmdName];
  4580. if (!cmd || !cmd.execCommand) {
  4581. return null;
  4582. }
  4583. if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
  4584. me.__hasEnterExecCommand = true;
  4585. if (me.queryCommandState.apply(me, arguments) != -1) {
  4586. me.fireEvent('beforeexeccommand', cmdName);
  4587. result = this._callCmdFn('execCommand', arguments);
  4588. !me._ignoreContentChange && me.fireEvent('contentchange');
  4589. me.fireEvent('afterexeccommand', cmdName);
  4590. }
  4591. me.__hasEnterExecCommand = false;
  4592. } else {
  4593. result = this._callCmdFn('execCommand', arguments);
  4594. !me._ignoreContentChange && me.fireEvent('contentchange')
  4595. }
  4596. !me._ignoreContentChange && me._selectionChange();
  4597. return result;
  4598. },
  4599. /**
  4600. * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
  4601. * @name queryCommandState
  4602. * @grammar editor.queryCommandState(cmdName) => (-1|0|1)
  4603. * @desc
  4604. * * ''-1'' 当前命令不可用
  4605. * * ''0'' 当前命令可用
  4606. * * ''1'' 当前命令已经执行过了
  4607. */
  4608. queryCommandState: function (cmdName) {
  4609. return this._callCmdFn('queryCommandState', arguments);
  4610. },
  4611. /**
  4612. * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
  4613. * @name queryCommandValue
  4614. * @grammar editor.queryCommandValue(cmdName) => {*}
  4615. */
  4616. queryCommandValue: function (cmdName) {
  4617. return this._callCmdFn('queryCommandValue', arguments);
  4618. },
  4619. /**
  4620. * 检查编辑区域中是否有内容,若包含tags中的节点类型,直接返回true
  4621. * @name hasContents
  4622. * @desc
  4623. * 默认有文本内容,或者有以下节点都不认为是空
  4624. * <code>{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}</code>
  4625. * @grammar editor.hasContents() => (true|false)
  4626. * @grammar editor.hasContents(tags) => (true|false) //若文档中包含tags数组里对应的tag,直接返回true
  4627. * @example
  4628. * editor.hasContents(['span']) //如果编辑器里有这些,不认为是空
  4629. */
  4630. hasContents: function (tags) {
  4631. if (tags) {
  4632. for (var i = 0, ci; ci = tags[i++];) {
  4633. if (this.document.getElementsByTagName(ci).length > 0) {
  4634. return true;
  4635. }
  4636. }
  4637. }
  4638. if (!domUtils.isEmptyBlock(this.body)) {
  4639. return true
  4640. }
  4641. //随时添加,定义的特殊标签如果存在,不能认为是空
  4642. tags = ['div'];
  4643. for (i = 0; ci = tags[i++];) {
  4644. var nodes = domUtils.getElementsByTagName(this.document, ci);
  4645. for (var n = 0, cn; cn = nodes[n++];) {
  4646. if (domUtils.isCustomeNode(cn)) {
  4647. return true;
  4648. }
  4649. }
  4650. }
  4651. return false;
  4652. },
  4653. /**
  4654. * 重置编辑器,可用来做多个tab使用同一个编辑器实例
  4655. * @name reset
  4656. * @desc
  4657. * * 清空编辑器内容
  4658. * * 清空回退列表
  4659. * @grammar editor.reset()
  4660. */
  4661. reset: function () {
  4662. this.fireEvent('reset');
  4663. },
  4664. setEnabled: function () {
  4665. var me = this, range;
  4666. if (me.body.contentEditable == 'false') {
  4667. me.body.contentEditable = true;
  4668. range = me.selection.getRange();
  4669. //有可能内容丢失了
  4670. try {
  4671. range.moveToBookmark(me.lastBk);
  4672. delete me.lastBk
  4673. } catch (e) {
  4674. range.setStartAtFirst(me.body).collapse(true)
  4675. }
  4676. range.select(true);
  4677. if (me.bkqueryCommandState) {
  4678. me.queryCommandState = me.bkqueryCommandState;
  4679. delete me.bkqueryCommandState;
  4680. }
  4681. me.fireEvent('selectionchange');
  4682. }
  4683. },
  4684. /**
  4685. * 设置当前编辑区域可以编辑
  4686. * @name enable
  4687. * @grammar editor.enable()
  4688. */
  4689. enable: function () {
  4690. return this.setEnabled();
  4691. },
  4692. setDisabled: function (except) {
  4693. var me = this;
  4694. except = except ? utils.isArray(except) ? except : [except] : [];
  4695. if (me.body.contentEditable == 'true') {
  4696. if (!me.lastBk) {
  4697. me.lastBk = me.selection.getRange().createBookmark(true);
  4698. }
  4699. me.body.contentEditable = false;
  4700. me.bkqueryCommandState = me.queryCommandState;
  4701. me.queryCommandState = function (type) {
  4702. if (utils.indexOf(except, type) != -1) {
  4703. return me.bkqueryCommandState.apply(me, arguments);
  4704. }
  4705. return -1;
  4706. };
  4707. me.fireEvent('selectionchange');
  4708. }
  4709. },
  4710. /** 设置当前编辑区域不可编辑,except中的命令除外
  4711. * @name disable
  4712. * @grammar editor.disable()
  4713. * @grammar editor.disable(except) //例外的命令,也即即使设置了disable,此处配置的命令仍然可以执行
  4714. * @example
  4715. * //禁用工具栏中除加粗和插入图片之外的所有功能
  4716. * editor.disable(['bold','insertimage']);//可以是单一的String,也可以是Array
  4717. */
  4718. disable: function (except) {
  4719. return this.setDisabled(except);
  4720. },
  4721. /**
  4722. * 设置默认内容
  4723. * @ignore
  4724. * @private
  4725. * @param {String} cont 要存入的内容
  4726. */
  4727. _setDefaultContent: function () {
  4728. function clear() {
  4729. var me = this;
  4730. if (me.document.getElementById('initContent')) {
  4731. me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>';
  4732. me.removeListener('firstBeforeExecCommand focus', clear);
  4733. setTimeout(function () {
  4734. me.focus();
  4735. me._selectionChange();
  4736. }, 0)
  4737. }
  4738. }
  4739. return function (cont) {
  4740. var me = this;
  4741. me.body.innerHTML = '<p id="initContent">' + cont + '</p>';
  4742. me.addListener('firstBeforeExecCommand focus', clear);
  4743. }
  4744. }(),
  4745. /**
  4746. * show方法的兼容版本
  4747. * @private
  4748. * @ignore
  4749. */
  4750. setShow: function () {
  4751. var me = this, range = me.selection.getRange();
  4752. if (me.container.style.display == 'none') {
  4753. //有可能内容丢失了
  4754. try {
  4755. range.moveToBookmark(me.lastBk);
  4756. delete me.lastBk
  4757. } catch (e) {
  4758. range.setStartAtFirst(me.body).collapse(true)
  4759. }
  4760. //ie下focus实效,所以做了个延迟
  4761. setTimeout(function () {
  4762. range.select(true);
  4763. }, 100);
  4764. me.container.style.display = '';
  4765. }
  4766. },
  4767. /**
  4768. * 显示编辑器
  4769. * @name show
  4770. * @grammar editor.show()
  4771. */
  4772. show: function () {
  4773. return this.setShow();
  4774. },
  4775. /**
  4776. * hide方法的兼容版本
  4777. * @private
  4778. * @ignore
  4779. */
  4780. setHide: function () {
  4781. var me = this;
  4782. if (!me.lastBk) {
  4783. me.lastBk = me.selection.getRange().createBookmark(true);
  4784. }
  4785. me.container.style.display = 'none'
  4786. },
  4787. /**
  4788. * 隐藏编辑器
  4789. * @name hide
  4790. * @grammar editor.hide()
  4791. */
  4792. hide: function () {
  4793. return this.setHide();
  4794. },
  4795. /**
  4796. * 根据制定的路径,获取对应的语言资源
  4797. * @name getLang
  4798. * @grammar editor.getLang(path) => (JSON|String) 路径根据的是lang目录下的语言文件的路径结构
  4799. * @example
  4800. * editor.getLang('contextMenu.delete') //如果当前是中文,那返回是的是删除
  4801. */
  4802. getLang: function (path) {
  4803. var lang = UE.I18N[this.options.lang];
  4804. if (!lang) {
  4805. throw Error("not import language file");
  4806. }
  4807. path = (path || "").split(".");
  4808. for (var i = 0, ci; ci = path[i++];) {
  4809. lang = lang[ci];
  4810. if (!lang)break;
  4811. }
  4812. return lang;
  4813. },
  4814. /**
  4815. * 计算编辑器当前内容的长度
  4816. * @name getContentLength
  4817. * @grammar editor.getContentLength(ingoneHtml,tagNames) =>
  4818. * @example
  4819. * editor.getLang(true)
  4820. */
  4821. getContentLength: function (ingoneHtml, tagNames) {
  4822. var count = this.getContent(false, false, true).length;
  4823. if (ingoneHtml) {
  4824. tagNames = (tagNames || []).concat([ 'hr', 'img', 'iframe']);
  4825. count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length;
  4826. for (var i = 0, ci; ci = tagNames[i++];) {
  4827. count += this.document.getElementsByTagName(ci).length;
  4828. }
  4829. }
  4830. return count;
  4831. },
  4832. addInputRule: function (rule) {
  4833. this.inputRules.push(rule);
  4834. },
  4835. filterInputRule: function (root) {
  4836. for (var i = 0, ci; ci = this.inputRules[i++];) {
  4837. ci.call(this, root)
  4838. }
  4839. },
  4840. addOutputRule: function (rule) {
  4841. this.outputRules.push(rule)
  4842. },
  4843. filterOutputRule: function (root) {
  4844. for (var i = 0, ci; ci = this.outputRules[i++];) {
  4845. ci.call(this, root)
  4846. }
  4847. }
  4848. /**
  4849. * 得到dialog实例对象
  4850. * @name getDialog
  4851. * @grammar editor.getDialog(dialogName) => Object
  4852. * @example
  4853. * var dialog = editor.getDialog("insertimage");
  4854. * dialog.open(); //打开dialog
  4855. * dialog.close(); //关闭dialog
  4856. */
  4857. };
  4858. utils.inherits(Editor, EventBase);
  4859. })();
  4860. /**
  4861. * @file
  4862. * @name UE.ajax
  4863. * @short Ajax
  4864. * @desc UEditor内置的ajax请求模块
  4865. * @import core/utils.js
  4866. * @user: taoqili
  4867. * @date: 11-8-18
  4868. * @time: 下午3:18
  4869. */
  4870. UE.ajax = function () {
  4871. /**
  4872. * 创建一个ajaxRequest对象
  4873. */
  4874. var fnStr = 'XMLHttpRequest()';
  4875. try {
  4876. new ActiveXObject("Msxml2.XMLHTTP");
  4877. fnStr = 'ActiveXObject(\'Msxml2.XMLHTTP\')';
  4878. } catch (e) {
  4879. try {
  4880. new ActiveXObject("Microsoft.XMLHTTP");
  4881. fnStr = 'ActiveXObject(\'Microsoft.XMLHTTP\')'
  4882. } catch (e) {
  4883. }
  4884. }
  4885. var creatAjaxRequest = new Function('return new ' + fnStr);
  4886. /**
  4887. * 将json参数转化成适合ajax提交的参数列表
  4888. * @param json
  4889. */
  4890. function json2str(json) {
  4891. var strArr = [];
  4892. for (var i in json) {
  4893. //忽略默认的几个参数
  4894. if (i == "method" || i == "timeout" || i == "async") continue;
  4895. //传递过来的对象和函数不在提交之列
  4896. if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) {
  4897. strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]));
  4898. }
  4899. }
  4900. return strArr.join("&");
  4901. }
  4902. return {
  4903. /**
  4904. * @name request
  4905. * @desc 发出ajax请求,ajaxOpt中默认包含method,timeout,async,data,onsuccess以及onerror等六个,支持自定义添加参数
  4906. * @grammar UE.ajax.request(url,ajaxOpt);
  4907. * @example
  4908. * UE.ajax.request('http://www.xxxx.com/test.php',{
  4909. * //可省略,默认POST
  4910. * method:'POST',
  4911. * //可以自定义参数
  4912. * content:'这里是提交的内容',
  4913. * //也可以直接传json,但是只能命名为data,否则当做一般字符串处理
  4914. * data:{
  4915. * name:'UEditor',
  4916. * age:'1'
  4917. * }
  4918. * onsuccess:function(xhr){
  4919. * console.log(xhr.responseText);
  4920. * },
  4921. * onerror:function(xhr){
  4922. * console.log(xhr.responseText);
  4923. * }
  4924. * })
  4925. * @param ajaxOptions
  4926. */
  4927. request: function (url, ajaxOptions) {
  4928. var ajaxRequest = creatAjaxRequest(),
  4929. //是否超时
  4930. timeIsOut = false,
  4931. //默认参数
  4932. defaultAjaxOptions = {
  4933. method: "POST",
  4934. timeout: 5000,
  4935. async: true,
  4936. data: {},//需要传递对象的话只能覆盖
  4937. onsuccess: function () {
  4938. },
  4939. onerror: function () {
  4940. }
  4941. };
  4942. if (typeof url === "object") {
  4943. ajaxOptions = url;
  4944. url = ajaxOptions.url;
  4945. }
  4946. if (!ajaxRequest || !url) return;
  4947. var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions, ajaxOptions) : defaultAjaxOptions;
  4948. var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  4949. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  4950. if (!utils.isEmptyObject(ajaxOpts.data)) {
  4951. submitStr += (submitStr ? "&" : "") + json2str(ajaxOpts.data);
  4952. }
  4953. //超时检测
  4954. var timerID = setTimeout(function () {
  4955. if (ajaxRequest.readyState != 4) {
  4956. timeIsOut = true;
  4957. ajaxRequest.abort();
  4958. clearTimeout(timerID);
  4959. }
  4960. }, ajaxOpts.timeout);
  4961. var method = ajaxOpts.method.toUpperCase();
  4962. var str = url + (url.indexOf("?") == -1 ? "?" : "&") + (method == "POST" ? "" : submitStr + "&noCache=" + +new Date);
  4963. ajaxRequest.open(method, str, ajaxOpts.async);
  4964. ajaxRequest.onreadystatechange = function () {
  4965. if (ajaxRequest.readyState == 4) {
  4966. if (!timeIsOut && ajaxRequest.status == 200) {
  4967. ajaxOpts.onsuccess(ajaxRequest);
  4968. } else {
  4969. ajaxOpts.onerror(ajaxRequest);
  4970. }
  4971. }
  4972. };
  4973. if (method == "POST") {
  4974. ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  4975. ajaxRequest.send(submitStr);
  4976. } else {
  4977. ajaxRequest.send(null);
  4978. }
  4979. }
  4980. };
  4981. }();
  4982. /**
  4983. * @file
  4984. * @name UE.filterWord
  4985. * @short filterWord
  4986. * @desc 用来过滤word粘贴过来的字符串
  4987. * @import editor.js,core/utils.js
  4988. * @anthor zhanyi
  4989. */
  4990. var filterWord = UE.filterWord = function () {
  4991. //是否是word过来的内容
  4992. function isWordDocument(str) {
  4993. return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<v:)/ig.test(str);
  4994. }
  4995. //去掉小数
  4996. function transUnit(v) {
  4997. v = v.replace(/[\d.]+\w+/g, function (m) {
  4998. return utils.transUnitToPx(m);
  4999. });
  5000. return v;
  5001. }
  5002. function filterPasteWord(str) {
  5003. return str.replace(/[\t\r\n]+/g, "")
  5004. .replace(/<!--[\s\S]*?-->/ig, "")
  5005. //转换图片
  5006. .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi, function (str) {
  5007. //opera能自己解析出image所这里直接返回空
  5008. if (browser.opera) {
  5009. return '';
  5010. }
  5011. try {
  5012. var width = str.match(/width:([ \d.]*p[tx])/i)[1],
  5013. height = str.match(/height:([ \d.]*p[tx])/i)[1],
  5014. src = str.match(/src=\s*"([^"]*)"/i)[1];
  5015. return '<img width="' + transUnit(width) + '" height="' + transUnit(height) + '" src="' + src + '" />';
  5016. } catch (e) {
  5017. return '';
  5018. }
  5019. })
  5020. //针对wps添加的多余标签处理
  5021. .replace(/<\/?div[^>]*>/g, '')
  5022. //去掉多余的属性
  5023. .replace(/v:\w+=(["']?)[^'"]+\1/g, '')
  5024. .replace(/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "")
  5025. .replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>")
  5026. //去掉多余的属性
  5027. .replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/ig, function (str, name, marks, val) {
  5028. //保留list的标示
  5029. return name == 'class' && val == 'MsoListParagraph' ? str : ''
  5030. })
  5031. //清除多余的font/span不能匹配&nbsp;有可能是空格
  5032. .replace(/<(font|span)[^>]*>\s*<\/\1>/gi, '')
  5033. //处理style的问题
  5034. .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (str, tag, tmp, style) {
  5035. var n = [],
  5036. s = style.replace(/^\s+|\s+$/, '')
  5037. .replace(/&#39;/g, '\'')
  5038. .replace(/&quot;/gi, "'")
  5039. .split(/;\s*/g);
  5040. for (var i = 0, v; v = s[i]; i++) {
  5041. var name, value,
  5042. parts = v.split(":");
  5043. if (parts.length == 2) {
  5044. name = parts[0].toLowerCase();
  5045. value = parts[1].toLowerCase();
  5046. if (/^(background)\w*/.test(name) && value.replace(/(initial|\s)/g, '').length == 0
  5047. ||
  5048. /^(margin)\w*/.test(name) && /^0\w+$/.test(value)
  5049. ) {
  5050. continue;
  5051. }
  5052. switch (name) {
  5053. case "mso-padding-alt":
  5054. case "mso-padding-top-alt":
  5055. case "mso-padding-right-alt":
  5056. case "mso-padding-bottom-alt":
  5057. case "mso-padding-left-alt":
  5058. case "mso-margin-alt":
  5059. case "mso-margin-top-alt":
  5060. case "mso-margin-right-alt":
  5061. case "mso-margin-bottom-alt":
  5062. case "mso-margin-left-alt":
  5063. //ie下会出现挤到一起的情况
  5064. //case "mso-table-layout-alt":
  5065. case "mso-height":
  5066. case "mso-width":
  5067. case "mso-vertical-align-alt":
  5068. //trace:1819 ff下会解析出padding在table上
  5069. if (!/<table/.test(tag))
  5070. n[i] = name.replace(/^mso-|-alt$/g, "") + ":" + transUnit(value);
  5071. continue;
  5072. case "horiz-align":
  5073. n[i] = "text-align:" + value;
  5074. continue;
  5075. case "vert-align":
  5076. n[i] = "vertical-align:" + value;
  5077. continue;
  5078. case "font-color":
  5079. case "mso-foreground":
  5080. n[i] = "color:" + value;
  5081. continue;
  5082. case "mso-background":
  5083. case "mso-highlight":
  5084. n[i] = "background:" + value;
  5085. continue;
  5086. case "mso-default-height":
  5087. n[i] = "min-height:" + transUnit(value);
  5088. continue;
  5089. case "mso-default-width":
  5090. n[i] = "min-width:" + transUnit(value);
  5091. continue;
  5092. case "mso-padding-between-alt":
  5093. n[i] = "border-collapse:separate;border-spacing:" + transUnit(value);
  5094. continue;
  5095. case "text-line-through":
  5096. if ((value == "single") || (value == "double")) {
  5097. n[i] = "text-decoration:line-through";
  5098. }
  5099. continue;
  5100. case "mso-zero-height":
  5101. if (value == "yes") {
  5102. n[i] = "display:none";
  5103. }
  5104. continue;
  5105. case 'background':
  5106. break;
  5107. case 'margin':
  5108. if (!/[1-9]/.test(value)) {
  5109. continue;
  5110. }
  5111. }
  5112. 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)
  5113. ||
  5114. /text\-indent|padding|margin/.test(name) && /\-[\d.]+/.test(value)
  5115. ) {
  5116. continue;
  5117. }
  5118. n[i] = name + ":" + parts[1];
  5119. }
  5120. }
  5121. return tag + (n.length ? ' style="' + n.join(';').replace(/;{2,}/g, ';') + '"' : '');
  5122. })
  5123. .replace(/[\d.]+(cm|pt)/g, function (str) {
  5124. return utils.transUnitToPx(str)
  5125. })
  5126. }
  5127. return function (html) {
  5128. return (isWordDocument(html) ? filterPasteWord(html) : html);
  5129. };
  5130. }();
  5131. ///import editor.js
  5132. ///import core/utils.js
  5133. ///import core/dom/dom.js
  5134. ///import core/dom/dtd.js
  5135. ///import core/htmlparser.js
  5136. //模拟的节点类
  5137. //by zhanyi
  5138. (function () {
  5139. var uNode = UE.uNode = function (obj) {
  5140. this.type = obj.type;
  5141. this.data = obj.data;
  5142. this.tagName = obj.tagName;
  5143. this.parentNode = obj.parentNode;
  5144. this.attrs = obj.attrs || {};
  5145. this.children = obj.children;
  5146. };
  5147. var indentChar = ' ',
  5148. breakChar = '\n';
  5149. function insertLine(arr, current, begin) {
  5150. arr.push(breakChar);
  5151. return current + (begin ? 1 : -1);
  5152. }
  5153. function insertIndent(arr, current) {
  5154. //插入缩进
  5155. for (var i = 0; i < current; i++) {
  5156. arr.push(indentChar);
  5157. }
  5158. }
  5159. //创建uNode的静态方法
  5160. //支持标签和html
  5161. uNode.createElement = function (html) {
  5162. if (/[<>]/.test(html)) {
  5163. return UE.htmlparser(html).children[0]
  5164. } else {
  5165. return new uNode({
  5166. type: 'element',
  5167. children: [],
  5168. tagName: html
  5169. })
  5170. }
  5171. };
  5172. uNode.createText = function (data) {
  5173. return new UE.uNode({
  5174. type: 'text',
  5175. 'data': utils.unhtml(data || '')
  5176. })
  5177. };
  5178. function nodeToHtml(node, arr, formatter, current) {
  5179. switch (node.type) {
  5180. case 'root':
  5181. for (var i = 0, ci; ci = node.children[i++];) {
  5182. //插入新行
  5183. if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
  5184. insertLine(arr, current, true);
  5185. insertIndent(arr, current)
  5186. }
  5187. nodeToHtml(ci, arr, formatter, current)
  5188. }
  5189. break;
  5190. case 'text':
  5191. isText(node, arr);
  5192. break;
  5193. case 'element':
  5194. isElement(node, arr, formatter, current);
  5195. break;
  5196. case 'comment':
  5197. isComment(node, arr, formatter);
  5198. }
  5199. return arr;
  5200. }
  5201. function isText(node, arr) {
  5202. arr.push(node.parentNode.tagName == 'pre' ? node.data : node.data.replace(/[ ]{2}/g, ' &nbsp;'))
  5203. }
  5204. function isElement(node, arr, formatter, current) {
  5205. var attrhtml = '';
  5206. if (node.attrs) {
  5207. attrhtml = [];
  5208. var attrs = node.attrs;
  5209. for (var a in attrs) {
  5210. attrhtml.push(a + (attrs[a] !== undefined ? '="' + utils.unhtml(attrs[a]) + '"' : ''))
  5211. }
  5212. attrhtml = attrhtml.join(' ');
  5213. }
  5214. arr.push('<' + node.tagName +
  5215. (attrhtml ? ' ' + attrhtml : '') +
  5216. (dtd.$empty[node.tagName] ? '\/' : '' ) + '>'
  5217. );
  5218. //插入新行
  5219. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
  5220. if (node.children && node.children.length) {
  5221. current = insertLine(arr, current, true);
  5222. insertIndent(arr, current)
  5223. }
  5224. }
  5225. if (node.children && node.children.length) {
  5226. for (var i = 0, ci; ci = node.children[i++];) {
  5227. if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
  5228. insertLine(arr, current);
  5229. insertIndent(arr, current)
  5230. }
  5231. nodeToHtml(ci, arr, formatter, current)
  5232. }
  5233. }
  5234. if (!dtd.$empty[node.tagName]) {
  5235. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
  5236. if (node.children && node.children.length) {
  5237. current = insertLine(arr, current);
  5238. insertIndent(arr, current)
  5239. }
  5240. }
  5241. arr.push('<\/' + node.tagName + '>');
  5242. }
  5243. }
  5244. function isComment(node, arr) {
  5245. arr.push('<!--' + node.data + '-->');
  5246. }
  5247. function getNodeById(root, id) {
  5248. var node;
  5249. if (root.type == 'element' && root.getAttr('id') == id) {
  5250. return root;
  5251. }
  5252. if (root.children && root.children.length) {
  5253. for (var i = 0, ci; ci = root.children[i++];) {
  5254. if (node = getNodeById(ci, id)) {
  5255. return node;
  5256. }
  5257. }
  5258. }
  5259. }
  5260. function getNodesByTagName(node, tagName, arr) {
  5261. if (node.type == 'element' && node.tagName == tagName) {
  5262. arr.push(node);
  5263. }
  5264. if (node.children && node.children.length) {
  5265. for (var i = 0, ci; ci = node.children[i++];) {
  5266. getNodesByTagName(ci, tagName, arr)
  5267. }
  5268. }
  5269. }
  5270. function nodeTraversal(root, fn) {
  5271. if (root.children && root.children.length) {
  5272. for (var i = 0, ci; ci = root.children[i];) {
  5273. nodeTraversal(ci, fn);
  5274. //ci被替换的情况,这里就不再走 fn了
  5275. if (ci.parentNode) {
  5276. if (ci.children && ci.children.length) {
  5277. fn(ci)
  5278. }
  5279. if (ci.parentNode) i++
  5280. }
  5281. }
  5282. } else {
  5283. fn(root)
  5284. }
  5285. }
  5286. uNode.prototype = {
  5287. toHtml: function (formatter) {
  5288. var arr = [];
  5289. nodeToHtml(this, arr, formatter, 0);
  5290. return arr.join('')
  5291. },
  5292. innerHTML: function (htmlstr) {
  5293. if (this.type != 'element' || dtd.$empty[this.tagName]) {
  5294. return this;
  5295. }
  5296. if (utils.isString(htmlstr)) {
  5297. if (this.children) {
  5298. for (var i = 0, ci; ci = this.children[i++];) {
  5299. ci.parentNode = null;
  5300. }
  5301. }
  5302. this.children = [];
  5303. var tmpRoot = UE.htmlparser(htmlstr);
  5304. for (var i = 0, ci; ci = tmpRoot.children[i++];) {
  5305. this.children.push(ci);
  5306. ci.parentNode = this;
  5307. }
  5308. return this;
  5309. } else {
  5310. var tmpRoot = new UE.uNode({
  5311. type: 'root',
  5312. children: this.children
  5313. });
  5314. return tmpRoot.toHtml();
  5315. }
  5316. },
  5317. innerText: function (textStr) {
  5318. if (this.type != 'element' || dtd.$empty[this.tagName]) {
  5319. return this;
  5320. }
  5321. if (textStr) {
  5322. if (this.children) {
  5323. for (var i = 0, ci; ci = this.children[i++];) {
  5324. ci.parentNode = null;
  5325. }
  5326. }
  5327. this.children = [];
  5328. this.appendChild(uNode.createText(textStr));
  5329. return this;
  5330. } else {
  5331. return this.toHtml().replace(/<[^>]+>/g, '');
  5332. }
  5333. },
  5334. getData: function () {
  5335. if (this.type == 'element')
  5336. return '';
  5337. return this.data
  5338. },
  5339. firstChild: function () {
  5340. // if (this.type != 'element' || dtd.$empty[this.tagName]) {
  5341. // return this;
  5342. // }
  5343. return this.children ? this.children[0] : null;
  5344. },
  5345. lastChild: function () {
  5346. // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
  5347. // return this;
  5348. // }
  5349. return this.children ? this.children[this.children.length - 1] : null;
  5350. },
  5351. previousSibling: function () {
  5352. var parent = this.parentNode;
  5353. for (var i = 0, ci; ci = parent.children[i]; i++) {
  5354. if (ci === this) {
  5355. return i == 0 ? null : parent.children[i - 1];
  5356. }
  5357. }
  5358. },
  5359. nextSibling: function () {
  5360. var parent = this.parentNode;
  5361. for (var i = 0, ci; ci = parent.children[i++];) {
  5362. if (ci === this) {
  5363. return parent.children[i];
  5364. }
  5365. }
  5366. },
  5367. replaceChild: function (target, source) {
  5368. if (this.children) {
  5369. if (target.parentNode) {
  5370. target.parentNode.removeChild(target);
  5371. }
  5372. for (var i = 0, ci; ci = this.children[i]; i++) {
  5373. if (ci === source) {
  5374. this.children.splice(i, 1, target);
  5375. source.parentNode = null;
  5376. target.parentNode = this;
  5377. return target;
  5378. }
  5379. }
  5380. }
  5381. },
  5382. appendChild: function (node) {
  5383. if (this.type == 'root' || (this.type == 'element' && !dtd.$empty[this.tagName])) {
  5384. if (!this.children) {
  5385. this.children = []
  5386. }
  5387. if (node.parentNode) {
  5388. node.parentNode.removeChild(node);
  5389. }
  5390. for (var i = 0, ci; ci = this.children[i]; i++) {
  5391. if (ci === node) {
  5392. this.children.splice(i, 1);
  5393. break;
  5394. }
  5395. }
  5396. this.children.push(node);
  5397. node.parentNode = this;
  5398. return node;
  5399. }
  5400. },
  5401. insertBefore: function (target, source) {
  5402. if (this.children) {
  5403. if (target.parentNode) {
  5404. target.parentNode.removeChild(target);
  5405. }
  5406. for (var i = 0, ci; ci = this.children[i]; i++) {
  5407. if (ci === source) {
  5408. this.children.splice(i, 0, target);
  5409. target.parentNode = this;
  5410. return target;
  5411. }
  5412. }
  5413. }
  5414. },
  5415. insertAfter: function (target, source) {
  5416. if (this.children) {
  5417. if (target.parentNode) {
  5418. target.parentNode.removeChild(target);
  5419. }
  5420. for (var i = 0, ci; ci = this.children[i]; i++) {
  5421. if (ci === source) {
  5422. this.children.splice(i + 1, 0, target);
  5423. target.parentNode = this;
  5424. return target;
  5425. }
  5426. }
  5427. }
  5428. },
  5429. removeChild: function (node, keepChildren) {
  5430. if (this.children) {
  5431. for (var i = 0, ci; ci = this.children[i]; i++) {
  5432. if (ci === node) {
  5433. this.children.splice(i, 1);
  5434. ci.parentNode = null;
  5435. if (keepChildren && ci.children && ci.children.length) {
  5436. for (var j = 0, cj; cj = ci.children[j]; j++) {
  5437. this.children.splice(i + j, 0, cj);
  5438. cj.parentNode = this;
  5439. }
  5440. }
  5441. return ci;
  5442. }
  5443. }
  5444. }
  5445. },
  5446. getAttr: function (attrName) {
  5447. return this.attrs && this.attrs[attrName.toLowerCase()]
  5448. },
  5449. setAttr: function (attrName, attrVal) {
  5450. if (!attrName) {
  5451. delete this.attrs;
  5452. return;
  5453. }
  5454. if (!this.attrs) {
  5455. this.attrs = {};
  5456. }
  5457. if (utils.isObject(attrName)) {
  5458. for (var a in attrName) {
  5459. if (!attrName[a]) {
  5460. delete this.attrs[a]
  5461. } else {
  5462. this.attrs[a.toLowerCase()] = attrName[a];
  5463. }
  5464. }
  5465. } else {
  5466. if (!attrVal) {
  5467. delete this.attrs[attrName]
  5468. } else {
  5469. this.attrs[attrName.toLowerCase()] = attrVal;
  5470. }
  5471. }
  5472. },
  5473. getIndex: function () {
  5474. var parent = this.parentNode;
  5475. for (var i = 0, ci; ci = parent.children[i]; i++) {
  5476. if (ci === this) {
  5477. return i;
  5478. }
  5479. }
  5480. return -1;
  5481. },
  5482. getNodeById: function (id) {
  5483. var node;
  5484. if (this.children && this.children.length) {
  5485. for (var i = 0, ci; ci = this.children[i++];) {
  5486. if (node = getNodeById(ci, id)) {
  5487. return node;
  5488. }
  5489. }
  5490. }
  5491. },
  5492. getNodesByTagName: function (tagNames) {
  5493. tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, ' ').split(' ');
  5494. var arr = [], me = this;
  5495. utils.each(tagNames, function (tagName) {
  5496. if (me.children && me.children.length) {
  5497. for (var i = 0, ci; ci = me.children[i++];) {
  5498. getNodesByTagName(ci, tagName, arr)
  5499. }
  5500. }
  5501. });
  5502. return arr;
  5503. },
  5504. getStyle: function (name) {
  5505. var cssStyle = this.getAttr('style');
  5506. if (!cssStyle) {
  5507. return ''
  5508. }
  5509. var reg = new RegExp(name + ':([^;]+)', 'i');
  5510. var match = cssStyle.match(reg);
  5511. if (match && match[0]) {
  5512. return match[1]
  5513. }
  5514. return '';
  5515. },
  5516. setStyle: function (name, val) {
  5517. function exec(name, val) {
  5518. var reg = new RegExp(name + ':([^;]+;?)', 'gi');
  5519. cssStyle = cssStyle.replace(reg, '');
  5520. if (val) {
  5521. cssStyle = name + ':' + utils.unhtml(val) + ';' + cssStyle
  5522. }
  5523. }
  5524. var cssStyle = this.getAttr('style');
  5525. if (!cssStyle) {
  5526. cssStyle = '';
  5527. }
  5528. if (utils.isObject(name)) {
  5529. for (var a in name) {
  5530. exec(a, name[a])
  5531. }
  5532. } else {
  5533. exec(name, val)
  5534. }
  5535. this.setAttr('style', utils.trim(cssStyle))
  5536. },
  5537. traversal: function (fn) {
  5538. if (this.children && this.children.length) {
  5539. nodeTraversal(this, fn);
  5540. }
  5541. return this;
  5542. }
  5543. }
  5544. })();
  5545. //html字符串转换成uNode节点
  5546. //by zhanyi
  5547. var htmlparser = UE.htmlparser = function (htmlstr, ignoreBlank) {
  5548. var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  5549. re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
  5550. //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
  5551. var allowEmptyTags = {
  5552. b: 1, code: 1, i: 1, u: 1, strike: 1, s: 1, tt: 1, strong: 1, q: 1, samp: 1, em: 1, span: 1,
  5553. sub: 1, img: 1, sup: 1, font: 1, big: 1, small: 1, iframe: 1, a: 1, br: 1, pre: 1
  5554. };
  5555. htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, 'g'), '');
  5556. if (!ignoreBlank) {
  5557. htmlstr = htmlstr.replace(new RegExp('[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*<\/?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*', 'g'), function (a, b) {
  5558. //br暂时单独处理
  5559. if (b && allowEmptyTags[b.toLowerCase()]) {
  5560. return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, '');
  5561. }
  5562. return a.replace(new RegExp('^[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+'), '').replace(new RegExp('[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+$'), '');
  5563. });
  5564. }
  5565. var uNode = UE.uNode,
  5566. needParentNode = {
  5567. 'td': 'tr',
  5568. 'tr': ['tbody', 'thead', 'tfoot'],
  5569. 'tbody': 'table',
  5570. 'th': 'tr',
  5571. 'thead': 'table',
  5572. 'tfoot': 'table',
  5573. 'caption': 'table',
  5574. 'li': ['ul', 'ol'],
  5575. 'dt': 'dl',
  5576. 'dd': 'dl',
  5577. 'option': 'select'
  5578. },
  5579. needChild = {
  5580. 'ol': 'li',
  5581. 'ul': 'li'
  5582. };
  5583. function text(parent, data) {
  5584. if (needChild[parent.tagName]) {
  5585. var tmpNode = uNode.createElement(needChild[parent.tagName]);
  5586. parent.appendChild(tmpNode);
  5587. tmpNode.appendChild(uNode.createText(data));
  5588. parent = tmpNode;
  5589. } else {
  5590. parent.appendChild(uNode.createText(data));
  5591. }
  5592. }
  5593. function element(parent, tagName, htmlattr) {
  5594. var needParentTag;
  5595. if (needParentTag = needParentNode[tagName]) {
  5596. var tmpParent = parent, hasParent;
  5597. while (tmpParent.type != 'root') {
  5598. if (utils.isArray(needParentTag) ? utils.indexOf(needParentTag, tmpParent.tagName) != -1 : needParentTag == tmpParent.tagName) {
  5599. parent = tmpParent;
  5600. hasParent = true;
  5601. break;
  5602. }
  5603. tmpParent = tmpParent.parentNode;
  5604. }
  5605. if (!hasParent) {
  5606. parent = element(parent, utils.isArray(needParentTag) ? needParentTag[0] : needParentTag)
  5607. }
  5608. }
  5609. //按dtd处理嵌套
  5610. // if(parent.type != 'root' && !dtd[parent.tagName][tagName])
  5611. // parent = parent.parentNode;
  5612. var elm = new uNode({
  5613. parentNode: parent,
  5614. type: 'element',
  5615. tagName: tagName.toLowerCase(),
  5616. //是自闭合的处理一下
  5617. children: dtd.$empty[tagName] ? null : []
  5618. });
  5619. //如果属性存在,处理属性
  5620. if (htmlattr) {
  5621. var attrs = {}, match;
  5622. while (match = re_attr.exec(htmlattr)) {
  5623. attrs[match[1].toLowerCase()] = utils.unhtml(match[2] || match[3] || match[4])
  5624. }
  5625. elm.attrs = attrs;
  5626. }
  5627. parent.children.push(elm);
  5628. //如果是自闭合节点返回父亲节点
  5629. return dtd.$empty[tagName] ? parent : elm
  5630. }
  5631. function comment(parent, data) {
  5632. parent.children.push(new uNode({
  5633. type: 'comment',
  5634. data: data,
  5635. parentNode: parent
  5636. }));
  5637. }
  5638. var match, currentIndex = 0, nextIndex = 0;
  5639. //设置根节点
  5640. var root = new uNode({
  5641. type: 'root',
  5642. children: []
  5643. });
  5644. var currentParent = root;
  5645. while (match = re_tag.exec(htmlstr)) {
  5646. currentIndex = match.index;
  5647. try {
  5648. if (currentIndex > nextIndex) {
  5649. //text node
  5650. text(currentParent, htmlstr.slice(nextIndex, currentIndex));
  5651. }
  5652. if (match[3]) {
  5653. //start tag
  5654. currentParent = element(currentParent, match[3].toLowerCase(), match[4]);
  5655. } else if (match[1]) {
  5656. if (currentParent.type != 'root') {
  5657. var tmpParent = currentParent;
  5658. while (currentParent.type == 'element' && currentParent.tagName != match[1].toLowerCase()) {
  5659. currentParent = currentParent.parentNode;
  5660. if (currentParent.type == 'root') {
  5661. currentParent = tmpParent;
  5662. throw 'break'
  5663. }
  5664. }
  5665. //end tag
  5666. currentParent = currentParent.parentNode;
  5667. }
  5668. } else if (match[2]) {
  5669. //comment
  5670. comment(currentParent, match[2])
  5671. }
  5672. } catch (e) {
  5673. }
  5674. nextIndex = re_tag.lastIndex;
  5675. }
  5676. //如果结束是文本,就有可能丢掉,所以这里手动判断一下
  5677. //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
  5678. if (nextIndex < htmlstr.length) {
  5679. text(currentParent, htmlstr.slice(nextIndex));
  5680. }
  5681. return root;
  5682. };
  5683. /**
  5684. * @file
  5685. * @name UE.filterNode
  5686. * @short filterNode
  5687. * @desc 根据给定的规则过滤节点
  5688. * @import editor.js,core/utils.js
  5689. * @anthor zhanyi
  5690. */
  5691. var filterNode = UE.filterNode = function () {
  5692. function filterNode(node, rules) {
  5693. switch (node.type) {
  5694. case 'text':
  5695. break;
  5696. case 'element':
  5697. var val;
  5698. if (val = rules[node.tagName]) {
  5699. if (val === '-') {
  5700. node.parentNode.removeChild(node)
  5701. } else if (utils.isFunction(val)) {
  5702. var parentNode = node.parentNode,
  5703. index = node.getIndex();
  5704. val(node);
  5705. if (node.parentNode) {
  5706. if (node.children) {
  5707. for (var i = 0, ci; ci = node.children[i];) {
  5708. filterNode(ci, rules);
  5709. if (ci.parentNode) {
  5710. i++;
  5711. }
  5712. }
  5713. }
  5714. } else {
  5715. for (var i = index, ci; ci = parentNode.children[i];) {
  5716. filterNode(ci, rules);
  5717. if (ci.parentNode) {
  5718. i++;
  5719. }
  5720. }
  5721. }
  5722. } else {
  5723. var attrs = val['$'];
  5724. if (attrs && node.attrs) {
  5725. var tmpAttrs = {}, tmpVal;
  5726. for (var a in attrs) {
  5727. tmpVal = node.getAttr(a);
  5728. //todo 只先对style单独处理
  5729. if (a == 'style' && utils.isArray(attrs[a])) {
  5730. var tmpCssStyle = [];
  5731. utils.each(attrs[a], function (v) {
  5732. var tmp;
  5733. if (tmp = node.getStyle(v)) {
  5734. tmpCssStyle.push(v + ':' + tmp);
  5735. }
  5736. });
  5737. tmpVal = tmpCssStyle.join(';')
  5738. }
  5739. if (tmpVal) {
  5740. tmpAttrs[a] = tmpVal;
  5741. }
  5742. }
  5743. node.attrs = tmpAttrs;
  5744. }
  5745. if (node.children) {
  5746. for (var i = 0, ci; ci = node.children[i];) {
  5747. filterNode(ci, rules);
  5748. if (ci.parentNode) {
  5749. i++;
  5750. }
  5751. }
  5752. }
  5753. }
  5754. } else {
  5755. //如果不在名单里扣出子节点并删除该节点,cdata除外
  5756. if (dtd.$cdata[node.tagName]) {
  5757. node.parentNode.removeChild(node)
  5758. } else {
  5759. var parentNode = node.parentNode,
  5760. index = node.getIndex();
  5761. node.parentNode.removeChild(node, true);
  5762. for (var i = index, ci; ci = parentNode.children[i];) {
  5763. filterNode(ci, rules);
  5764. if (ci.parentNode) {
  5765. i++;
  5766. }
  5767. }
  5768. }
  5769. }
  5770. break;
  5771. case 'comment':
  5772. node.parentNode.removeChild(node)
  5773. }
  5774. }
  5775. return function (root, rules) {
  5776. if (utils.isEmptyObject(rules)) {
  5777. return root;
  5778. }
  5779. var val;
  5780. if (val = rules['-']) {
  5781. utils.each(val.split(' '), function (k) {
  5782. rules[k] = '-'
  5783. })
  5784. }
  5785. for (var i = 0, ci; ci = root.children[i];) {
  5786. filterNode(ci, rules);
  5787. if (ci.parentNode) {
  5788. i++;
  5789. }
  5790. }
  5791. return root;
  5792. }
  5793. }();
  5794. ///import core
  5795. ///plugin 编辑器默认的过滤转换机制
  5796. UE.plugins['defaultfilter'] = function () {
  5797. var me = this;
  5798. me.setOpt('allowDivTransToP', true);
  5799. //默认的过滤处理
  5800. //进入编辑器的内容处理
  5801. me.addInputRule(function (root) {
  5802. var allowDivTransToP = this.options.allowDivTransToP;
  5803. var val;
  5804. //进行默认的处理
  5805. root.traversal(function (node) {
  5806. if (node.type == 'element') {
  5807. if (!dtd.$cdata[node.tagName] && me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  5808. if (!node.firstChild()) node.parentNode.removeChild(node);
  5809. else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  5810. node.parentNode.removeChild(node, true)
  5811. }
  5812. return;
  5813. }
  5814. switch (node.tagName) {
  5815. case 'style':
  5816. case 'script':
  5817. node.setAttr({
  5818. cdata_tag: node.tagName,
  5819. cdata_data: encodeURIComponent(node.innerText() || '')
  5820. });
  5821. node.tagName = 'div';
  5822. node.removeChild(node.firstChild());
  5823. break;
  5824. case 'a':
  5825. if (val = node.getAttr('href')) {
  5826. node.setAttr('_href', val)
  5827. }
  5828. break;
  5829. case 'img':
  5830. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  5831. if (val = node.getAttr('src')) {
  5832. if (/^data:/.test(val)) {
  5833. node.parentNode.removeChild(node);
  5834. break;
  5835. }
  5836. }
  5837. node.setAttr('_src', node.getAttr('src'));
  5838. break;
  5839. case 'span':
  5840. if (browser.webkit && (val = node.getStyle('white-space'))) {
  5841. if (/nowrap|normal/.test(val)) {
  5842. node.setStyle('white-space', '');
  5843. if (me.options.autoClearEmptyNode && utils.isEmptyObject(node.attrs)) {
  5844. node.parentNode.removeChild(node, true)
  5845. }
  5846. }
  5847. }
  5848. break;
  5849. case 'p':
  5850. if (val = node.getAttr('align')) {
  5851. node.setAttr('align');
  5852. node.setStyle('text-align', val)
  5853. }
  5854. //trace:3431
  5855. // var cssStyle = node.getAttr('style');
  5856. // if (cssStyle) {
  5857. // cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
  5858. // node.setAttr('style', cssStyle)
  5859. //
  5860. // }
  5861. if (!node.firstChild()) {
  5862. node.innerHTML(browser.ie ? '&nbsp;' : '<br/>')
  5863. }
  5864. break;
  5865. case 'div':
  5866. if (node.getAttr('cdata_tag')) {
  5867. break;
  5868. }
  5869. //针对代码这里不处理插入代码的div
  5870. val = node.getAttr('class');
  5871. if (val && /^line number\d+/.test(val)) {
  5872. break;
  5873. }
  5874. if (!allowDivTransToP) {
  5875. break;
  5876. }
  5877. var tmpNode, p = UE.uNode.createElement('p');
  5878. while (tmpNode = node.firstChild()) {
  5879. if (tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) {
  5880. p.appendChild(tmpNode);
  5881. } else {
  5882. if (p.firstChild()) {
  5883. node.parentNode.insertBefore(p, node);
  5884. p = UE.uNode.createElement('p');
  5885. } else {
  5886. node.parentNode.insertBefore(tmpNode, node);
  5887. }
  5888. }
  5889. }
  5890. if (p.firstChild()) {
  5891. node.parentNode.insertBefore(p, node);
  5892. }
  5893. node.parentNode.removeChild(node);
  5894. break;
  5895. case 'dl':
  5896. node.tagName = 'ul';
  5897. break;
  5898. case 'dt':
  5899. case 'dd':
  5900. node.tagName = 'li';
  5901. break;
  5902. case 'li':
  5903. var className = node.getAttr('class');
  5904. if (!className || !/list\-/.test(className)) {
  5905. node.setAttr()
  5906. }
  5907. var tmpNodes = node.getNodesByTagName('ol ul');
  5908. UE.utils.each(tmpNodes, function (n) {
  5909. node.parentNode.insertAfter(n, node);
  5910. });
  5911. break;
  5912. case 'td':
  5913. case 'th':
  5914. case 'caption':
  5915. if (!node.children || !node.children.length) {
  5916. node.appendChild(browser.ie ? UE.uNode.createText(' ') : UE.uNode.createElement('br'))
  5917. }
  5918. }
  5919. }
  5920. if (node.type == 'comment') {
  5921. node.parentNode.removeChild(node);
  5922. }
  5923. })
  5924. });
  5925. //从编辑器出去的内容处理
  5926. me.addOutputRule(function (root) {
  5927. var val;
  5928. root.traversal(function (node) {
  5929. if (node.type == 'element') {
  5930. if (me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  5931. if (!node.firstChild()) node.parentNode.removeChild(node);
  5932. else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  5933. node.parentNode.removeChild(node, true)
  5934. }
  5935. return;
  5936. }
  5937. switch (node.tagName) {
  5938. case 'div':
  5939. if (val = node.getAttr('cdata_tag')) {
  5940. node.tagName = val;
  5941. node.appendChild(UE.uNode.createText(node.getAttr('cdata_data')));
  5942. node.setAttr({cdata_tag: '', cdata_data: ''});
  5943. }
  5944. break;
  5945. case 'a':
  5946. if (val = node.getAttr('_href')) {
  5947. node.setAttr({
  5948. 'href': val,
  5949. '_href': ''
  5950. })
  5951. }
  5952. break;
  5953. case 'img':
  5954. if (val = node.getAttr('_src')) {
  5955. node.setAttr({
  5956. 'src': node.getAttr('_src'),
  5957. '_src': ''
  5958. })
  5959. }
  5960. }
  5961. }
  5962. })
  5963. });
  5964. };
  5965. ///import core
  5966. /**
  5967. * @description 插入内容
  5968. * @name baidu.editor.execCommand
  5969. * @param {String} cmdName inserthtml插入内容的命令
  5970. * @param {String} html 要插入的内容
  5971. * @author zhanyi
  5972. */
  5973. UE.commands['inserthtml'] = {
  5974. execCommand: function (command, html, notNeedFilter) {
  5975. var me = this,
  5976. range,
  5977. div;
  5978. if (!html) {
  5979. return;
  5980. }
  5981. if (me.fireEvent('beforeinserthtml', html) === true) {
  5982. return;
  5983. }
  5984. range = me.selection.getRange();
  5985. div = range.document.createElement('div');
  5986. div.style.display = 'inline';
  5987. if (!notNeedFilter) {
  5988. var root = UE.htmlparser(html);
  5989. //如果给了过滤规则就先进行过滤
  5990. if (me.options.filterRules) {
  5991. UE.filterNode(root, me.options.filterRules);
  5992. }
  5993. //执行默认的处理
  5994. me.filterInputRule(root);
  5995. html = root.toHtml()
  5996. }
  5997. div.innerHTML = utils.trim(html);
  5998. if (!range.collapsed) {
  5999. var tmpNode = range.startContainer;
  6000. if (domUtils.isFillChar(tmpNode)) {
  6001. range.setStartBefore(tmpNode)
  6002. }
  6003. tmpNode = range.endContainer;
  6004. if (domUtils.isFillChar(tmpNode)) {
  6005. range.setEndAfter(tmpNode)
  6006. }
  6007. range.txtToElmBoundary();
  6008. //结束边界可能放到了br的前边,要把br包含进来
  6009. // x[xxx]<br/>
  6010. if (range.endContainer && range.endContainer.nodeType == 1) {
  6011. tmpNode = range.endContainer.childNodes[range.endOffset];
  6012. if (tmpNode && domUtils.isBr(tmpNode)) {
  6013. range.setEndAfter(tmpNode);
  6014. }
  6015. }
  6016. if (range.startOffset == 0) {
  6017. tmpNode = range.startContainer;
  6018. if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
  6019. tmpNode = range.endContainer;
  6020. if (range.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) {
  6021. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  6022. range.setStart(me.body.firstChild, 0).collapse(true)
  6023. }
  6024. }
  6025. }
  6026. !range.collapsed && range.deleteContents();
  6027. if (range.startContainer.nodeType == 1) {
  6028. var child = range.startContainer.childNodes[range.startOffset], pre;
  6029. if (child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)) {
  6030. range.setEnd(pre, pre.childNodes.length).collapse();
  6031. while (child.firstChild) {
  6032. pre.appendChild(child.firstChild);
  6033. }
  6034. domUtils.remove(child);
  6035. }
  6036. }
  6037. }
  6038. var child, parent, pre, tmp, hadBreak = 0, nextNode;
  6039. //如果当前位置选中了fillchar要干掉,要不会产生空行
  6040. if (range.inFillChar()) {
  6041. child = range.startContainer;
  6042. if (domUtils.isFillChar(child)) {
  6043. range.setStartBefore(child).collapse(true);
  6044. domUtils.remove(child);
  6045. } else if (domUtils.isFillChar(child, true)) {
  6046. child.nodeValue = child.nodeValue.replace(fillCharReg, '');
  6047. range.startOffset--;
  6048. range.collapsed && range.collapse(true)
  6049. }
  6050. }
  6051. //列表单独处理
  6052. var li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  6053. if (li) {
  6054. var next, last;
  6055. while (child = div.firstChild) {
  6056. //针对hr单独处理一下先
  6057. while (child && (child.nodeType == 3 || !domUtils.isBlockElm(child) || child.tagName == 'HR' )) {
  6058. next = child.nextSibling;
  6059. range.insertNode(child).collapse();
  6060. last = child;
  6061. child = next;
  6062. }
  6063. if (child) {
  6064. if (/^(ol|ul)$/i.test(child.tagName)) {
  6065. while (child.firstChild) {
  6066. last = child.firstChild;
  6067. domUtils.insertAfter(li, child.firstChild);
  6068. li = li.nextSibling;
  6069. }
  6070. domUtils.remove(child)
  6071. } else {
  6072. var tmpLi;
  6073. next = child.nextSibling;
  6074. tmpLi = me.document.createElement('li');
  6075. domUtils.insertAfter(li, tmpLi);
  6076. tmpLi.appendChild(child);
  6077. last = child;
  6078. child = next;
  6079. li = tmpLi;
  6080. }
  6081. }
  6082. }
  6083. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  6084. if (domUtils.isEmptyBlock(li)) {
  6085. domUtils.remove(li)
  6086. }
  6087. if (last) {
  6088. range.setStartAfter(last).collapse(true).select(true)
  6089. }
  6090. } else {
  6091. while (child = div.firstChild) {
  6092. if (hadBreak) {
  6093. var p = me.document.createElement('p');
  6094. while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
  6095. nextNode = child.nextSibling;
  6096. p.appendChild(child);
  6097. child = nextNode;
  6098. }
  6099. if (p.firstChild) {
  6100. child = p
  6101. }
  6102. }
  6103. range.insertNode(child);
  6104. nextNode = child.nextSibling;
  6105. if (!hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm(child)) {
  6106. parent = domUtils.findParent(child, function (node) {
  6107. return domUtils.isBlockElm(node);
  6108. });
  6109. if (parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)) {
  6110. if (!dtd[parent.tagName][child.nodeName]) {
  6111. pre = parent;
  6112. } else {
  6113. tmp = child.parentNode;
  6114. while (tmp !== parent) {
  6115. pre = tmp;
  6116. tmp = tmp.parentNode;
  6117. }
  6118. }
  6119. domUtils.breakParent(child, pre || tmp);
  6120. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  6121. var pre = child.previousSibling;
  6122. domUtils.trimWhiteTextNode(pre);
  6123. if (!pre.childNodes.length) {
  6124. domUtils.remove(pre);
  6125. }
  6126. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  6127. if (!browser.ie &&
  6128. (next = child.nextSibling) &&
  6129. domUtils.isBlockElm(next) &&
  6130. next.lastChild && !domUtils.isBr(next.lastChild)) {
  6131. next.appendChild(me.document.createElement('br'));
  6132. }
  6133. hadBreak = 1;
  6134. }
  6135. }
  6136. var next = child.nextSibling;
  6137. if (!div.firstChild && next && domUtils.isBlockElm(next)) {
  6138. range.setStart(next, 0).collapse(true);
  6139. break;
  6140. }
  6141. range.setEndAfter(child).collapse();
  6142. }
  6143. child = range.startContainer;
  6144. if (nextNode && domUtils.isBr(nextNode)) {
  6145. domUtils.remove(nextNode)
  6146. }
  6147. //用chrome可能有空白展位符
  6148. if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
  6149. if (nextNode = child.nextSibling) {
  6150. domUtils.remove(child);
  6151. if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
  6152. range.setStart(nextNode, 0).collapse(true).shrinkBoundary()
  6153. }
  6154. } else {
  6155. try {
  6156. child.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
  6157. } catch (e) {
  6158. range.setStartBefore(child);
  6159. domUtils.remove(child)
  6160. }
  6161. }
  6162. }
  6163. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  6164. try {
  6165. range.select(true);
  6166. } catch (e) {
  6167. }
  6168. }
  6169. setTimeout(function () {
  6170. range = me.selection.getRange();
  6171. range.scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0);
  6172. me.fireEvent('afterinserthtml');
  6173. }, 200);
  6174. }
  6175. };
  6176. ///import core
  6177. ///commands 自动排版
  6178. ///commandsName autotypeset
  6179. ///commandsTitle 自动排版
  6180. /**
  6181. * 自动排版
  6182. * @function
  6183. * @name baidu.editor.execCommands
  6184. */
  6185. UE.plugins['autotypeset'] = function () {
  6186. this.setOpt({'autotypeset': {
  6187. mergeEmptyline: true, //合并空行
  6188. removeClass: true, //去掉冗余的class
  6189. removeEmptyline: false, //去掉空行
  6190. textAlign: "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  6191. imageBlockLine: 'center', //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  6192. pasteFilter: false, //根据规则过滤没事粘贴进来的内容
  6193. clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
  6194. clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
  6195. removeEmptyNode: false, // 去掉空节点
  6196. //可以去掉的标签
  6197. removeTagNames: utils.extend({div: 1}, dtd.$removeEmpty),
  6198. indent: false, // 行首缩进
  6199. indentValue: '2em' //行首缩进的大小
  6200. }});
  6201. var me = this,
  6202. opt = me.options.autotypeset,
  6203. remainClass = {
  6204. 'selectTdClass': 1,
  6205. 'pagebreak': 1,
  6206. 'anchorclass': 1
  6207. },
  6208. remainTag = {
  6209. 'li': 1
  6210. },
  6211. tags = {
  6212. div: 1,
  6213. p: 1,
  6214. //trace:2183 这些也认为是行
  6215. blockquote: 1, center: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1,
  6216. span: 1
  6217. },
  6218. highlightCont;
  6219. //升级了版本,但配置项目里没有autotypeset
  6220. if (!opt) {
  6221. return;
  6222. }
  6223. function isLine(node, notEmpty) {
  6224. if (!node || node.nodeType == 3)
  6225. return 0;
  6226. if (domUtils.isBr(node))
  6227. return 1;
  6228. if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
  6229. if (highlightCont && highlightCont.contains(node)
  6230. ||
  6231. node.getAttribute('pagebreak')
  6232. ) {
  6233. return 0;
  6234. }
  6235. return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node, new RegExp('[\\s' + domUtils.fillChar
  6236. + ']', 'g'));
  6237. }
  6238. }
  6239. function removeNotAttributeSpan(node) {
  6240. if (!node.style.cssText) {
  6241. domUtils.removeAttributes(node, ['style']);
  6242. if (node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)) {
  6243. domUtils.remove(node, true);
  6244. }
  6245. }
  6246. }
  6247. function autotype(type, html) {
  6248. var me = this, cont;
  6249. if (html) {
  6250. if (!opt.pasteFilter) {
  6251. return;
  6252. }
  6253. cont = me.document.createElement('div');
  6254. cont.innerHTML = html.html;
  6255. } else {
  6256. cont = me.document.body;
  6257. }
  6258. var nodes = domUtils.getElementsByTagName(cont, '*');
  6259. // 行首缩进,段落方向,段间距,段内间距
  6260. for (var i = 0, ci; ci = nodes[i++];) {
  6261. if (me.fireEvent('excludeNodeinautotype', ci) === true) {
  6262. continue;
  6263. }
  6264. //font-size
  6265. if (opt.clearFontSize && ci.style.fontSize) {
  6266. domUtils.removeStyle(ci, 'font-size');
  6267. removeNotAttributeSpan(ci);
  6268. }
  6269. //font-family
  6270. if (opt.clearFontFamily && ci.style.fontFamily) {
  6271. domUtils.removeStyle(ci, 'font-family');
  6272. removeNotAttributeSpan(ci);
  6273. }
  6274. if (isLine(ci)) {
  6275. //合并空行
  6276. if (opt.mergeEmptyline) {
  6277. var next = ci.nextSibling, tmpNode, isBr = domUtils.isBr(ci);
  6278. while (isLine(next)) {
  6279. tmpNode = next;
  6280. next = tmpNode.nextSibling;
  6281. if (isBr && (!next || next && !domUtils.isBr(next))) {
  6282. break;
  6283. }
  6284. domUtils.remove(tmpNode);
  6285. }
  6286. }
  6287. //去掉空行,保留占位的空行
  6288. if (opt.removeEmptyline && domUtils.inDoc(ci, cont) && !remainTag[ci.parentNode.tagName.toLowerCase()]) {
  6289. if (domUtils.isBr(ci)) {
  6290. next = ci.nextSibling;
  6291. if (next && !domUtils.isBr(next)) {
  6292. continue;
  6293. }
  6294. }
  6295. domUtils.remove(ci);
  6296. continue;
  6297. }
  6298. }
  6299. if (isLine(ci, true) && ci.tagName != 'SPAN') {
  6300. if (opt.indent) {
  6301. ci.style.textIndent = opt.indentValue;
  6302. }
  6303. if (opt.textAlign) {
  6304. ci.style.textAlign = opt.textAlign;
  6305. }
  6306. // if(opt.lineHeight)
  6307. // ci.style.lineHeight = opt.lineHeight + 'cm';
  6308. }
  6309. //去掉class,保留的class不去掉
  6310. if (opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]) {
  6311. if (highlightCont && highlightCont.contains(ci)) {
  6312. continue;
  6313. }
  6314. domUtils.removeAttributes(ci, ['class']);
  6315. }
  6316. //表情不处理
  6317. if (opt.imageBlockLine && ci.tagName.toLowerCase() == 'img' && !ci.getAttribute('emotion')) {
  6318. if (html) {
  6319. var img = ci;
  6320. switch (opt.imageBlockLine) {
  6321. case 'left':
  6322. case 'right':
  6323. case 'none':
  6324. var pN = img.parentNode, tmpNode, pre, next;
  6325. while (dtd.$inline[pN.tagName] || pN.tagName == 'A') {
  6326. pN = pN.parentNode;
  6327. }
  6328. tmpNode = pN;
  6329. if (tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') {
  6330. if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function (node) {
  6331. return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  6332. }) == 1) {
  6333. pre = tmpNode.previousSibling;
  6334. next = tmpNode.nextSibling;
  6335. if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) {
  6336. pre.appendChild(tmpNode.firstChild);
  6337. while (next.firstChild) {
  6338. pre.appendChild(next.firstChild);
  6339. }
  6340. domUtils.remove(tmpNode);
  6341. domUtils.remove(next);
  6342. } else {
  6343. domUtils.setStyle(tmpNode, 'text-align', '');
  6344. }
  6345. }
  6346. }
  6347. domUtils.setStyle(img, 'float', opt.imageBlockLine);
  6348. break;
  6349. case 'center':
  6350. if (me.queryCommandValue('imagefloat') != 'center') {
  6351. pN = img.parentNode;
  6352. domUtils.setStyle(img, 'float', 'none');
  6353. tmpNode = img;
  6354. while (pN && domUtils.getChildCount(pN, function (node) {
  6355. return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  6356. }) == 1
  6357. && (dtd.$inline[pN.tagName] || pN.tagName == 'A')) {
  6358. tmpNode = pN;
  6359. pN = pN.parentNode;
  6360. }
  6361. var pNode = me.document.createElement('p');
  6362. domUtils.setAttributes(pNode, {
  6363. style: 'text-align:center'
  6364. });
  6365. tmpNode.parentNode.insertBefore(pNode, tmpNode);
  6366. pNode.appendChild(tmpNode);
  6367. domUtils.setStyle(tmpNode, 'float', '');
  6368. }
  6369. }
  6370. } else {
  6371. var range = me.selection.getRange();
  6372. range.selectNode(ci).select();
  6373. me.execCommand('imagefloat', opt.imageBlockLine);
  6374. }
  6375. }
  6376. //去掉冗余的标签
  6377. if (opt.removeEmptyNode) {
  6378. if (opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils.isEmptyBlock(ci)) {
  6379. domUtils.remove(ci);
  6380. }
  6381. }
  6382. }
  6383. if (html) {
  6384. html.html = cont.innerHTML;
  6385. }
  6386. }
  6387. if (opt.pasteFilter) {
  6388. me.addListener('beforepaste', autotype);
  6389. }
  6390. me.commands['autotypeset'] = {
  6391. execCommand: function () {
  6392. me.removeListener('beforepaste', autotype);
  6393. if (opt.pasteFilter) {
  6394. me.addListener('beforepaste', autotype);
  6395. }
  6396. autotype.call(me)
  6397. }
  6398. };
  6399. };
  6400. ///import core
  6401. ///commands 自动提交
  6402. ///commandsName autosubmit
  6403. ///commandsTitle 自动提交
  6404. UE.plugins['autosubmit'] = function () {
  6405. var me = this;
  6406. me.commands['autosubmit'] = {
  6407. execCommand: function () {
  6408. var me = this,
  6409. form = domUtils.findParentByTagName(me.iframe, "form", false);
  6410. if (form) {
  6411. if (me.fireEvent("beforesubmit") === false) {
  6412. return;
  6413. }
  6414. me.sync();
  6415. form.submit();
  6416. }
  6417. }
  6418. };
  6419. //快捷键
  6420. me.addshortcutkey({
  6421. "autosubmit": "ctrl+13" //手动提交
  6422. });
  6423. };
  6424. ///import core
  6425. ///commands 插入背景
  6426. ///commandsName background
  6427. ///commandsTitle 插入背景
  6428. ///commandsDialog dialogs\background
  6429. UE.plugins['background'] = function () {
  6430. var me = this;
  6431. me.addListener("getAllHtml", function (type, headHtml) {
  6432. var body = this.body,
  6433. su = domUtils.getComputedStyle(body, "background-image"),
  6434. url = "";
  6435. if (su.indexOf(me.options.imagePath) > 0) {
  6436. url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(/"|\(|\)/ig, "");
  6437. } else {
  6438. url = su != "none" ? su.replace(/url\("?|"?\)/ig, "") : "";
  6439. }
  6440. var html = '<style type="text/css">body{';
  6441. var bgObj = {
  6442. "background-color": domUtils.getComputedStyle(body, "background-color") || "#ffffff",
  6443. 'background-image': url ? 'url(' + url + ')' : '',
  6444. 'background-repeat': domUtils.getComputedStyle(body, "background-repeat") || "",
  6445. 'background-position': browser.ie ? (domUtils.getComputedStyle(body, "background-position-x") + " " + domUtils.getComputedStyle(body, "background-position-y")) : domUtils.getComputedStyle(body, "background-position"),
  6446. 'height': domUtils.getComputedStyle(body, "height")
  6447. };
  6448. for (var name in bgObj) {
  6449. if (bgObj.hasOwnProperty(name)) {
  6450. html += name + ":" + bgObj[name] + ";";
  6451. }
  6452. }
  6453. html += '}</style> ';
  6454. headHtml.push(html);
  6455. });
  6456. }
  6457. ///import core
  6458. ///import plugins\inserthtml.js
  6459. ///commands 插入图片,操作图片的对齐方式
  6460. ///commandsName InsertImage,ImageNone,ImageLeft,ImageRight,ImageCenter
  6461. ///commandsTitle 图片,默认,居左,居右,居中
  6462. ///commandsDialog dialogs\image
  6463. /**
  6464. * Created by .
  6465. * User: zhanyi
  6466. * for image
  6467. */
  6468. UE.commands['imagefloat'] = {
  6469. execCommand: function (cmd, align) {
  6470. var me = this,
  6471. range = me.selection.getRange();
  6472. if (!range.collapsed) {
  6473. var img = range.getClosedNode();
  6474. if (img && img.tagName == 'IMG') {
  6475. switch (align) {
  6476. case 'left':
  6477. case 'right':
  6478. case 'none':
  6479. var pN = img.parentNode, tmpNode, pre, next;
  6480. while (dtd.$inline[pN.tagName] || pN.tagName == 'A') {
  6481. pN = pN.parentNode;
  6482. }
  6483. tmpNode = pN;
  6484. if (tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') {
  6485. if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function (node) {
  6486. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  6487. }) == 1) {
  6488. pre = tmpNode.previousSibling;
  6489. next = tmpNode.nextSibling;
  6490. if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) {
  6491. pre.appendChild(tmpNode.firstChild);
  6492. while (next.firstChild) {
  6493. pre.appendChild(next.firstChild);
  6494. }
  6495. domUtils.remove(tmpNode);
  6496. domUtils.remove(next);
  6497. } else {
  6498. domUtils.setStyle(tmpNode, 'text-align', '');
  6499. }
  6500. }
  6501. range.selectNode(img).select();
  6502. }
  6503. domUtils.setStyle(img, 'float', align == 'none' ? '' : align);
  6504. if (align == 'none') {
  6505. domUtils.removeAttributes(img, 'align');
  6506. }
  6507. break;
  6508. case 'center':
  6509. if (me.queryCommandValue('imagefloat') != 'center') {
  6510. pN = img.parentNode;
  6511. domUtils.setStyle(img, 'float', '');
  6512. domUtils.removeAttributes(img, 'align');
  6513. tmpNode = img;
  6514. while (pN && domUtils.getChildCount(pN, function (node) {
  6515. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  6516. }) == 1
  6517. && (dtd.$inline[pN.tagName] || pN.tagName == 'A')) {
  6518. tmpNode = pN;
  6519. pN = pN.parentNode;
  6520. }
  6521. range.setStartBefore(tmpNode).setCursor(false);
  6522. pN = me.document.createElement('div');
  6523. pN.appendChild(tmpNode);
  6524. domUtils.setStyle(tmpNode, 'float', '');
  6525. me.execCommand('insertHtml', '<p id="_img_parent_tmp" style="text-align:center">' + pN.innerHTML + '</p>');
  6526. tmpNode = me.document.getElementById('_img_parent_tmp');
  6527. tmpNode.removeAttribute('id');
  6528. tmpNode = tmpNode.firstChild;
  6529. range.selectNode(tmpNode).select();
  6530. //去掉后边多余的元素
  6531. next = tmpNode.parentNode.nextSibling;
  6532. if (next && domUtils.isEmptyNode(next)) {
  6533. domUtils.remove(next);
  6534. }
  6535. }
  6536. break;
  6537. }
  6538. }
  6539. }
  6540. },
  6541. queryCommandValue: function () {
  6542. var range = this.selection.getRange(),
  6543. startNode, floatStyle;
  6544. if (range.collapsed) {
  6545. return 'none';
  6546. }
  6547. startNode = range.getClosedNode();
  6548. if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
  6549. floatStyle = startNode.getAttribute('align') || domUtils.getComputedStyle(startNode, 'float');
  6550. if (floatStyle == 'none') {
  6551. floatStyle = domUtils.getComputedStyle(startNode.parentNode, 'text-align') == 'center' ? 'center' : floatStyle;
  6552. }
  6553. return {
  6554. left: 1,
  6555. right: 1,
  6556. center: 1
  6557. }[floatStyle] ? floatStyle : 'none';
  6558. }
  6559. return 'none';
  6560. },
  6561. queryCommandState: function () {
  6562. var range = this.selection.getRange(),
  6563. startNode;
  6564. if (range.collapsed) return -1;
  6565. startNode = range.getClosedNode();
  6566. if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
  6567. return 0;
  6568. }
  6569. return -1;
  6570. }
  6571. };
  6572. UE.commands['insertimage'] = {
  6573. execCommand: function (cmd, opt) {
  6574. opt = utils.isArray(opt) ? opt : [opt];
  6575. if (!opt.length) {
  6576. return;
  6577. }
  6578. var me = this,
  6579. range = me.selection.getRange(),
  6580. img = range.getClosedNode();
  6581. if (img && /img/i.test(img.tagName) && img.className != "edui-faked-video" && !img.getAttribute("word_img")) {
  6582. var first = opt.shift();
  6583. var floatStyle = first['floatStyle'];
  6584. delete first['floatStyle'];
  6585. //// img.style.border = (first.border||0) +"px solid #000";
  6586. //// img.style.margin = (first.margin||0) +"px";
  6587. // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
  6588. domUtils.setAttributes(img, first);
  6589. me.execCommand('imagefloat', floatStyle);
  6590. if (opt.length > 0) {
  6591. range.setStartAfter(img).setCursor(false, true);
  6592. me.execCommand('insertimage', opt);
  6593. }
  6594. } else {
  6595. var html = [], str = '', ci;
  6596. ci = opt[0];
  6597. if (opt.length == 1) {
  6598. str = '<img src="' + ci.src + '" ' + (ci._src ? ' _src="' + ci._src + '" ' : '') +
  6599. (ci.width ? 'width="' + ci.width + '" ' : '') +
  6600. (ci.height ? ' height="' + ci.height + '" ' : '') +
  6601. (ci['floatStyle'] == 'left' || ci['floatStyle'] == 'right' ? ' style="float:' + ci['floatStyle'] + ';"' : '') +
  6602. (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : '') +
  6603. (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : '') +
  6604. (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : '') +
  6605. (ci.hspace && ci.hspace != "0" ? ' hspace = "' + ci.hspace + '"' : '') +
  6606. (ci.vspace && ci.vspace != "0" ? ' vspace = "' + ci.vspace + '"' : '') + '/>';
  6607. if (ci['floatStyle'] == 'center') {
  6608. str = '<p style="text-align: center">' + str + '</p>';
  6609. }
  6610. html.push(str);
  6611. } else {
  6612. for (var i = 0; ci = opt[i++];) {
  6613. str = '<p ' + (ci['floatStyle'] == 'center' ? 'style="text-align: center" ' : '') + '><img src="' + ci.src + '" ' +
  6614. (ci.width ? 'width="' + ci.width + '" ' : '') + (ci._src ? ' _src="' + ci._src + '" ' : '') +
  6615. (ci.height ? ' height="' + ci.height + '" ' : '') +
  6616. ' style="' + (ci['floatStyle'] && ci['floatStyle'] != 'center' ? 'float:' + ci['floatStyle'] + ';' : '') +
  6617. (ci.border || '') + '" ' +
  6618. (ci.title ? ' title="' + ci.title + '"' : '') + ' /></p>';
  6619. html.push(str);
  6620. }
  6621. }
  6622. me.execCommand('insertHtml', html.join(''));
  6623. }
  6624. }
  6625. };
  6626. ///import core
  6627. ///commands 段落格式,居左,居右,居中,两端对齐
  6628. ///commandsName JustifyLeft,JustifyCenter,JustifyRight,JustifyJustify
  6629. ///commandsTitle 居左对齐,居中对齐,居右对齐,两端对齐
  6630. /**
  6631. * @description 居左右中
  6632. * @name baidu.editor.execCommand
  6633. * @param {String} cmdName justify执行对齐方式的命令
  6634. * @param {String} align 对齐方式:left居左,right居右,center居中,justify两端对齐
  6635. * @author zhanyi
  6636. */
  6637. UE.plugins['justify'] = function () {
  6638. var me = this,
  6639. block = domUtils.isBlockElm,
  6640. defaultValue = {
  6641. left: 1,
  6642. right: 1,
  6643. center: 1,
  6644. justify: 1
  6645. },
  6646. doJustify = function (range, style) {
  6647. var bookmark = range.createBookmark(),
  6648. filterFn = function (node) {
  6649. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
  6650. };
  6651. range.enlarge(true);
  6652. var bookmark2 = range.createBookmark(),
  6653. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  6654. tmpRange = range.cloneRange(),
  6655. tmpNode;
  6656. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  6657. if (current.nodeType == 3 || !block(current)) {
  6658. tmpRange.setStartBefore(current);
  6659. while (current && current !== bookmark2.end && !block(current)) {
  6660. tmpNode = current;
  6661. current = domUtils.getNextDomNode(current, false, null, function (node) {
  6662. return !block(node);
  6663. });
  6664. }
  6665. tmpRange.setEndAfter(tmpNode);
  6666. var common = tmpRange.getCommonAncestor();
  6667. if (!domUtils.isBody(common) && block(common)) {
  6668. domUtils.setStyles(common, utils.isString(style) ? {'text-align': style} : style);
  6669. current = common;
  6670. } else {
  6671. var p = range.document.createElement('p');
  6672. domUtils.setStyles(p, utils.isString(style) ? {'text-align': style} : style);
  6673. var frag = tmpRange.extractContents();
  6674. p.appendChild(frag);
  6675. tmpRange.insertNode(p);
  6676. current = p;
  6677. }
  6678. current = domUtils.getNextDomNode(current, false, filterFn);
  6679. } else {
  6680. current = domUtils.getNextDomNode(current, true, filterFn);
  6681. }
  6682. }
  6683. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  6684. };
  6685. UE.commands['justify'] = {
  6686. execCommand: function (cmdName, align) {
  6687. var range = this.selection.getRange(),
  6688. txt;
  6689. //闭合时单独处理
  6690. if (range.collapsed) {
  6691. txt = this.document.createTextNode('p');
  6692. range.insertNode(txt);
  6693. }
  6694. doJustify(range, align);
  6695. if (txt) {
  6696. range.setStartBefore(txt).collapse(true);
  6697. domUtils.remove(txt);
  6698. }
  6699. range.select();
  6700. return true;
  6701. },
  6702. queryCommandValue: function () {
  6703. var startNode = this.selection.getStart(),
  6704. value = domUtils.getComputedStyle(startNode, 'text-align');
  6705. return defaultValue[value] ? value : 'left';
  6706. },
  6707. queryCommandState: function () {
  6708. var start = this.selection.getStart(),
  6709. cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  6710. return cell ? -1 : 0;
  6711. }
  6712. };
  6713. };
  6714. ///import core
  6715. ///import plugins\removeformat.js
  6716. ///commands 字体颜色,背景色,字号,字体,下划线,删除线
  6717. ///commandsName ForeColor,BackColor,FontSize,FontFamily,Underline,StrikeThrough
  6718. ///commandsTitle 字体颜色,背景色,字号,字体,下划线,删除线
  6719. /**
  6720. * @description 字体
  6721. * @name baidu.editor.execCommand
  6722. * @param {String} cmdName 执行的功能名称
  6723. * @param {String} value 传入的值
  6724. */
  6725. UE.plugins['font'] = function () {
  6726. var me = this,
  6727. fonts = {
  6728. 'forecolor': 'color',
  6729. 'backcolor': 'background-color',
  6730. 'fontsize': 'font-size',
  6731. 'fontfamily': 'font-family',
  6732. 'underline': 'text-decoration',
  6733. 'strikethrough': 'text-decoration',
  6734. 'fontborder': 'border'
  6735. },
  6736. needCmd = {'underline': 1, 'strikethrough': 1, 'fontborder': 1},
  6737. needSetChild = {
  6738. 'forecolor': 'color',
  6739. 'backcolor': 'background-color',
  6740. 'fontsize': 'font-size',
  6741. 'fontfamily': 'font-family'
  6742. };
  6743. me.setOpt({
  6744. 'fontfamily': [
  6745. { name: 'songti', val: '宋体,SimSun'},
  6746. { name: 'yahei', val: '微软雅黑,Microsoft YaHei'},
  6747. { name: 'kaiti', val: '楷体,楷体_GB2312, SimKai'},
  6748. { name: 'heiti', val: '黑体, SimHei'},
  6749. { name: 'lishu', val: '隶书, SimLi'},
  6750. { name: 'andaleMono', val: 'andale mono'},
  6751. { name: 'arial', val: 'arial, helvetica,sans-serif'},
  6752. { name: 'arialBlack', val: 'arial black,avant garde'},
  6753. { name: 'comicSansMs', val: 'comic sans ms'},
  6754. { name: 'impact', val: 'impact,chicago'},
  6755. { name: 'timesNewRoman', val: 'times new roman'}
  6756. ],
  6757. 'fontsize': [10, 11, 12, 14, 16, 18, 20, 24, 36]
  6758. });
  6759. function mergeWithParent(node) {
  6760. var parent;
  6761. while (parent = node.parentNode) {
  6762. if (parent.tagName == 'SPAN' && domUtils.getChildCount(parent, function (child) {
  6763. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child)
  6764. }) == 1) {
  6765. parent.style.cssText += node.style.cssText;
  6766. domUtils.remove(node, true);
  6767. node = parent;
  6768. } else {
  6769. break;
  6770. }
  6771. }
  6772. }
  6773. function mergeChild(rng, cmdName, value) {
  6774. if (needSetChild[cmdName]) {
  6775. rng.adjustmentBoundary();
  6776. if (!rng.collapsed && rng.startContainer.nodeType == 1) {
  6777. var start = rng.startContainer.childNodes[rng.startOffset];
  6778. if (start && domUtils.isTagNode(start, 'span')) {
  6779. var bk = rng.createBookmark();
  6780. utils.each(domUtils.getElementsByTagName(start, 'span'), function (span) {
  6781. if (!span.parentNode || domUtils.isBookmarkNode(span))return;
  6782. if (cmdName == 'backcolor' && domUtils.getComputedStyle(span, 'background-color').toLowerCase() === value) {
  6783. return;
  6784. }
  6785. domUtils.removeStyle(span, needSetChild[cmdName]);
  6786. if (span.style.cssText.replace(/^\s+$/, '').length == 0) {
  6787. domUtils.remove(span, true)
  6788. }
  6789. });
  6790. rng.moveToBookmark(bk)
  6791. }
  6792. }
  6793. }
  6794. }
  6795. function mergesibling(rng, cmdName, value) {
  6796. var collapsed = rng.collapsed,
  6797. bk = rng.createBookmark(), common;
  6798. if (collapsed) {
  6799. common = bk.start.parentNode;
  6800. while (dtd.$inline[common.tagName]) {
  6801. common = common.parentNode;
  6802. }
  6803. } else {
  6804. common = domUtils.getCommonAncestor(bk.start, bk.end);
  6805. }
  6806. utils.each(domUtils.getElementsByTagName(common, 'span'), function (span) {
  6807. if (!span.parentNode || domUtils.isBookmarkNode(span))return;
  6808. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  6809. if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
  6810. domUtils.remove(span, true);
  6811. } else {
  6812. domUtils.removeStyle(span, 'border');
  6813. }
  6814. return
  6815. }
  6816. if (/border/i.test(span.style.cssText) && span.parentNode.tagName == 'SPAN' && /border/i.test(span.parentNode.style.cssText)) {
  6817. span.style.cssText = span.style.cssText.replace(/border[^:]*:[^;]+;?/gi, '');
  6818. }
  6819. if (!(cmdName == 'fontborder' && value == 'none')) {
  6820. var next = span.nextSibling;
  6821. while (next && next.nodeType == 1 && next.tagName == 'SPAN') {
  6822. if (domUtils.isBookmarkNode(next) && cmdName == 'fontborder') {
  6823. span.appendChild(next);
  6824. next = span.nextSibling;
  6825. continue;
  6826. }
  6827. if (next.style.cssText == span.style.cssText) {
  6828. domUtils.moveChild(next, span);
  6829. domUtils.remove(next);
  6830. }
  6831. if (span.nextSibling === next)
  6832. break;
  6833. next = span.nextSibling;
  6834. }
  6835. }
  6836. mergeWithParent(span);
  6837. if (browser.ie && browser.version > 8) {
  6838. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  6839. var parent = domUtils.findParent(span, function (n) {
  6840. return n.tagName == 'SPAN' && /background-color/.test(n.style.cssText)
  6841. });
  6842. if (parent && !/background-color/.test(span.style.cssText)) {
  6843. span.style.backgroundColor = parent.style.backgroundColor;
  6844. }
  6845. }
  6846. });
  6847. rng.moveToBookmark(bk);
  6848. mergeChild(rng, cmdName, value)
  6849. }
  6850. me.addInputRule(function (root) {
  6851. utils.each(root.getNodesByTagName('u s del font strike'), function (node) {
  6852. if (node.tagName == 'font') {
  6853. var cssStyle = [];
  6854. for (var p in node.attrs) {
  6855. switch (p) {
  6856. case 'size':
  6857. cssStyle.push('font-size:' + node.attrs[p] + 'px');
  6858. break;
  6859. case 'color':
  6860. cssStyle.push('color:' + node.attrs[p]);
  6861. break;
  6862. case 'face':
  6863. cssStyle.push('font-family:' + node.attrs[p]);
  6864. break;
  6865. case 'style':
  6866. cssStyle.push(node.attrs[p]);
  6867. }
  6868. }
  6869. node.attrs = {
  6870. 'style': cssStyle.join(';')
  6871. };
  6872. } else {
  6873. var val = node.tagName == 'u' ? 'underline' : 'line-through';
  6874. node.attrs = {
  6875. 'style': (node.getAttr('style') || '') + 'text-decoration:' + val + ';'
  6876. }
  6877. }
  6878. node.tagName = 'span';
  6879. });
  6880. // utils.each(root.getNodesByTagName('span'), function (node) {
  6881. // var val;
  6882. // if(val = node.getAttr('class')){
  6883. // if(/fontstrikethrough/.test(val)){
  6884. // node.setStyle('text-decoration','line-through');
  6885. // if(node.attrs['class']){
  6886. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  6887. // }else{
  6888. // node.setAttr('class')
  6889. // }
  6890. // }
  6891. // if(/fontborder/.test(val)){
  6892. // node.setStyle('border','1px solid #000');
  6893. // if(node.attrs['class']){
  6894. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  6895. // }else{
  6896. // node.setAttr('class')
  6897. // }
  6898. // }
  6899. // }
  6900. // });
  6901. });
  6902. // me.addOutputRule(function(root){
  6903. // utils.each(root.getNodesByTagName('span'), function (node) {
  6904. // var val;
  6905. // if(val = node.getStyle('text-decoration')){
  6906. // if(/line-through/.test(val)){
  6907. // if(node.attrs['class']){
  6908. // node.attrs['class'] += ' fontstrikethrough';
  6909. // }else{
  6910. // node.setAttr('class','fontstrikethrough')
  6911. // }
  6912. // }
  6913. //
  6914. // node.setStyle('text-decoration')
  6915. // }
  6916. // if(val = node.getStyle('border')){
  6917. // if(/1px/.test(val) && /solid/.test(val)){
  6918. // if(node.attrs['class']){
  6919. // node.attrs['class'] += ' fontborder';
  6920. //
  6921. // }else{
  6922. // node.setAttr('class','fontborder')
  6923. // }
  6924. // }
  6925. // node.setStyle('border')
  6926. //
  6927. // }
  6928. // });
  6929. // });
  6930. for (var p in fonts) {
  6931. (function (cmd, style) {
  6932. UE.commands[cmd] = {
  6933. execCommand: function (cmdName, value) {
  6934. value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' :
  6935. cmdName == 'fontborder' ? '1px solid #000' :
  6936. 'line-through');
  6937. var me = this,
  6938. range = this.selection.getRange(),
  6939. text;
  6940. if (value == 'default') {
  6941. if (range.collapsed) {
  6942. text = me.document.createTextNode('font');
  6943. range.insertNode(text).select();
  6944. }
  6945. me.execCommand('removeFormat', 'span,a', style);
  6946. if (text) {
  6947. range.setStartBefore(text).collapse(true);
  6948. domUtils.remove(text);
  6949. }
  6950. mergesibling(range, cmdName, value);
  6951. range.select()
  6952. } else {
  6953. if (!range.collapsed) {
  6954. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  6955. me.execCommand('removeFormat', 'span,a', style);
  6956. }
  6957. range = me.selection.getRange();
  6958. range.applyInlineStyle('span', {'style': style + ':' + value});
  6959. mergesibling(range, cmdName, value);
  6960. range.select();
  6961. } else {
  6962. var span = domUtils.findParentByTagName(range.startContainer, 'span', true);
  6963. text = me.document.createTextNode('font');
  6964. if (span && !span.children.length && !span[browser.ie ? 'innerText' : 'textContent'].replace(fillCharReg, '').length) {
  6965. //for ie hack when enter
  6966. range.insertNode(text);
  6967. if (needCmd[cmd]) {
  6968. range.selectNode(text).select();
  6969. me.execCommand('removeFormat', 'span,a', style, null);
  6970. span = domUtils.findParentByTagName(text, 'span', true);
  6971. range.setStartBefore(text);
  6972. }
  6973. span && (span.style.cssText += ';' + style + ':' + value);
  6974. range.collapse(true).select();
  6975. } else {
  6976. range.insertNode(text);
  6977. range.selectNode(text).select();
  6978. span = range.document.createElement('span');
  6979. if (needCmd[cmd]) {
  6980. //a标签内的不处理跳过
  6981. if (domUtils.findParentByTagName(text, 'a', true)) {
  6982. range.setStartBefore(text).setCursor();
  6983. domUtils.remove(text);
  6984. return;
  6985. }
  6986. me.execCommand('removeFormat', 'span,a', style);
  6987. }
  6988. span.style.cssText = style + ':' + value;
  6989. text.parentNode.insertBefore(span, text);
  6990. //修复,span套span 但样式不继承的问题
  6991. if (!browser.ie || browser.ie && browser.version == 9) {
  6992. var spanParent = span.parentNode;
  6993. while (!domUtils.isBlockElm(spanParent)) {
  6994. if (spanParent.tagName == 'SPAN') {
  6995. //opera合并style不会加入";"
  6996. span.style.cssText = spanParent.style.cssText + ";" + span.style.cssText;
  6997. }
  6998. spanParent = spanParent.parentNode;
  6999. }
  7000. }
  7001. if (opera) {
  7002. setTimeout(function () {
  7003. range.setStart(span, 0).collapse(true);
  7004. mergesibling(range, cmdName, value);
  7005. range.select();
  7006. });
  7007. } else {
  7008. range.setStart(span, 0).collapse(true);
  7009. mergesibling(range, cmdName, value);
  7010. range.select();
  7011. }
  7012. //trace:981
  7013. //domUtils.mergeToParent(span)
  7014. }
  7015. domUtils.remove(text);
  7016. }
  7017. }
  7018. return true;
  7019. },
  7020. queryCommandValue: function (cmdName) {
  7021. var startNode = this.selection.getStart();
  7022. //trace:946
  7023. if (cmdName == 'underline' || cmdName == 'strikethrough') {
  7024. var tmpNode = startNode, value;
  7025. while (tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)) {
  7026. if (tmpNode.nodeType == 1) {
  7027. value = domUtils.getComputedStyle(tmpNode, style);
  7028. if (value != 'none') {
  7029. return value;
  7030. }
  7031. }
  7032. tmpNode = tmpNode.parentNode;
  7033. }
  7034. return 'none';
  7035. }
  7036. if (cmdName == 'fontborder') {
  7037. var tmp = startNode, val;
  7038. while (tmp && dtd.$inline[tmp.tagName]) {
  7039. if (val = domUtils.getComputedStyle(tmp, 'border')) {
  7040. if (/1px/.test(val) && /solid/.test(val)) {
  7041. return val;
  7042. }
  7043. }
  7044. tmp = tmp.parentNode;
  7045. }
  7046. return ''
  7047. }
  7048. if (cmdName == 'FontSize') {
  7049. var styleVal = domUtils.getComputedStyle(startNode, style),
  7050. tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);
  7051. if (tmp) {
  7052. return Math.floor(tmp[1]) + tmp[2];
  7053. }
  7054. return styleVal;
  7055. }
  7056. return domUtils.getComputedStyle(startNode, style);
  7057. },
  7058. queryCommandState: function (cmdName) {
  7059. if (!needCmd[cmdName])
  7060. return 0;
  7061. var val = this.queryCommandValue(cmdName);
  7062. if (cmdName == 'fontborder') {
  7063. return /1px/.test(val) && /solid/.test(val)
  7064. } else {
  7065. return val == (cmdName == 'underline' ?
  7066. 'underline' : 'line-through');
  7067. }
  7068. }
  7069. };
  7070. })(p, fonts[p]);
  7071. }
  7072. };
  7073. ///import core
  7074. ///commands 超链接,取消链接
  7075. ///commandsName Link,Unlink
  7076. ///commandsTitle 超链接,取消链接
  7077. ///commandsDialog dialogs\link
  7078. /**
  7079. * 超链接
  7080. * @function
  7081. * @name baidu.editor.execCommand
  7082. * @param {String} cmdName link插入超链接
  7083. * @param {Object} options url地址,title标题,target是否打开新页
  7084. * @author zhanyi
  7085. */
  7086. /**
  7087. * 取消链接
  7088. * @function
  7089. * @name baidu.editor.execCommand
  7090. * @param {String} cmdName unlink取消链接
  7091. * @author zhanyi
  7092. */
  7093. UE.plugins['link'] = function () {
  7094. function optimize(range) {
  7095. var start = range.startContainer, end = range.endContainer;
  7096. if (start = domUtils.findParentByTagName(start, 'a', true)) {
  7097. range.setStartBefore(start);
  7098. }
  7099. if (end = domUtils.findParentByTagName(end, 'a', true)) {
  7100. range.setEndAfter(end);
  7101. }
  7102. }
  7103. UE.commands['unlink'] = {
  7104. execCommand: function () {
  7105. var range = this.selection.getRange(),
  7106. bookmark;
  7107. if (range.collapsed && !domUtils.findParentByTagName(range.startContainer, 'a', true)) {
  7108. return;
  7109. }
  7110. bookmark = range.createBookmark();
  7111. optimize(range);
  7112. range.removeInlineStyle('a').moveToBookmark(bookmark).select();
  7113. },
  7114. queryCommandState: function () {
  7115. return !this.highlight && this.queryCommandValue('link') ? 0 : -1;
  7116. }
  7117. };
  7118. function doLink(range, opt, me) {
  7119. var rngClone = range.cloneRange(),
  7120. link = me.queryCommandValue('link');
  7121. optimize(range = range.adjustmentBoundary());
  7122. var start = range.startContainer;
  7123. if (start.nodeType == 1 && link) {
  7124. start = start.childNodes[range.startOffset];
  7125. if (start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie ? 'innerText' : 'textContent'])) {
  7126. start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue || opt.href);
  7127. }
  7128. }
  7129. if (!rngClone.collapsed || link) {
  7130. range.removeInlineStyle('a');
  7131. rngClone = range.cloneRange();
  7132. }
  7133. if (rngClone.collapsed) {
  7134. var a = range.document.createElement('a'),
  7135. text = '';
  7136. if (opt.textValue) {
  7137. text = utils.html(opt.textValue);
  7138. delete opt.textValue;
  7139. } else {
  7140. text = utils.html(opt.href);
  7141. }
  7142. domUtils.setAttributes(a, opt);
  7143. start = domUtils.findParentByTagName(rngClone.startContainer, 'a', true);
  7144. if (start && domUtils.isInNodeEndBoundary(rngClone, start)) {
  7145. range.setStartAfter(start).collapse(true);
  7146. }
  7147. a[browser.ie ? 'innerText' : 'textContent'] = text;
  7148. range.insertNode(a).selectNode(a);
  7149. } else {
  7150. range.applyInlineStyle('a', opt);
  7151. }
  7152. }
  7153. UE.commands['link'] = {
  7154. execCommand: function (cmdName, opt) {
  7155. var range;
  7156. opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g));
  7157. opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g));
  7158. opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g));
  7159. doLink(range = this.selection.getRange(), opt, this);
  7160. //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
  7161. range.collapse().select(true);
  7162. },
  7163. queryCommandValue: function () {
  7164. var range = this.selection.getRange(),
  7165. node;
  7166. if (range.collapsed) {
  7167. // node = this.selection.getStart();
  7168. //在ie下getstart()取值偏上了
  7169. node = range.startContainer;
  7170. node = node.nodeType == 1 ? node : node.parentNode;
  7171. if (node && (node = domUtils.findParentByTagName(node, 'a', true)) && !domUtils.isInNodeEndBoundary(range, node)) {
  7172. return node;
  7173. }
  7174. } else {
  7175. //trace:1111 如果是<p><a>xx</a></p> startContainer是p就会找不到a
  7176. range.shrinkBoundary();
  7177. var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset],
  7178. end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset - 1],
  7179. common = range.getCommonAncestor();
  7180. node = domUtils.findParentByTagName(common, 'a', true);
  7181. if (!node && common.nodeType == 1) {
  7182. var as = common.getElementsByTagName('a'),
  7183. ps, pe;
  7184. for (var i = 0, ci; ci = as[i++];) {
  7185. ps = domUtils.getPosition(ci, start), pe = domUtils.getPosition(ci, end);
  7186. if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS)
  7187. &&
  7188. (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
  7189. ) {
  7190. node = ci;
  7191. break;
  7192. }
  7193. }
  7194. }
  7195. return node;
  7196. }
  7197. },
  7198. queryCommandState: function () {
  7199. //判断如果是视频的话连接不可用
  7200. //fix 853
  7201. var img = this.selection.getRange().getClosedNode(),
  7202. flag = img && (img.className == "edui-faked-video");
  7203. return flag ? -1 : 0;
  7204. }
  7205. };
  7206. };
  7207. ///import core
  7208. ///import plugins\inserthtml.js
  7209. ///commands 插入框架
  7210. ///commandsName InsertFrame
  7211. ///commandsTitle 插入Iframe
  7212. ///commandsDialog dialogs\insertframe
  7213. UE.plugins['insertframe'] = function () {
  7214. var me = this;
  7215. function deleteIframe() {
  7216. me._iframe && delete me._iframe;
  7217. }
  7218. me.addListener("selectionchange", function () {
  7219. deleteIframe();
  7220. });
  7221. };
  7222. ///import core
  7223. ///commands 涂鸦
  7224. ///commandsName Scrawl
  7225. ///commandsTitle 涂鸦
  7226. ///commandsDialog dialogs\scrawl
  7227. UE.commands['scrawl'] = {
  7228. queryCommandState: function () {
  7229. return ( browser.ie && browser.version <= 8 ) ? -1 : 0;
  7230. }
  7231. };
  7232. ///import core
  7233. ///commands 清除格式
  7234. ///commandsName RemoveFormat
  7235. ///commandsTitle 清除格式
  7236. /**
  7237. * @description 清除格式
  7238. * @name baidu.editor.execCommand
  7239. * @param {String} cmdName removeformat清除格式命令
  7240. * @param {String} tags 以逗号隔开的标签。如:span,a
  7241. * @param {String} style 样式
  7242. * @param {String} attrs 属性
  7243. * @param {String} notIncluedA 是否把a标签切开
  7244. * @author zhanyi
  7245. */
  7246. UE.plugins['removeformat'] = function () {
  7247. var me = this;
  7248. me.setOpt({
  7249. 'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var',
  7250. 'removeFormatAttributes': 'class,style,lang,width,height,align,hspace,valign'
  7251. });
  7252. me.commands['removeformat'] = {
  7253. execCommand: function (cmdName, tags, style, attrs, notIncludeA) {
  7254. var tagReg = new RegExp('^(?:' + (tags || this.options.removeFormatTags).replace(/,/g, '|') + ')$', 'i') ,
  7255. removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split(','),
  7256. range = new dom.Range(this.document),
  7257. bookmark, node, parent,
  7258. filter = function (node) {
  7259. return node.nodeType == 1;
  7260. };
  7261. function isRedundantSpan(node) {
  7262. if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span') {
  7263. return 0;
  7264. }
  7265. if (browser.ie) {
  7266. //ie 下判断实效,所以只能简单用style来判断
  7267. //return node.style.cssText == '' ? 1 : 0;
  7268. var attrs = node.attributes;
  7269. if (attrs.length) {
  7270. for (var i = 0, l = attrs.length; i < l; i++) {
  7271. if (attrs[i].specified) {
  7272. return 0;
  7273. }
  7274. }
  7275. return 1;
  7276. }
  7277. }
  7278. return !node.attributes.length;
  7279. }
  7280. function doRemove(range) {
  7281. var bookmark1 = range.createBookmark();
  7282. if (range.collapsed) {
  7283. range.enlarge(true);
  7284. }
  7285. //不能把a标签切了
  7286. if (!notIncludeA) {
  7287. var aNode = domUtils.findParentByTagName(range.startContainer, 'a', true);
  7288. if (aNode) {
  7289. range.setStartBefore(aNode);
  7290. }
  7291. aNode = domUtils.findParentByTagName(range.endContainer, 'a', true);
  7292. if (aNode) {
  7293. range.setEndAfter(aNode);
  7294. }
  7295. }
  7296. bookmark = range.createBookmark();
  7297. node = bookmark.start;
  7298. //切开始
  7299. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  7300. domUtils.breakParent(node, parent);
  7301. domUtils.clearEmptySibling(node);
  7302. }
  7303. if (bookmark.end) {
  7304. //切结束
  7305. node = bookmark.end;
  7306. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  7307. domUtils.breakParent(node, parent);
  7308. domUtils.clearEmptySibling(node);
  7309. }
  7310. //开始去除样式
  7311. var current = domUtils.getNextDomNode(bookmark.start, false, filter),
  7312. next;
  7313. while (current) {
  7314. if (current == bookmark.end) {
  7315. break;
  7316. }
  7317. next = domUtils.getNextDomNode(current, true, filter);
  7318. if (!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(current)) {
  7319. if (tagReg.test(current.tagName)) {
  7320. if (style) {
  7321. domUtils.removeStyle(current, style);
  7322. if (isRedundantSpan(current) && style != 'text-decoration') {
  7323. domUtils.remove(current, true);
  7324. }
  7325. } else {
  7326. domUtils.remove(current, true);
  7327. }
  7328. } else {
  7329. //trace:939 不能把list上的样式去掉
  7330. if (!dtd.$tableContent[current.tagName] && !dtd.$list[current.tagName]) {
  7331. domUtils.removeAttributes(current, removeFormatAttributes);
  7332. if (isRedundantSpan(current)) {
  7333. domUtils.remove(current, true);
  7334. }
  7335. }
  7336. }
  7337. }
  7338. current = next;
  7339. }
  7340. }
  7341. //trace:1035
  7342. //trace:1096 不能把td上的样式去掉,比如边框
  7343. var pN = bookmark.start.parentNode;
  7344. if (domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) {
  7345. domUtils.removeAttributes(pN, removeFormatAttributes);
  7346. }
  7347. pN = bookmark.end.parentNode;
  7348. if (bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) {
  7349. domUtils.removeAttributes(pN, removeFormatAttributes);
  7350. }
  7351. range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
  7352. //清除冗余的代码 <b><bookmark></b>
  7353. var node = range.startContainer,
  7354. tmp,
  7355. collapsed = range.collapsed;
  7356. while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
  7357. tmp = node.parentNode;
  7358. range.setStartBefore(node);
  7359. //trace:937
  7360. //更新结束边界
  7361. if (range.startContainer === range.endContainer) {
  7362. range.endOffset--;
  7363. }
  7364. domUtils.remove(node);
  7365. node = tmp;
  7366. }
  7367. if (!collapsed) {
  7368. node = range.endContainer;
  7369. while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
  7370. tmp = node.parentNode;
  7371. range.setEndBefore(node);
  7372. domUtils.remove(node);
  7373. node = tmp;
  7374. }
  7375. }
  7376. }
  7377. range = this.selection.getRange();
  7378. doRemove(range);
  7379. range.select();
  7380. }
  7381. };
  7382. };
  7383. ///import core
  7384. ///commands 引用
  7385. ///commandsName BlockQuote
  7386. ///commandsTitle 引用
  7387. /**
  7388. *
  7389. * 引用模块实现
  7390. * @function
  7391. * @name baidu.editor.execCommand
  7392. * @param {String} cmdName blockquote引用
  7393. */
  7394. UE.plugins['blockquote'] = function () {
  7395. var me = this;
  7396. function getObj(editor) {
  7397. return domUtils.filterNodeList(editor.selection.getStartElementPath(), 'blockquote');
  7398. }
  7399. me.commands['blockquote'] = {
  7400. execCommand: function (cmdName, attrs) {
  7401. var range = this.selection.getRange(),
  7402. obj = getObj(this),
  7403. blockquote = dtd.blockquote,
  7404. bookmark = range.createBookmark();
  7405. if (obj) {
  7406. var start = range.startContainer,
  7407. startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start, function (node) {
  7408. return domUtils.isBlockElm(node)
  7409. }),
  7410. end = range.endContainer,
  7411. endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end, function (node) {
  7412. return domUtils.isBlockElm(node)
  7413. });
  7414. //处理一下li
  7415. startBlock = domUtils.findParentByTagName(startBlock, 'li', true) || startBlock;
  7416. endBlock = domUtils.findParentByTagName(endBlock, 'li', true) || endBlock;
  7417. if (startBlock.tagName == 'LI' || startBlock.tagName == 'TD' || startBlock === obj || domUtils.isBody(startBlock)) {
  7418. domUtils.remove(obj, true);
  7419. } else {
  7420. domUtils.breakParent(startBlock, obj);
  7421. }
  7422. if (startBlock !== endBlock) {
  7423. obj = domUtils.findParentByTagName(endBlock, 'blockquote');
  7424. if (obj) {
  7425. if (endBlock.tagName == 'LI' || endBlock.tagName == 'TD' || domUtils.isBody(endBlock)) {
  7426. obj.parentNode && domUtils.remove(obj, true);
  7427. } else {
  7428. domUtils.breakParent(endBlock, obj);
  7429. }
  7430. }
  7431. }
  7432. var blockquotes = domUtils.getElementsByTagName(this.document, 'blockquote');
  7433. for (var i = 0, bi; bi = blockquotes[i++];) {
  7434. if (!bi.childNodes.length) {
  7435. domUtils.remove(bi);
  7436. } else if (domUtils.getPosition(bi, startBlock) & domUtils.POSITION_FOLLOWING && domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING) {
  7437. domUtils.remove(bi, true);
  7438. }
  7439. }
  7440. } else {
  7441. var tmpRange = range.cloneRange(),
  7442. node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode,
  7443. preNode = node,
  7444. doEnd = 1;
  7445. //调整开始
  7446. while (1) {
  7447. if (domUtils.isBody(node)) {
  7448. if (preNode !== node) {
  7449. if (range.collapsed) {
  7450. tmpRange.selectNode(preNode);
  7451. doEnd = 0;
  7452. } else {
  7453. tmpRange.setStartBefore(preNode);
  7454. }
  7455. } else {
  7456. tmpRange.setStart(node, 0);
  7457. }
  7458. break;
  7459. }
  7460. if (!blockquote[node.tagName]) {
  7461. if (range.collapsed) {
  7462. tmpRange.selectNode(preNode);
  7463. } else {
  7464. tmpRange.setStartBefore(preNode);
  7465. }
  7466. break;
  7467. }
  7468. preNode = node;
  7469. node = node.parentNode;
  7470. }
  7471. //调整结束
  7472. if (doEnd) {
  7473. preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode;
  7474. while (1) {
  7475. if (domUtils.isBody(node)) {
  7476. if (preNode !== node) {
  7477. tmpRange.setEndAfter(preNode);
  7478. } else {
  7479. tmpRange.setEnd(node, node.childNodes.length);
  7480. }
  7481. break;
  7482. }
  7483. if (!blockquote[node.tagName]) {
  7484. tmpRange.setEndAfter(preNode);
  7485. break;
  7486. }
  7487. preNode = node;
  7488. node = node.parentNode;
  7489. }
  7490. }
  7491. node = range.document.createElement('blockquote');
  7492. domUtils.setAttributes(node, attrs);
  7493. node.appendChild(tmpRange.extractContents());
  7494. tmpRange.insertNode(node);
  7495. //去除重复的
  7496. var childs = domUtils.getElementsByTagName(node, 'blockquote');
  7497. for (var i = 0, ci; ci = childs[i++];) {
  7498. if (ci.parentNode) {
  7499. domUtils.remove(ci, true);
  7500. }
  7501. }
  7502. }
  7503. range.moveToBookmark(bookmark).select();
  7504. },
  7505. queryCommandState: function () {
  7506. return getObj(this) ? 1 : 0;
  7507. }
  7508. };
  7509. };
  7510. ///import core
  7511. ///commands 大小写转换
  7512. ///commandsName touppercase,tolowercase
  7513. ///commandsTitle 大写,小写
  7514. /**
  7515. * 大小写转换
  7516. * @function
  7517. * @name baidu.editor.execCommands
  7518. * @param {String} cmdName cmdName="convertcase"
  7519. */
  7520. UE.commands['touppercase'] =
  7521. UE.commands['tolowercase'] = {
  7522. execCommand: function (cmd) {
  7523. var me = this;
  7524. var rng = me.selection.getRange();
  7525. if (rng.collapsed) {
  7526. return rng;
  7527. }
  7528. var bk = rng.createBookmark(),
  7529. bkEnd = bk.end,
  7530. filterFn = function (node) {
  7531. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  7532. },
  7533. curNode = domUtils.getNextDomNode(bk.start, false, filterFn);
  7534. while (curNode && (domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING)) {
  7535. if (curNode.nodeType == 3) {
  7536. curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase']();
  7537. }
  7538. curNode = domUtils.getNextDomNode(curNode, true, filterFn);
  7539. if (curNode === bkEnd) {
  7540. break;
  7541. }
  7542. }
  7543. rng.moveToBookmark(bk).select();
  7544. }
  7545. };
  7546. ///import core
  7547. ///import plugins\paragraph.js
  7548. ///commands 首行缩进
  7549. ///commandsName Outdent,Indent
  7550. ///commandsTitle 取消缩进,首行缩进
  7551. /**
  7552. * 首行缩进
  7553. * @function
  7554. * @name baidu.editor.execCommand
  7555. * @param {String} cmdName outdent取消缩进,indent缩进
  7556. */
  7557. UE.commands['indent'] = {
  7558. execCommand: function () {
  7559. var me = this, value = me.queryCommandState("indent") ? "0em" : (me.options.indentValue || '2em');
  7560. me.execCommand('Paragraph', 'p', {style: 'text-indent:' + value});
  7561. },
  7562. queryCommandState: function () {
  7563. var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6');
  7564. return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
  7565. }
  7566. };
  7567. ///import core
  7568. ///commands 打印
  7569. ///commandsName Print
  7570. ///commandsTitle 打印
  7571. /**
  7572. * @description 打印
  7573. * @name baidu.editor.execCommand
  7574. * @param {String} cmdName print打印编辑器内容
  7575. * @author zhanyi
  7576. */
  7577. UE.commands['print'] = {
  7578. execCommand: function () {
  7579. this.window.print();
  7580. },
  7581. notNeedUndo: 1
  7582. };
  7583. ///import core
  7584. ///commands 预览
  7585. ///commandsName Preview
  7586. ///commandsTitle 预览
  7587. /**
  7588. * 预览
  7589. * @function
  7590. * @name baidu.editor.execCommand
  7591. * @param {String} cmdName preview预览编辑器内容
  7592. */
  7593. UE.commands['preview'] = {
  7594. execCommand: function () {
  7595. var w = window.open('', '_blank', ''),
  7596. d = w.document;
  7597. d.open();
  7598. d.write('<html><head><script src="' + this.options.UEDITOR_HOME_URL + 'ueditor.parse.js"></script><script>' +
  7599. "setTimeout(function(){uParse('div',{" +
  7600. " 'highlightJsUrl':'" + this.options.UEDITOR_HOME_URL + "third-party/SyntaxHighlighter/shCore.js'," +
  7601. " 'highlightCssUrl':'" + this.options.UEDITOR_HOME_URL + "third-party/SyntaxHighlighter/shCoreDefault.css'" +
  7602. "})},300)" +
  7603. '</script></head><body><div>' + this.getContent(null, null, true) + '</div></body></html>');
  7604. d.close();
  7605. },
  7606. notNeedUndo: 1
  7607. };
  7608. ///import core
  7609. ///commands 全选
  7610. ///commandsName SelectAll
  7611. ///commandsTitle 全选
  7612. /**
  7613. * 选中所有
  7614. * @function
  7615. * @name baidu.editor.execCommand
  7616. * @param {String} cmdName selectall选中编辑器里的所有内容
  7617. * @author zhanyi
  7618. */
  7619. UE.plugins['selectall'] = function () {
  7620. var me = this;
  7621. me.commands['selectall'] = {
  7622. execCommand: function () {
  7623. //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
  7624. var me = this, body = me.body,
  7625. range = me.selection.getRange();
  7626. range.selectNodeContents(body);
  7627. if (domUtils.isEmptyBlock(body)) {
  7628. //opera不能自动合并到元素的里边,要手动处理一下
  7629. if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
  7630. range.setStartAtFirst(body.firstChild);
  7631. }
  7632. range.collapse(true);
  7633. }
  7634. range.select(true);
  7635. },
  7636. notNeedUndo: 1
  7637. };
  7638. //快捷键
  7639. me.addshortcutkey({
  7640. "selectAll": "ctrl+65"
  7641. });
  7642. };
  7643. ///import core
  7644. ///commands 格式
  7645. ///commandsName Paragraph
  7646. ///commandsTitle 段落格式
  7647. /**
  7648. * 段落样式
  7649. * @function
  7650. * @name baidu.editor.execCommand
  7651. * @param {String} cmdName paragraph插入段落执行命令
  7652. * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
  7653. * @param {String} attrs 标签的属性
  7654. * @author zhanyi
  7655. */
  7656. UE.plugins['paragraph'] = function () {
  7657. var me = this,
  7658. block = domUtils.isBlockElm,
  7659. notExchange = ['TD', 'LI', 'PRE'],
  7660. doParagraph = function (range, style, attrs, sourceCmdName) {
  7661. var bookmark = range.createBookmark(),
  7662. filterFn = function (node) {
  7663. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
  7664. },
  7665. para;
  7666. range.enlarge(true);
  7667. var bookmark2 = range.createBookmark(),
  7668. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  7669. tmpRange = range.cloneRange(),
  7670. tmpNode;
  7671. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  7672. if (current.nodeType == 3 || !block(current)) {
  7673. tmpRange.setStartBefore(current);
  7674. while (current && current !== bookmark2.end && !block(current)) {
  7675. tmpNode = current;
  7676. current = domUtils.getNextDomNode(current, false, null, function (node) {
  7677. return !block(node);
  7678. });
  7679. }
  7680. tmpRange.setEndAfter(tmpNode);
  7681. para = range.document.createElement(style);
  7682. if (attrs) {
  7683. domUtils.setAttributes(para, attrs);
  7684. if (sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) {
  7685. para.style.cssText = attrs.style;
  7686. }
  7687. }
  7688. para.appendChild(tmpRange.extractContents());
  7689. //需要内容占位
  7690. if (domUtils.isEmptyNode(para)) {
  7691. domUtils.fillChar(range.document, para);
  7692. }
  7693. tmpRange.insertNode(para);
  7694. var parent = para.parentNode;
  7695. //如果para上一级是一个block元素且不是body,td就删除它
  7696. if (block(parent) && !domUtils.isBody(para.parentNode) && utils.indexOf(notExchange, parent.tagName) == -1) {
  7697. //存储dir,style
  7698. if (!(sourceCmdName && sourceCmdName == 'customstyle')) {
  7699. parent.getAttribute('dir') && para.setAttribute('dir', parent.getAttribute('dir'));
  7700. //trace:1070
  7701. parent.style.cssText && (para.style.cssText = parent.style.cssText + ';' + para.style.cssText);
  7702. //trace:1030
  7703. parent.style.textAlign && !para.style.textAlign && (para.style.textAlign = parent.style.textAlign);
  7704. parent.style.textIndent && !para.style.textIndent && (para.style.textIndent = parent.style.textIndent);
  7705. parent.style.padding && !para.style.padding && (para.style.padding = parent.style.padding);
  7706. }
  7707. //trace:1706 选择的就是h1-6要删除
  7708. if (attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName)) {
  7709. domUtils.setAttributes(parent, attrs);
  7710. if (sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) {
  7711. parent.style.cssText = attrs.style;
  7712. }
  7713. domUtils.remove(para, true);
  7714. para = parent;
  7715. } else {
  7716. domUtils.remove(para.parentNode, true);
  7717. }
  7718. }
  7719. if (utils.indexOf(notExchange, parent.tagName) != -1) {
  7720. current = parent;
  7721. } else {
  7722. current = para;
  7723. }
  7724. current = domUtils.getNextDomNode(current, false, filterFn);
  7725. } else {
  7726. current = domUtils.getNextDomNode(current, true, filterFn);
  7727. }
  7728. }
  7729. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  7730. };
  7731. me.setOpt('paragraph', {'p': '', 'h1': '', 'h2': '', 'h3': '', 'h4': '', 'h5': '', 'h6': ''});
  7732. me.commands['paragraph'] = {
  7733. execCommand: function (cmdName, style, attrs, sourceCmdName) {
  7734. var range = this.selection.getRange();
  7735. //闭合时单独处理
  7736. if (range.collapsed) {
  7737. var txt = this.document.createTextNode('p');
  7738. range.insertNode(txt);
  7739. //去掉冗余的fillchar
  7740. if (browser.ie) {
  7741. var node = txt.previousSibling;
  7742. if (node && domUtils.isWhitespace(node)) {
  7743. domUtils.remove(node);
  7744. }
  7745. node = txt.nextSibling;
  7746. if (node && domUtils.isWhitespace(node)) {
  7747. domUtils.remove(node);
  7748. }
  7749. }
  7750. }
  7751. range = doParagraph(range, style, attrs, sourceCmdName);
  7752. if (txt) {
  7753. range.setStartBefore(txt).collapse(true);
  7754. pN = txt.parentNode;
  7755. domUtils.remove(txt);
  7756. if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
  7757. domUtils.fillNode(this.document, pN);
  7758. }
  7759. }
  7760. if (browser.gecko && range.collapsed && range.startContainer.nodeType == 1) {
  7761. var child = range.startContainer.childNodes[range.startOffset];
  7762. if (child && child.nodeType == 1 && child.tagName.toLowerCase() == style) {
  7763. range.setStart(child, 0).collapse(true);
  7764. }
  7765. }
  7766. //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
  7767. range.select();
  7768. return true;
  7769. },
  7770. queryCommandValue: function () {
  7771. var node = domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6');
  7772. return node ? node.tagName.toLowerCase() : '';
  7773. }
  7774. };
  7775. };
  7776. ///import core
  7777. ///commands 输入的方向
  7778. ///commandsName DirectionalityLtr,DirectionalityRtl
  7779. ///commandsTitle 从左向右输入,从右向左输入
  7780. /**
  7781. * 输入的方向
  7782. * @function
  7783. * @name baidu.editor.execCommand
  7784. * @param {String} cmdName directionality执行函数的参数
  7785. * @param {String} forward ltr从左向右输入,rtl从右向左输入
  7786. */
  7787. (function () {
  7788. var block = domUtils.isBlockElm ,
  7789. getObj = function (editor) {
  7790. // var startNode = editor.selection.getStart(),
  7791. // parents;
  7792. // if ( startNode ) {
  7793. // //查找所有的是block的父亲节点
  7794. // parents = domUtils.findParents( startNode, true, block, true );
  7795. // for ( var i = 0,ci; ci = parents[i++]; ) {
  7796. // if ( ci.getAttribute( 'dir' ) ) {
  7797. // return ci;
  7798. // }
  7799. // }
  7800. // }
  7801. return domUtils.filterNodeList(editor.selection.getStartElementPath(), function (n) {
  7802. return n.getAttribute('dir')
  7803. });
  7804. },
  7805. doDirectionality = function (range, editor, forward) {
  7806. var bookmark,
  7807. filterFn = function (node) {
  7808. return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
  7809. },
  7810. obj = getObj(editor);
  7811. if (obj && range.collapsed) {
  7812. obj.setAttribute('dir', forward);
  7813. return range;
  7814. }
  7815. bookmark = range.createBookmark();
  7816. range.enlarge(true);
  7817. var bookmark2 = range.createBookmark(),
  7818. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  7819. tmpRange = range.cloneRange(),
  7820. tmpNode;
  7821. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  7822. if (current.nodeType == 3 || !block(current)) {
  7823. tmpRange.setStartBefore(current);
  7824. while (current && current !== bookmark2.end && !block(current)) {
  7825. tmpNode = current;
  7826. current = domUtils.getNextDomNode(current, false, null, function (node) {
  7827. return !block(node);
  7828. });
  7829. }
  7830. tmpRange.setEndAfter(tmpNode);
  7831. var common = tmpRange.getCommonAncestor();
  7832. if (!domUtils.isBody(common) && block(common)) {
  7833. //遍历到了block节点
  7834. common.setAttribute('dir', forward);
  7835. current = common;
  7836. } else {
  7837. //没有遍历到,添加一个block节点
  7838. var p = range.document.createElement('p');
  7839. p.setAttribute('dir', forward);
  7840. var frag = tmpRange.extractContents();
  7841. p.appendChild(frag);
  7842. tmpRange.insertNode(p);
  7843. current = p;
  7844. }
  7845. current = domUtils.getNextDomNode(current, false, filterFn);
  7846. } else {
  7847. current = domUtils.getNextDomNode(current, true, filterFn);
  7848. }
  7849. }
  7850. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  7851. };
  7852. UE.commands['directionality'] = {
  7853. execCommand: function (cmdName, forward) {
  7854. var range = this.selection.getRange();
  7855. //闭合时单独处理
  7856. if (range.collapsed) {
  7857. var txt = this.document.createTextNode('d');
  7858. range.insertNode(txt);
  7859. }
  7860. doDirectionality(range, this, forward);
  7861. if (txt) {
  7862. range.setStartBefore(txt).collapse(true);
  7863. domUtils.remove(txt);
  7864. }
  7865. range.select();
  7866. return true;
  7867. },
  7868. queryCommandValue: function () {
  7869. var node = getObj(this);
  7870. return node ? node.getAttribute('dir') : 'ltr';
  7871. }
  7872. };
  7873. })();
  7874. ///import core
  7875. ///import plugins\inserthtml.js
  7876. ///commands 分割线
  7877. ///commandsName Horizontal
  7878. ///commandsTitle 分隔线
  7879. /**
  7880. * 分割线
  7881. * @function
  7882. * @name baidu.editor.execCommand
  7883. * @param {String} cmdName horizontal插入分割线
  7884. */
  7885. UE.plugins['horizontal'] = function () {
  7886. var me = this;
  7887. me.commands['horizontal'] = {
  7888. execCommand: function (cmdName) {
  7889. var me = this;
  7890. if (me.queryCommandState(cmdName) !== -1) {
  7891. me.execCommand('insertHtml', '<hr>');
  7892. var range = me.selection.getRange(),
  7893. start = range.startContainer;
  7894. if (start.nodeType == 1 && !start.childNodes[range.startOffset]) {
  7895. var tmp;
  7896. if (tmp = start.childNodes[range.startOffset - 1]) {
  7897. if (tmp.nodeType == 1 && tmp.tagName == 'HR') {
  7898. if (me.options.enterTag == 'p') {
  7899. tmp = me.document.createElement('p');
  7900. range.insertNode(tmp);
  7901. range.setStart(tmp, 0).setCursor();
  7902. } else {
  7903. tmp = me.document.createElement('br');
  7904. range.insertNode(tmp);
  7905. range.setStartBefore(tmp).setCursor();
  7906. }
  7907. }
  7908. }
  7909. }
  7910. return true;
  7911. }
  7912. },
  7913. //边界在table里不能加分隔线
  7914. queryCommandState: function () {
  7915. return domUtils.filterNodeList(this.selection.getStartElementPath(), 'table') ? -1 : 0;
  7916. }
  7917. };
  7918. // me.addListener('delkeyup',function(){
  7919. // var rng = this.selection.getRange();
  7920. // if(browser.ie && browser.version > 8){
  7921. // rng.txtToElmBoundary(true);
  7922. // if(domUtils.isStartInblock(rng)){
  7923. // var tmpNode = rng.startContainer;
  7924. // var pre = tmpNode.previousSibling;
  7925. // if(pre && domUtils.isTagNode(pre,'hr')){
  7926. // domUtils.remove(pre);
  7927. // rng.select();
  7928. // return;
  7929. // }
  7930. // }
  7931. // }
  7932. // if(domUtils.isBody(rng.startContainer)){
  7933. // var hr = rng.startContainer.childNodes[rng.startOffset -1];
  7934. // if(hr && hr.nodeName == 'HR'){
  7935. // var next = hr.nextSibling;
  7936. // if(next){
  7937. // rng.setStart(next,0)
  7938. // }else if(hr.previousSibling){
  7939. // rng.setStartAtLast(hr.previousSibling)
  7940. // }else{
  7941. // var p = this.document.createElement('p');
  7942. // hr.parentNode.insertBefore(p,hr);
  7943. // domUtils.fillNode(this.document,p);
  7944. // rng.setStart(p,0);
  7945. // }
  7946. // domUtils.remove(hr);
  7947. // rng.setCursor(false,true);
  7948. // }
  7949. // }
  7950. // })
  7951. me.addListener('delkeydown', function (name, evt) {
  7952. var rng = this.selection.getRange();
  7953. rng.txtToElmBoundary(true);
  7954. if (domUtils.isStartInblock(rng)) {
  7955. var tmpNode = rng.startContainer;
  7956. var pre = tmpNode.previousSibling;
  7957. if (pre && domUtils.isTagNode(pre, 'hr')) {
  7958. domUtils.remove(pre);
  7959. rng.select();
  7960. domUtils.preventDefault(evt);
  7961. return true;
  7962. }
  7963. }
  7964. })
  7965. };
  7966. ///import core
  7967. ///import plugins\inserthtml.js
  7968. ///commands 日期,时间
  7969. ///commandsName Date,Time
  7970. ///commandsTitle 日期,时间
  7971. /**
  7972. * 插入日期
  7973. * @function
  7974. * @name baidu.editor.execCommand
  7975. * @param {String} cmdName date插入日期
  7976. * @author zhuwenxuan
  7977. */
  7978. /**
  7979. * 插入时间
  7980. * @function
  7981. * @name baidu.editor.execCommand
  7982. * @param {String} cmdName time插入时间
  7983. * @author zhuwenxuan
  7984. */
  7985. UE.commands['time'] = UE.commands["date"] = {
  7986. execCommand: function (cmd) {
  7987. var date = new Date;
  7988. this.execCommand('insertHtml', cmd == "time" ?
  7989. (date.getHours() + ":" + (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":" + (date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds())) :
  7990. (date.getFullYear() + "-" + ((date.getMonth() + 1) < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-" + (date.getDate() < 10 ? "0" + date.getDate() : date.getDate())));
  7991. }
  7992. };
  7993. ///import core
  7994. ///import plugins\paragraph.js
  7995. ///commands 段间距
  7996. ///commandsName RowSpacingBottom,RowSpacingTop
  7997. ///commandsTitle 段间距
  7998. /**
  7999. * @description 设置段前距,段后距
  8000. * @name baidu.editor.execCommand
  8001. * @param {String} cmdName rowspacing设置段间距
  8002. * @param {String} value 值,以px为单位
  8003. * @param {String} dir top或bottom段前后段后
  8004. * @author zhanyi
  8005. */
  8006. UE.plugins['rowspacing'] = function () {
  8007. var me = this;
  8008. me.setOpt({
  8009. 'rowspacingtop': ['5', '10', '15', '20', '25'],
  8010. 'rowspacingbottom': ['5', '10', '15', '20', '25']
  8011. });
  8012. me.commands['rowspacing'] = {
  8013. execCommand: function (cmdName, value, dir) {
  8014. this.execCommand('paragraph', 'p', {style: 'margin-' + dir + ':' + value + 'px'});
  8015. return true;
  8016. },
  8017. queryCommandValue: function (cmdName, dir) {
  8018. var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function (node) {
  8019. return domUtils.isBlockElm(node)
  8020. }),
  8021. value;
  8022. //trace:1026
  8023. if (pN) {
  8024. value = domUtils.getComputedStyle(pN, 'margin-' + dir).replace(/[^\d]/g, '');
  8025. return !value ? 0 : value;
  8026. }
  8027. return 0;
  8028. }
  8029. };
  8030. };
  8031. ///import core
  8032. ///import plugins\paragraph.js
  8033. ///commands 行间距
  8034. ///commandsName LineHeight
  8035. ///commandsTitle 行间距
  8036. /**
  8037. * @description 设置行内间距
  8038. * @name baidu.editor.execCommand
  8039. * @param {String} cmdName lineheight设置行内间距
  8040. * @param {String} value 值
  8041. * @author zhuwenxuan
  8042. */
  8043. UE.plugins['lineheight'] = function () {
  8044. var me = this;
  8045. me.setOpt({'lineheight': ['1', '1.5', '1.75', '2', '3', '4', '5']});
  8046. me.commands['lineheight'] = {
  8047. execCommand: function (cmdName, value) {
  8048. this.execCommand('paragraph', 'p', {style: 'line-height:' + (value == "1" ? "normal" : value + 'em') });
  8049. return true;
  8050. },
  8051. queryCommandValue: function () {
  8052. var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function (node) {
  8053. return domUtils.isBlockElm(node)
  8054. });
  8055. if (pN) {
  8056. var value = domUtils.getComputedStyle(pN, 'line-height');
  8057. return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig, "");
  8058. }
  8059. }
  8060. };
  8061. };
  8062. ///import core
  8063. ///import plugins/inserthtml.js
  8064. ///commands 插入代码
  8065. ///commandsName code
  8066. ///commandsTitle 插入代码
  8067. UE.plugins['insertcode'] = function () {
  8068. var me = this;
  8069. me.ready(function () {
  8070. utils.cssRule('pre', 'pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}',
  8071. me.document)
  8072. });
  8073. me.setOpt('insertcode', {
  8074. 'as3': 'ActionScript3',
  8075. 'bash': 'Bash/Shell',
  8076. 'cpp': 'C/C++',
  8077. 'css': 'Css',
  8078. 'cf': 'CodeFunction',
  8079. 'c#': 'C#',
  8080. 'delphi': 'Delphi',
  8081. 'diff': 'Diff',
  8082. 'erlang': 'Erlang',
  8083. 'groovy': 'Groovy',
  8084. 'html': 'Html',
  8085. 'java': 'Java',
  8086. 'jfx': 'JavaFx',
  8087. 'js': 'Javascript',
  8088. 'pl': 'Perl',
  8089. 'php': 'Php',
  8090. 'plain': 'Plain Text',
  8091. 'ps': 'PowerShell',
  8092. 'python': 'Python',
  8093. 'ruby': 'Ruby',
  8094. 'scala': 'Scala',
  8095. 'sql': 'Sql',
  8096. 'vb': 'Vb',
  8097. 'xml': 'Xml'
  8098. });
  8099. me.commands['insertcode'] = {
  8100. execCommand: function (cmd, lang) {
  8101. var me = this,
  8102. rng = me.selection.getRange(),
  8103. pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
  8104. if (pre) {
  8105. pre.className = 'brush:' + lang + ';toolbar:false;';
  8106. } else {
  8107. var code = '';
  8108. if (rng.collapsed) {
  8109. code = browser.ie ? (browser.version > 8 ? '' : '&nbsp;') : '<br/>';
  8110. } else {
  8111. var frag = rng.extractContents();
  8112. var div = me.document.createElement('div');
  8113. div.appendChild(frag);
  8114. utils.each(UE.filterNode(UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, '')), me.options.filterTxtRules).children, function (node) {
  8115. if (browser.ie && browser.version > 8) {
  8116. if (node.type == 'element') {
  8117. if (node.tagName == 'br') {
  8118. code += '\n'
  8119. } else if (!dtd.$empty[node.tagName]) {
  8120. utils.each(node.children, function (cn) {
  8121. if (cn.type == 'element') {
  8122. if (cn.tagName == 'br') {
  8123. code += '\n'
  8124. } else if (!dtd.$empty[node.tagName]) {
  8125. code += cn.innerText();
  8126. }
  8127. } else {
  8128. code += cn.data
  8129. }
  8130. })
  8131. if (!/\n$/.test(code)) {
  8132. code += '\n';
  8133. }
  8134. }
  8135. } else {
  8136. code += node.data + '\n'
  8137. }
  8138. if (!node.nextSibling() && /\n$/.test(code)) {
  8139. code = code.replace(/\n$/, '');
  8140. }
  8141. } else {
  8142. if (browser.ie) {
  8143. if (node.type == 'element') {
  8144. if (node.tagName == 'br') {
  8145. code += '<br>'
  8146. } else if (!dtd.$empty[node.tagName]) {
  8147. utils.each(node.children, function (cn) {
  8148. if (cn.type == 'element') {
  8149. if (cn.tagName == 'br') {
  8150. code += '<br>'
  8151. } else if (!dtd.$empty[node.tagName]) {
  8152. code += cn.innerText();
  8153. }
  8154. } else {
  8155. code += cn.data
  8156. }
  8157. });
  8158. if (!/br>$/.test(code)) {
  8159. code += '<br>';
  8160. }
  8161. }
  8162. } else {
  8163. code += node.data + '<br>'
  8164. }
  8165. if (!node.nextSibling() && /<br>$/.test(code)) {
  8166. code = code.replace(/<br>$/, '');
  8167. }
  8168. } else {
  8169. code += (node.type == 'element' ? (dtd.$empty[node.tagName] ? '' : node.innerText()) : node.data);
  8170. if (!/br\/?\s*>$/.test(code)) {
  8171. if (!node.nextSibling())
  8172. return;
  8173. code += '<br>'
  8174. }
  8175. }
  8176. }
  8177. });
  8178. }
  8179. me.execCommand('inserthtml', '<pre id="coder"class="brush:' + lang + ';toolbar:false">' + code + '</pre>', true);
  8180. pre = me.document.getElementById('coder');
  8181. domUtils.removeAttributes(pre, 'id');
  8182. var tmpNode = pre.previousSibling;
  8183. if (tmpNode && (tmpNode.nodeType == 3 && tmpNode.nodeValue.length == 1 && browser.ie && browser.version == 6 || domUtils.isEmptyBlock(tmpNode))) {
  8184. domUtils.remove(tmpNode)
  8185. }
  8186. var rng = me.selection.getRange();
  8187. if (domUtils.isEmptyBlock(pre)) {
  8188. rng.setStart(pre, 0).setCursor(false, true)
  8189. } else {
  8190. rng.selectNodeContents(pre).select()
  8191. }
  8192. }
  8193. },
  8194. queryCommandValue: function () {
  8195. var path = this.selection.getStartElementPath();
  8196. var lang = '';
  8197. utils.each(path, function (node) {
  8198. if (node.nodeName == 'PRE') {
  8199. var match = node.className.match(/brush:([^;]+)/);
  8200. lang = match && match[1] ? match[1] : '';
  8201. return false;
  8202. }
  8203. });
  8204. return lang;
  8205. }
  8206. };
  8207. me.addInputRule(function (root) {
  8208. utils.each(root.getNodesByTagName('pre'), function (pre) {
  8209. var brs = pre.getNodesByTagName('br');
  8210. if (brs.length) {
  8211. browser.ie && browser.version > 8 && utils.each(brs, function (br) {
  8212. var txt = UE.uNode.createText('\n');
  8213. br.parentNode.insertBefore(txt, br);
  8214. br.parentNode.removeChild(br);
  8215. });
  8216. return;
  8217. }
  8218. if (browser.ie && browser.version > 8)
  8219. return;
  8220. var code = pre.innerText().split(/\n/);
  8221. pre.innerHTML('');
  8222. utils.each(code, function (c) {
  8223. if (c.length) {
  8224. pre.appendChild(UE.uNode.createText(c));
  8225. }
  8226. pre.appendChild(UE.uNode.createElement('br'))
  8227. })
  8228. })
  8229. });
  8230. me.addOutputRule(function (root) {
  8231. utils.each(root.getNodesByTagName('pre'), function (pre) {
  8232. var code = '';
  8233. utils.each(pre.children, function (n) {
  8234. if (n.type == 'text') {
  8235. //在ie下文本内容有可能末尾带有\n要去掉
  8236. //trace:3396
  8237. code += n.data.replace(/[ ]/g, '&nbsp;').replace(/\n$/, '');
  8238. } else {
  8239. if (n.tagName == 'br') {
  8240. code += '\n'
  8241. } else {
  8242. code += (!dtd.$empty[n.tagName] ? '' : n.innerText());
  8243. }
  8244. }
  8245. });
  8246. pre.innerText(code.replace(/(&nbsp;|\n)+$/, ''))
  8247. })
  8248. });
  8249. //不需要判断highlight的command列表
  8250. me.notNeedCodeQuery = {
  8251. help: 1,
  8252. undo: 1,
  8253. redo: 1,
  8254. source: 1,
  8255. print: 1,
  8256. searchreplace: 1,
  8257. fullscreen: 1,
  8258. preview: 1,
  8259. insertparagraph: 1,
  8260. elementpath: 1,
  8261. highlightcode: 1,
  8262. insertcode: 1,
  8263. inserthtml: 1,
  8264. selectall: 1
  8265. };
  8266. //将queyCommamndState重置
  8267. var orgQuery = me.queryCommandState;
  8268. me.queryCommandState = function (cmd) {
  8269. var me = this;
  8270. if (!me.notNeedCodeQuery[cmd.toLowerCase()] && me.selection && me.queryCommandValue('insertcode')) {
  8271. return -1;
  8272. }
  8273. return UE.Editor.prototype.queryCommandState.apply(this, arguments)
  8274. };
  8275. me.addListener('beforeenterkeydown', function () {
  8276. var rng = me.selection.getRange();
  8277. var pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
  8278. if (pre) {
  8279. me.fireEvent('saveScene');
  8280. if (!rng.collapsed) {
  8281. rng.deleteContents();
  8282. }
  8283. if (!browser.ie) {
  8284. var tmpNode = me.document.createElement('br'), pre;
  8285. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
  8286. var next = tmpNode.nextSibling;
  8287. if (!next) {
  8288. rng.insertNode(tmpNode.cloneNode(false));
  8289. } else {
  8290. rng.setStartAfter(tmpNode);
  8291. }
  8292. pre = tmpNode.previousSibling;
  8293. var tmp;
  8294. while (pre) {
  8295. tmp = pre;
  8296. pre = pre.previousSibling;
  8297. if (!pre || pre.nodeName == 'BR') {
  8298. pre = tmp;
  8299. break;
  8300. }
  8301. }
  8302. if (pre) {
  8303. var str = '';
  8304. while (pre && pre.nodeName != 'BR' && new RegExp('^[\\s' + domUtils.fillChar + ']*$').test(pre.nodeValue)) {
  8305. str += pre.nodeValue;
  8306. pre = pre.nextSibling;
  8307. }
  8308. if (pre.nodeName != 'BR') {
  8309. var match = pre.nodeValue.match(new RegExp('^([\\s' + domUtils.fillChar + ']+)'));
  8310. if (match && match[1]) {
  8311. str += match[1]
  8312. }
  8313. }
  8314. if (str) {
  8315. str = me.document.createTextNode(str);
  8316. rng.insertNode(str).setStartAfter(str);
  8317. }
  8318. }
  8319. rng.collapse(true).select(true);
  8320. } else {
  8321. if (browser.version > 8) {
  8322. var txt = me.document.createTextNode('\n');
  8323. var start = rng.startContainer;
  8324. if (rng.startOffset == 0) {
  8325. var preNode = start.previousSibling;
  8326. if (preNode) {
  8327. rng.insertNode(txt);
  8328. var fillchar = me.document.createTextNode(' ');
  8329. rng.setStartAfter(txt).insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true)
  8330. }
  8331. } else {
  8332. rng.insertNode(txt).setStartAfter(txt);
  8333. var fillchar = me.document.createTextNode(' ');
  8334. start = rng.startContainer.childNodes[rng.startOffset];
  8335. if (start && !/^\n/.test(start.nodeValue)) {
  8336. rng.setStartBefore(txt)
  8337. }
  8338. rng.insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true)
  8339. }
  8340. } else {
  8341. var tmpNode = me.document.createElement('br');
  8342. rng.insertNode(tmpNode);
  8343. rng.insertNode(me.document.createTextNode(domUtils.fillChar));
  8344. rng.setStartAfter(tmpNode);
  8345. pre = tmpNode.previousSibling;
  8346. var tmp;
  8347. while (pre) {
  8348. tmp = pre;
  8349. pre = pre.previousSibling;
  8350. if (!pre || pre.nodeName == 'BR') {
  8351. pre = tmp;
  8352. break;
  8353. }
  8354. }
  8355. if (pre) {
  8356. var str = '';
  8357. while (pre && pre.nodeName != 'BR' && new RegExp('^[ ' + domUtils.fillChar + ']*$').test(pre.nodeValue)) {
  8358. str += pre.nodeValue;
  8359. pre = pre.nextSibling;
  8360. }
  8361. if (pre.nodeName != 'BR') {
  8362. var match = pre.nodeValue.match(new RegExp('^([ ' + domUtils.fillChar + ']+)'));
  8363. if (match && match[1]) {
  8364. str += match[1]
  8365. }
  8366. }
  8367. str = me.document.createTextNode(str);
  8368. rng.insertNode(str).setStartAfter(str);
  8369. }
  8370. rng.collapse(true).select();
  8371. }
  8372. }
  8373. me.fireEvent('saveScene');
  8374. return true;
  8375. }
  8376. });
  8377. me.addListener('tabkeydown', function (cmd, evt) {
  8378. var rng = me.selection.getRange();
  8379. var pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
  8380. if (pre) {
  8381. me.fireEvent('saveScene');
  8382. if (evt.shiftKey) {
  8383. // if(!rng.collapsed){
  8384. // var bk = rng.createBookmark();
  8385. // var start = bk.start.previousSibling;
  8386. // if(start === pre.firstChild){
  8387. // start.nodeValue = start.nodeValue.replace(/^\s{4}/,'');
  8388. // }else{
  8389. // while(start){
  8390. // if(domUtils.isBr(start)){
  8391. // start = start.nextSibling;
  8392. // start.nodeValue = start.nodeValue.replace(/^\s{4}/,'');
  8393. // break;
  8394. // }
  8395. // while(start.previousSibling && start.previousSibling.nodeType == 3){
  8396. // start.nodeValue = start.previousSibling.nodeValue + start.nodeValue;
  8397. // domUtils.remove(start.previousSibling)
  8398. // }
  8399. // start = start.previousSibling;
  8400. // }
  8401. // }
  8402. //
  8403. // var end = bk.end;
  8404. // start = bk.start.nextSibling;
  8405. //
  8406. // while(start && start !== end){
  8407. // if(domUtils.isBr(start) && start.nextSibling){
  8408. // if(start.nextSibling === end){
  8409. // break;
  8410. // }
  8411. // start = start.nextSibling;
  8412. // while(start.nextSibling && start.nextSibling.nodeType == 3){
  8413. // start.nodeValue += start.nextSibling.nodeValue;
  8414. // domUtils.remove(start.nextSibling)
  8415. // }
  8416. //
  8417. // start.nodeValue = start.nodeValue.replace(/^\s{4}/,'');
  8418. // }
  8419. //
  8420. // start = start.nextSibling;
  8421. // }
  8422. // rng.moveToBookmark(bk).select();
  8423. // }else{
  8424. // var bk = rng.createBookmark();
  8425. // var start = bk.start.previousSibling;
  8426. // if(start === pre.firstChild){
  8427. // start.nodeValue = start.nodeValue.replace(/^\s{4}/,'');
  8428. // }else{
  8429. // while(start){
  8430. // if(domUtils.isBr(start)){
  8431. // start = start.nextSibling;
  8432. // start.nodeValue = start.nodeValue.replace(/^\s{4}/,'');
  8433. // break;
  8434. // }
  8435. // while(start.previousSibling && start.previousSibling.nodeType == 3){
  8436. // start.nodeValue = start.previousSibling.nodeValue + start.nodeValue;
  8437. // domUtils.remove(start.previousSibling)
  8438. // }
  8439. // start = start.previousSibling;
  8440. // }
  8441. // }
  8442. // }
  8443. } else {
  8444. if (!rng.collapsed) {
  8445. var bk = rng.createBookmark();
  8446. var start = bk.start.previousSibling;
  8447. while (start) {
  8448. if (pre.firstChild === start && !domUtils.isBr(start)) {
  8449. pre.insertBefore(me.document.createTextNode(' '), start);
  8450. break;
  8451. }
  8452. if (domUtils.isBr(start)) {
  8453. pre.insertBefore(me.document.createTextNode(' '), start.nextSibling);
  8454. break;
  8455. }
  8456. start = start.previousSibling;
  8457. }
  8458. var end = bk.end;
  8459. start = bk.start.nextSibling;
  8460. if (pre.firstChild === bk.start) {
  8461. pre.insertBefore(me.document.createTextNode(' '), start.nextSibling)
  8462. }
  8463. while (start && start !== end) {
  8464. if (domUtils.isBr(start) && start.nextSibling) {
  8465. if (start.nextSibling === end) {
  8466. break;
  8467. }
  8468. pre.insertBefore(me.document.createTextNode(' '), start.nextSibling)
  8469. }
  8470. start = start.nextSibling;
  8471. }
  8472. rng.moveToBookmark(bk).select();
  8473. } else {
  8474. var tmpNode = me.document.createTextNode(' ');
  8475. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true);
  8476. }
  8477. }
  8478. me.fireEvent('saveScene');
  8479. return true;
  8480. }
  8481. });
  8482. me.addListener('beforeinserthtml', function (evtName, html) {
  8483. var me = this,
  8484. rng = me.selection.getRange(),
  8485. pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
  8486. if (pre) {
  8487. if (!rng.collapsed) {
  8488. rng.deleteContents()
  8489. }
  8490. var htmlstr = '';
  8491. if (browser.ie && browser.version > 8) {
  8492. utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children, function (node) {
  8493. if (node.type == 'element') {
  8494. if (node.tagName == 'br') {
  8495. htmlstr += '\n'
  8496. } else if (!dtd.$empty[node.tagName]) {
  8497. utils.each(node.children, function (cn) {
  8498. if (cn.type == 'element') {
  8499. if (cn.tagName == 'br') {
  8500. htmlstr += '\n'
  8501. } else if (!dtd.$empty[node.tagName]) {
  8502. htmlstr += cn.innerText();
  8503. }
  8504. } else {
  8505. htmlstr += cn.data
  8506. }
  8507. })
  8508. if (!/\n$/.test(htmlstr)) {
  8509. htmlstr += '\n';
  8510. }
  8511. }
  8512. } else {
  8513. htmlstr += node.data + '\n'
  8514. }
  8515. if (!node.nextSibling() && /\n$/.test(htmlstr)) {
  8516. htmlstr = htmlstr.replace(/\n$/, '');
  8517. }
  8518. });
  8519. var tmpNode = me.document.createTextNode(utils.html(htmlstr.replace(/&nbsp;/g, ' ')));
  8520. rng.insertNode(tmpNode).selectNode(tmpNode).select();
  8521. } else {
  8522. var frag = me.document.createDocumentFragment();
  8523. utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children, function (node) {
  8524. if (node.type == 'element') {
  8525. if (node.tagName == 'br') {
  8526. frag.appendChild(me.document.createElement('br'))
  8527. } else if (!dtd.$empty[node.tagName]) {
  8528. utils.each(node.children, function (cn) {
  8529. if (cn.type == 'element') {
  8530. if (cn.tagName == 'br') {
  8531. frag.appendChild(me.document.createElement('br'))
  8532. } else if (!dtd.$empty[node.tagName]) {
  8533. frag.appendChild(me.document.createTextNode(utils.html(cn.innerText().replace(/&nbsp;/g, ' '))));
  8534. }
  8535. } else {
  8536. frag.appendChild(me.document.createTextNode(utils.html(cn.data.replace(/&nbsp;/g, ' '))));
  8537. }
  8538. })
  8539. if (frag.lastChild.nodeName != 'BR') {
  8540. frag.appendChild(me.document.createElement('br'))
  8541. }
  8542. }
  8543. } else {
  8544. frag.appendChild(me.document.createTextNode(utils.html(node.data.replace(/&nbsp;/g, ' '))));
  8545. }
  8546. if (!node.nextSibling() && frag.lastChild.nodeName == 'BR') {
  8547. frag.removeChild(frag.lastChild)
  8548. }
  8549. });
  8550. rng.insertNode(frag).select();
  8551. }
  8552. return true;
  8553. }
  8554. });
  8555. //方向键的处理
  8556. me.addListener('keydown', function (cmd, evt) {
  8557. var me = this, keyCode = evt.keyCode || evt.which;
  8558. if (keyCode == 40) {
  8559. var rng = me.selection.getRange(), pre, start = rng.startContainer;
  8560. if (rng.collapsed && (pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)) && !pre.nextSibling) {
  8561. var last = pre.lastChild
  8562. while (last && last.nodeName == 'BR') {
  8563. last = last.previousSibling;
  8564. }
  8565. if (last === start || rng.startContainer === pre && rng.startOffset == pre.childNodes.length) {
  8566. me.execCommand('insertparagraph');
  8567. domUtils.preventDefault(evt)
  8568. }
  8569. }
  8570. }
  8571. });
  8572. //trace:3395
  8573. me.addListener('delkeydown', function (type, evt) {
  8574. var rng = this.selection.getRange();
  8575. rng.txtToElmBoundary(true);
  8576. var start = rng.startContainer;
  8577. if (domUtils.isTagNode(start, 'pre') && rng.collapsed && domUtils.isStartInblock(rng)) {
  8578. var p = me.document.createElement('p');
  8579. domUtils.fillNode(me.document, p);
  8580. start.parentNode.insertBefore(p, start);
  8581. domUtils.remove(start);
  8582. rng.setStart(p, 0).setCursor(false, true);
  8583. domUtils.preventDefault(evt);
  8584. return true;
  8585. }
  8586. })
  8587. };
  8588. ///import core
  8589. ///commands 清空文档
  8590. ///commandsName ClearDoc
  8591. ///commandsTitle 清空文档
  8592. /**
  8593. *
  8594. * 清空文档
  8595. * @function
  8596. * @name baidu.editor.execCommand
  8597. * @param {String} cmdName cleardoc清空文档
  8598. */
  8599. UE.commands['cleardoc'] = {
  8600. execCommand: function (cmdName) {
  8601. var me = this,
  8602. enterTag = me.options.enterTag,
  8603. range = me.selection.getRange();
  8604. if (enterTag == "br") {
  8605. me.body.innerHTML = "<br/>";
  8606. range.setStart(me.body, 0).setCursor();
  8607. } else {
  8608. me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
  8609. range.setStart(me.body.firstChild, 0).setCursor(false, true);
  8610. }
  8611. setTimeout(function () {
  8612. me.fireEvent("clearDoc");
  8613. }, 0);
  8614. }
  8615. };
  8616. ///import core
  8617. ///commands 锚点
  8618. ///commandsName Anchor
  8619. ///commandsTitle 锚点
  8620. ///commandsDialog dialogs\anchor
  8621. /**
  8622. * 锚点
  8623. * @function
  8624. * @name baidu.editor.execCommands
  8625. * @param {String} cmdName cmdName="anchor"插入锚点
  8626. */
  8627. UE.plugins['anchor'] = function () {
  8628. var me = this;
  8629. me.ready(function () {
  8630. utils.cssRule('anchor',
  8631. '.anchorclass{background: url(\''
  8632. + me.options.UEDITOR_HOME_URL +
  8633. 'themes/default/images/anchor.gif\') no-repeat scroll left center transparent;border: 1px dotted #0000FF;cursor: auto;display: inline-block;height: 16px;width: 15px;}',
  8634. me.document)
  8635. });
  8636. me.addOutputRule(function (root) {
  8637. utils.each(root.getNodesByTagName('img'), function (a) {
  8638. var val;
  8639. if (val = a.getAttr('anchorname')) {
  8640. a.tagName = 'a';
  8641. a.setAttr({
  8642. anchorname: '',
  8643. name: val,
  8644. 'class': ''
  8645. })
  8646. }
  8647. })
  8648. });
  8649. me.addInputRule(function (root) {
  8650. utils.each(root.getNodesByTagName('a'), function (a) {
  8651. var val;
  8652. if ((val = a.getAttr('name')) && !a.getAttr('href')) {
  8653. a.tagName = 'img';
  8654. a.setAttr({
  8655. anchorname: a.getAttr('name'),
  8656. 'class': 'anchorclass'
  8657. });
  8658. a.setAttr('name')
  8659. }
  8660. })
  8661. });
  8662. me.commands['anchor'] = {
  8663. execCommand: function (cmd, name) {
  8664. var range = this.selection.getRange(), img = range.getClosedNode();
  8665. if (img && img.getAttribute('anchorname')) {
  8666. if (name) {
  8667. img.setAttribute('anchorname', name);
  8668. } else {
  8669. range.setStartBefore(img).setCursor();
  8670. domUtils.remove(img);
  8671. }
  8672. } else {
  8673. if (name) {
  8674. //只在选区的开始插入
  8675. var anchor = this.document.createElement('img');
  8676. range.collapse(true);
  8677. domUtils.setAttributes(anchor, {
  8678. 'anchorname': name,
  8679. 'class': 'anchorclass'
  8680. });
  8681. range.insertNode(anchor).setStartAfter(anchor).setCursor(false, true);
  8682. }
  8683. }
  8684. }
  8685. };
  8686. };
  8687. ///import core
  8688. ///commands 字数统计
  8689. ///commandsName WordCount,wordCount
  8690. ///commandsTitle 字数统计
  8691. /**
  8692. * Created by JetBrains WebStorm.
  8693. * User: taoqili
  8694. * Date: 11-9-7
  8695. * Time: 下午8:18
  8696. * To change this template use File | Settings | File Templates.
  8697. */
  8698. UE.plugins['wordcount'] = function () {
  8699. var me = this;
  8700. me.addListener('contentchange', function () {
  8701. me.fireEvent('wordcount');
  8702. });
  8703. var timer;
  8704. me.addListener('ready', function () {
  8705. var me = this;
  8706. domUtils.on(me.body, "keyup", function (evt) {
  8707. var code = evt.keyCode || evt.which,
  8708. //忽略的按键,ctr,alt,shift,方向键
  8709. ignores = {"16": 1, "18": 1, "20": 1, "37": 1, "38": 1, "39": 1, "40": 1};
  8710. if (code in ignores) return;
  8711. clearTimeout(timer);
  8712. timer = setTimeout(function () {
  8713. me.fireEvent('wordcount');
  8714. }, 200)
  8715. })
  8716. });
  8717. };
  8718. ///import core
  8719. ///commands 添加分页功能
  8720. ///commandsName PageBreak
  8721. ///commandsTitle 分页
  8722. /**
  8723. * @description 添加分页功能
  8724. * @author zhanyi
  8725. */
  8726. UE.plugins['pagebreak'] = function () {
  8727. var me = this,
  8728. notBreakTags = ['td'];
  8729. me.setOpt('pageBreakTag', '_ueditor_page_break_tag_');
  8730. function fillNode(node) {
  8731. if (domUtils.isEmptyBlock(node)) {
  8732. var firstChild = node.firstChild, tmpNode;
  8733. while (firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)) {
  8734. tmpNode = firstChild;
  8735. firstChild = firstChild.firstChild;
  8736. }
  8737. !tmpNode && (tmpNode = node);
  8738. domUtils.fillNode(me.document, tmpNode);
  8739. }
  8740. }
  8741. //分页符样式添加
  8742. me.ready(function () {
  8743. utils.cssRule('pagebreak', '.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}', me.document);
  8744. });
  8745. function isHr(node) {
  8746. return node && node.nodeType == 1 && node.tagName == 'HR' && node.className == 'pagebreak';
  8747. }
  8748. me.addInputRule(function (root) {
  8749. root.traversal(function (node) {
  8750. if (node.type == 'text' && node.data == me.options.pageBreakTag) {
  8751. var hr = UE.uNode.createElement('<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">');
  8752. node.parentNode.insertBefore(hr, node);
  8753. node.parentNode.removeChild(node)
  8754. }
  8755. })
  8756. });
  8757. me.addOutputRule(function (node) {
  8758. utils.each(node.getNodesByTagName('hr'), function (n) {
  8759. if (n.getAttr('class') == 'pagebreak') {
  8760. var txt = UE.uNode.createText(me.options.pageBreakTag);
  8761. n.parentNode.insertBefore(txt, n);
  8762. n.parentNode.removeChild(n);
  8763. }
  8764. })
  8765. });
  8766. me.commands['pagebreak'] = {
  8767. execCommand: function () {
  8768. var range = me.selection.getRange(), hr = me.document.createElement('hr');
  8769. domUtils.setAttributes(hr, {
  8770. 'class': 'pagebreak',
  8771. noshade: "noshade",
  8772. size: "5"
  8773. });
  8774. domUtils.unSelectable(hr);
  8775. //table单独处理
  8776. var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true),
  8777. parents = [], pN;
  8778. if (node) {
  8779. switch (node.tagName) {
  8780. case 'TD':
  8781. pN = node.parentNode;
  8782. if (!pN.previousSibling) {
  8783. var table = domUtils.findParentByTagName(pN, 'table');
  8784. // var tableWrapDiv = table.parentNode;
  8785. // if(tableWrapDiv && tableWrapDiv.nodeType == 1
  8786. // && tableWrapDiv.tagName == 'DIV'
  8787. // && tableWrapDiv.getAttribute('dropdrag')
  8788. // ){
  8789. // domUtils.remove(tableWrapDiv,true);
  8790. // }
  8791. table.parentNode.insertBefore(hr, table);
  8792. parents = domUtils.findParents(hr, true);
  8793. } else {
  8794. pN.parentNode.insertBefore(hr, pN);
  8795. parents = domUtils.findParents(hr);
  8796. }
  8797. pN = parents[1];
  8798. if (hr !== pN) {
  8799. domUtils.breakParent(hr, pN);
  8800. }
  8801. //table要重写绑定一下拖拽
  8802. me.fireEvent('afteradjusttable', me.document);
  8803. }
  8804. } else {
  8805. if (!range.collapsed) {
  8806. range.deleteContents();
  8807. var start = range.startContainer;
  8808. while (!domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils.isEmptyNode(start)) {
  8809. range.setStartBefore(start).collapse(true);
  8810. domUtils.remove(start);
  8811. start = range.startContainer;
  8812. }
  8813. }
  8814. range.insertNode(hr);
  8815. var pN = hr.parentNode, nextNode;
  8816. while (!domUtils.isBody(pN)) {
  8817. domUtils.breakParent(hr, pN);
  8818. nextNode = hr.nextSibling;
  8819. if (nextNode && domUtils.isEmptyBlock(nextNode)) {
  8820. domUtils.remove(nextNode);
  8821. }
  8822. pN = hr.parentNode;
  8823. }
  8824. nextNode = hr.nextSibling;
  8825. var pre = hr.previousSibling;
  8826. if (isHr(pre)) {
  8827. domUtils.remove(pre);
  8828. } else {
  8829. pre && fillNode(pre);
  8830. }
  8831. if (!nextNode) {
  8832. var p = me.document.createElement('p');
  8833. hr.parentNode.appendChild(p);
  8834. domUtils.fillNode(me.document, p);
  8835. range.setStart(p, 0).collapse(true);
  8836. } else {
  8837. if (isHr(nextNode)) {
  8838. domUtils.remove(nextNode);
  8839. } else {
  8840. fillNode(nextNode);
  8841. }
  8842. range.setEndAfter(hr).collapse(false);
  8843. }
  8844. range.select(true);
  8845. }
  8846. }
  8847. };
  8848. };
  8849. ///import core
  8850. ///commands 本地图片引导上传
  8851. ///commandsName WordImage
  8852. ///commandsTitle 本地图片引导上传
  8853. ///commandsDialog dialogs\wordimage
  8854. UE.plugins["wordimage"] = function () {
  8855. var me = this,
  8856. images;
  8857. me.addInputRule(function (root) {
  8858. utils.each(root.getNodesByTagName('img'), function (img) {
  8859. var attrs = img.attrs,
  8860. flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
  8861. opt = me.options,
  8862. src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
  8863. if (attrs['_src'] && attrs['_src'].indexOf("file:///") !== -1) {
  8864. img.setAttr({
  8865. width: attrs.width,
  8866. height: attrs.height,
  8867. alt: attrs.alt,
  8868. word_img: attrs._src,
  8869. src: src,
  8870. _src: src,
  8871. 'style': 'background:url(' + ( flag ? opt.themePath + opt.theme + '/images/word.gif' : opt.langPath + opt.lang + '/images/localimage.png') + ') no-repeat center center;border:1px solid #ddd'
  8872. })
  8873. }
  8874. })
  8875. });
  8876. me.commands['wordimage'] = {
  8877. execCommand: function () {
  8878. images = domUtils.getElementsByTagName(me.document.body, "img");
  8879. var urlList = [];
  8880. for (var i = 0, ci; ci = images[i++];) {
  8881. var url = ci.getAttribute("word_img");
  8882. url && urlList.push(url);
  8883. }
  8884. if (images.length) {
  8885. this["word_img"] = urlList;
  8886. }
  8887. },
  8888. queryCommandState: function () {
  8889. images = domUtils.getElementsByTagName(me.document.body, "img");
  8890. for (var i = 0, ci; ci = images[i++];) {
  8891. if (ci.getAttribute("word_img")) {
  8892. return 1;
  8893. }
  8894. }
  8895. return -1;
  8896. }
  8897. };
  8898. };
  8899. UE.plugins['dragdrop'] = function () {
  8900. var me = this;
  8901. me.ready(function () {
  8902. domUtils.on(this.body, 'dragend', function () {
  8903. var rng = me.selection.getRange();
  8904. var node = rng.getClosedNode() || me.selection.getStart();
  8905. if (node && node.tagName == 'IMG') {
  8906. var pre = node.previousSibling, next;
  8907. while (next = node.nextSibling) {
  8908. if (next.nodeType == 1 && next.tagName == 'SPAN' && !next.firstChild) {
  8909. domUtils.remove(next)
  8910. } else {
  8911. break;
  8912. }
  8913. }
  8914. if ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre) || !pre) && (!next || next && !domUtils.isEmptyBlock(next))) {
  8915. if (pre && pre.tagName == 'P' && !domUtils.isEmptyBlock(pre)) {
  8916. pre.appendChild(node);
  8917. domUtils.moveChild(next, pre);
  8918. domUtils.remove(next);
  8919. } else if (next && next.tagName == 'P' && !domUtils.isEmptyBlock(next)) {
  8920. next.insertBefore(node, next.firstChild);
  8921. }
  8922. if (pre && pre.tagName == 'P' && domUtils.isEmptyBlock(pre)) {
  8923. domUtils.remove(pre)
  8924. }
  8925. if (next && next.tagName == 'P' && domUtils.isEmptyBlock(next)) {
  8926. domUtils.remove(next)
  8927. }
  8928. rng.selectNode(node).select();
  8929. me.fireEvent('saveScene');
  8930. }
  8931. }
  8932. })
  8933. });
  8934. me.addListener('keyup', function (type, evt) {
  8935. var keyCode = evt.keyCode || evt.which;
  8936. if (keyCode == 13) {
  8937. var rng = me.selection.getRange(), node;
  8938. if (node = domUtils.findParentByTagName(rng.startContainer, 'p', true)) {
  8939. if (domUtils.getComputedStyle(node, 'text-align') == 'center') {
  8940. domUtils.removeStyle(node, 'text-align')
  8941. }
  8942. }
  8943. }
  8944. })
  8945. };
  8946. ///import core
  8947. ///commands 撤销和重做
  8948. ///commandsName Undo,Redo
  8949. ///commandsTitle 撤销,重做
  8950. /**
  8951. * @description 回退
  8952. * @author zhanyi
  8953. */
  8954. UE.plugins['undo'] = function () {
  8955. var saveSceneTimer;
  8956. var me = this,
  8957. maxUndoCount = me.options.maxUndoCount || 20,
  8958. maxInputCount = me.options.maxInputCount || 20,
  8959. fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi');// ie会产生多余的</hr>
  8960. var noNeedFillCharTags = {
  8961. ol: 1, ul: 1, table: 1, tbody: 1, tr: 1, body: 1
  8962. };
  8963. var orgState = me.options.autoClearEmptyNode;
  8964. function compareAddr(indexA, indexB) {
  8965. if (indexA.length != indexB.length)
  8966. return 0;
  8967. for (var i = 0, l = indexA.length; i < l; i++) {
  8968. if (indexA[i] != indexB[i])
  8969. return 0
  8970. }
  8971. return 1;
  8972. }
  8973. function compareRangeAddress(rngAddrA, rngAddrB) {
  8974. if (rngAddrA.collapsed != rngAddrB.collapsed) {
  8975. return 0;
  8976. }
  8977. if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) {
  8978. return 0;
  8979. }
  8980. return 1;
  8981. }
  8982. function UndoManager() {
  8983. this.list = [];
  8984. this.index = 0;
  8985. this.hasUndo = false;
  8986. this.hasRedo = false;
  8987. this.undo = function () {
  8988. if (this.hasUndo) {
  8989. if (!this.list[this.index - 1] && this.list.length == 1) {
  8990. this.reset();
  8991. return;
  8992. }
  8993. while (this.list[this.index].content == this.list[this.index - 1].content) {
  8994. this.index--;
  8995. if (this.index == 0) {
  8996. return this.restore(0);
  8997. }
  8998. }
  8999. this.restore(--this.index);
  9000. }
  9001. };
  9002. this.redo = function () {
  9003. if (this.hasRedo) {
  9004. while (this.list[this.index].content == this.list[this.index + 1].content) {
  9005. this.index++;
  9006. if (this.index == this.list.length - 1) {
  9007. return this.restore(this.index);
  9008. }
  9009. }
  9010. this.restore(++this.index);
  9011. }
  9012. };
  9013. this.restore = function () {
  9014. var me = this.editor;
  9015. var scene = this.list[this.index];
  9016. var root = UE.htmlparser(scene.content.replace(fillchar, ''));
  9017. me.options.autoClearEmptyNode = false;
  9018. me.filterInputRule(root);
  9019. me.options.autoClearEmptyNode = orgState;
  9020. //trace:873
  9021. //去掉展位符
  9022. me.document.body.innerHTML = root.toHtml();
  9023. me.fireEvent('afterscencerestore');
  9024. //处理undo后空格不展位的问题
  9025. if (browser.ie) {
  9026. utils.each(domUtils.getElementsByTagName(me.document, 'td th caption p'), function (node) {
  9027. if (domUtils.isEmptyNode(node)) {
  9028. domUtils.fillNode(me.document, node);
  9029. }
  9030. })
  9031. }
  9032. try {
  9033. var rng = new dom.Range(me.document).moveToAddress(scene.address);
  9034. rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]);
  9035. } catch (e) {
  9036. }
  9037. this.update();
  9038. this.clearKey();
  9039. //不能把自己reset了
  9040. me.fireEvent('reset', true);
  9041. };
  9042. this.getScene = function () {
  9043. var me = this.editor;
  9044. var rng = me.selection.getRange(),
  9045. rngAddress = rng.createAddress(false, true);
  9046. me.fireEvent('beforegetscene');
  9047. var root = UE.htmlparser(me.body.innerHTML);
  9048. me.options.autoClearEmptyNode = false;
  9049. me.filterOutputRule(root);
  9050. me.options.autoClearEmptyNode = orgState;
  9051. var cont = root.toHtml();
  9052. //trace:3461
  9053. //这个会引起回退时导致空格丢失的情况
  9054. // browser.ie && (cont = cont.replace(/>&nbsp;</g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
  9055. me.fireEvent('aftergetscene');
  9056. return {
  9057. address: rngAddress,
  9058. content: cont
  9059. }
  9060. };
  9061. this.save = function (notCompareRange, notSetCursor) {
  9062. clearTimeout(saveSceneTimer);
  9063. var currentScene = this.getScene(notSetCursor),
  9064. lastScene = this.list[this.index];
  9065. //内容相同位置相同不存
  9066. if (lastScene && lastScene.content == currentScene.content &&
  9067. ( notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address) )
  9068. ) {
  9069. return;
  9070. }
  9071. this.list = this.list.slice(0, this.index + 1);
  9072. this.list.push(currentScene);
  9073. //如果大于最大数量了,就把最前的剔除
  9074. if (this.list.length > maxUndoCount) {
  9075. this.list.shift();
  9076. }
  9077. this.index = this.list.length - 1;
  9078. this.clearKey();
  9079. //跟新undo/redo状态
  9080. this.update();
  9081. };
  9082. this.update = function () {
  9083. this.hasRedo = !!this.list[this.index + 1];
  9084. this.hasUndo = !!this.list[this.index - 1];
  9085. };
  9086. this.reset = function () {
  9087. this.list = [];
  9088. this.index = 0;
  9089. this.hasUndo = false;
  9090. this.hasRedo = false;
  9091. this.clearKey();
  9092. };
  9093. this.clearKey = function () {
  9094. keycont = 0;
  9095. lastKeyCode = null;
  9096. };
  9097. }
  9098. me.undoManger = new UndoManager();
  9099. me.undoManger.editor = me;
  9100. function saveScene() {
  9101. this.undoManger.save();
  9102. }
  9103. me.addListener('saveScene', function () {
  9104. var args = Array.prototype.splice.call(arguments, 1);
  9105. this.undoManger.save.apply(this.undoManger, args);
  9106. });
  9107. me.addListener('beforeexeccommand', saveScene);
  9108. me.addListener('afterexeccommand', saveScene);
  9109. me.addListener('reset', function (type, exclude) {
  9110. if (!exclude) {
  9111. this.undoManger.reset();
  9112. }
  9113. });
  9114. me.commands['redo'] = me.commands['undo'] = {
  9115. execCommand: function (cmdName) {
  9116. this.undoManger[cmdName]();
  9117. },
  9118. queryCommandState: function (cmdName) {
  9119. return this.undoManger['has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')] ? 0 : -1;
  9120. },
  9121. notNeedUndo: 1
  9122. };
  9123. var keys = {
  9124. // /*Backspace*/ 8:1, /*Delete*/ 46:1,
  9125. /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1,
  9126. 37: 1, 38: 1, 39: 1, 40: 1
  9127. },
  9128. keycont = 0,
  9129. lastKeyCode;
  9130. //输入法状态下不计算字符数
  9131. var inputType = false;
  9132. me.addListener('ready', function () {
  9133. domUtils.on(this.body, 'compositionstart', function () {
  9134. inputType = true;
  9135. });
  9136. domUtils.on(this.body, 'compositionend', function () {
  9137. inputType = false;
  9138. })
  9139. });
  9140. //快捷键
  9141. me.addshortcutkey({
  9142. "Undo": "ctrl+90", //undo
  9143. "Redo": "ctrl+89" //redo
  9144. });
  9145. var isCollapsed = true;
  9146. me.addListener('keydown', function (type, evt) {
  9147. var me = this;
  9148. var keyCode = evt.keyCode || evt.which;
  9149. if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  9150. if (inputType)
  9151. return;
  9152. if (!me.selection.getRange().collapsed) {
  9153. me.undoManger.save(false, true);
  9154. isCollapsed = false;
  9155. return;
  9156. }
  9157. if (me.undoManger.list.length == 0) {
  9158. me.undoManger.save(true);
  9159. }
  9160. clearTimeout(saveSceneTimer);
  9161. function save(cont) {
  9162. if (cont.selection.getRange().collapsed)
  9163. cont.fireEvent('contentchange');
  9164. cont.undoManger.save(false, true);
  9165. cont.fireEvent('selectionchange');
  9166. }
  9167. saveSceneTimer = setTimeout(function () {
  9168. if (inputType) {
  9169. var interalTimer = setInterval(function () {
  9170. if (!inputType) {
  9171. save(me);
  9172. clearInterval(interalTimer)
  9173. }
  9174. }, 300)
  9175. return;
  9176. }
  9177. save(me);
  9178. }, 200);
  9179. lastKeyCode = keyCode;
  9180. keycont++;
  9181. if (keycont >= maxInputCount) {
  9182. save(me)
  9183. }
  9184. }
  9185. });
  9186. me.addListener('keyup', function (type, evt) {
  9187. var keyCode = evt.keyCode || evt.which;
  9188. if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  9189. if (inputType)
  9190. return;
  9191. if (!isCollapsed) {
  9192. this.undoManger.save(false, true);
  9193. isCollapsed = true;
  9194. }
  9195. }
  9196. });
  9197. };
  9198. ///import core
  9199. ///import plugins/inserthtml.js
  9200. ///import plugins/undo.js
  9201. ///import plugins/serialize.js
  9202. ///commands 粘贴
  9203. ///commandsName PastePlain
  9204. ///commandsTitle 纯文本粘贴模式
  9205. /*
  9206. ** @description 粘贴
  9207. * @author zhanyi
  9208. */
  9209. UE.plugins['paste'] = function () {
  9210. function getClipboardData(callback) {
  9211. var doc = this.document;
  9212. if (doc.getElementById('baidu_pastebin')) {
  9213. return;
  9214. }
  9215. var range = this.selection.getRange(),
  9216. bk = range.createBookmark(),
  9217. //创建剪贴的容器div
  9218. pastebin = doc.createElement('div');
  9219. pastebin.id = 'baidu_pastebin';
  9220. // Safari 要求div必须有内容,才能粘贴内容进来
  9221. browser.webkit && pastebin.appendChild(doc.createTextNode(domUtils.fillChar + domUtils.fillChar));
  9222. doc.body.appendChild(pastebin);
  9223. //trace:717 隐藏的span不能得到top
  9224. //bk.start.innerHTML = '&nbsp;';
  9225. bk.start.style.display = '';
  9226. pastebin.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
  9227. //要在现在光标平行的位置加入,否则会出现跳动的问题
  9228. domUtils.getXY(bk.start).y + 'px';
  9229. range.selectNodeContents(pastebin).select(true);
  9230. setTimeout(function () {
  9231. if (browser.webkit) {
  9232. for (var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin'), pi; pi = pastebins[i++];) {
  9233. if (domUtils.isEmptyNode(pi)) {
  9234. domUtils.remove(pi);
  9235. } else {
  9236. pastebin = pi;
  9237. break;
  9238. }
  9239. }
  9240. }
  9241. try {
  9242. pastebin.parentNode.removeChild(pastebin);
  9243. } catch (e) {
  9244. }
  9245. range.moveToBookmark(bk).select(true);
  9246. callback(pastebin);
  9247. }, 0);
  9248. }
  9249. var me = this;
  9250. var txtContent, htmlContent, address;
  9251. function filter(div) {
  9252. var html;
  9253. if (div.firstChild) {
  9254. //去掉cut中添加的边界值
  9255. var nodes = domUtils.getElementsByTagName(div, 'span');
  9256. for (var i = 0, ni; ni = nodes[i++];) {
  9257. if (ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
  9258. domUtils.remove(ni);
  9259. }
  9260. }
  9261. if (browser.webkit) {
  9262. var brs = div.querySelectorAll('div br');
  9263. for (var i = 0, bi; bi = brs[i++];) {
  9264. var pN = bi.parentNode;
  9265. if (pN.tagName == 'DIV' && pN.childNodes.length == 1) {
  9266. pN.innerHTML = '<p><br/></p>';
  9267. domUtils.remove(pN);
  9268. }
  9269. }
  9270. var divs = div.querySelectorAll('#baidu_pastebin');
  9271. for (var i = 0, di; di = divs[i++];) {
  9272. var tmpP = me.document.createElement('p');
  9273. di.parentNode.insertBefore(tmpP, di);
  9274. while (di.firstChild) {
  9275. tmpP.appendChild(di.firstChild);
  9276. }
  9277. domUtils.remove(di);
  9278. }
  9279. var metas = div.querySelectorAll('meta');
  9280. for (var i = 0, ci; ci = metas[i++];) {
  9281. domUtils.remove(ci);
  9282. }
  9283. var brs = div.querySelectorAll('br');
  9284. for (i = 0; ci = brs[i++];) {
  9285. if (/^apple-/i.test(ci.className)) {
  9286. domUtils.remove(ci);
  9287. }
  9288. }
  9289. }
  9290. if (browser.gecko) {
  9291. var dirtyNodes = div.querySelectorAll('[_moz_dirty]');
  9292. for (i = 0; ci = dirtyNodes[i++];) {
  9293. ci.removeAttribute('_moz_dirty');
  9294. }
  9295. }
  9296. if (!browser.ie) {
  9297. var spans = div.querySelectorAll('span.Apple-style-span');
  9298. for (var i = 0, ci; ci = spans[i++];) {
  9299. domUtils.remove(ci, true);
  9300. }
  9301. }
  9302. //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
  9303. html = div.innerHTML;//.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
  9304. //过滤word粘贴过来的冗余属性
  9305. html = UE.filterWord(html);
  9306. //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
  9307. var root = UE.htmlparser(html);
  9308. //如果给了过滤规则就先进行过滤
  9309. if (me.options.filterRules) {
  9310. UE.filterNode(root, me.options.filterRules);
  9311. }
  9312. //执行默认的处理
  9313. me.filterInputRule(root);
  9314. //针对chrome的处理
  9315. if (browser.webkit) {
  9316. var br = root.lastChild();
  9317. if (br && br.type == 'element' && br.tagName == 'br') {
  9318. root.removeChild(br)
  9319. }
  9320. utils.each(me.body.querySelectorAll('div'), function (node) {
  9321. if (domUtils.isEmptyBlock(node)) {
  9322. domUtils.remove(node)
  9323. }
  9324. })
  9325. }
  9326. html = {'html': root.toHtml()};
  9327. me.fireEvent('beforepaste', html, root);
  9328. //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
  9329. if (!html.html) {
  9330. return;
  9331. }
  9332. root = UE.htmlparser(html.html, true);
  9333. //如果开启了纯文本模式
  9334. if (me.queryCommandState('pasteplain') === 1) {
  9335. me.execCommand('insertHtml', UE.filterNode(root, me.options.filterTxtRules).toHtml(), true);
  9336. } else {
  9337. //文本模式
  9338. UE.filterNode(root, me.options.filterTxtRules);
  9339. txtContent = root.toHtml();
  9340. //完全模式
  9341. htmlContent = html.html;
  9342. address = me.selection.getRange().createAddress(true);
  9343. me.execCommand('insertHtml', htmlContent, true);
  9344. }
  9345. me.fireEvent("afterpaste", html);
  9346. }
  9347. }
  9348. me.addListener('pasteTransfer', function (cmd, plainType) {
  9349. if (address && txtContent && htmlContent && txtContent != htmlContent) {
  9350. var range = me.selection.getRange();
  9351. range.moveToAddress(address, true);
  9352. if (!range.collapsed) {
  9353. while (!domUtils.isBody(range.startContainer)
  9354. ) {
  9355. var start = range.startContainer;
  9356. if (start.nodeType == 1) {
  9357. start = start.childNodes[range.startOffset];
  9358. if (!start) {
  9359. range.setStartBefore(range.startContainer);
  9360. continue;
  9361. }
  9362. var pre = start.previousSibling;
  9363. if (pre && pre.nodeType == 3 && new RegExp('^[\n\r\t ' + domUtils.fillChar + ']*$').test(pre.nodeValue)) {
  9364. range.setStartBefore(pre)
  9365. }
  9366. }
  9367. if (range.startOffset == 0) {
  9368. range.setStartBefore(range.startContainer);
  9369. } else {
  9370. break;
  9371. }
  9372. }
  9373. while (!domUtils.isBody(range.endContainer)
  9374. ) {
  9375. var end = range.endContainer;
  9376. if (end.nodeType == 1) {
  9377. end = end.childNodes[range.endOffset];
  9378. if (!end) {
  9379. range.setEndAfter(range.endContainer);
  9380. continue;
  9381. }
  9382. var next = end.nextSibling;
  9383. if (next && next.nodeType == 3 && new RegExp('^[\n\r\t' + domUtils.fillChar + ']*$').test(next.nodeValue)) {
  9384. range.setEndAfter(next)
  9385. }
  9386. }
  9387. if (range.endOffset == range.endContainer[range.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length) {
  9388. range.setEndAfter(range.endContainer);
  9389. } else {
  9390. break;
  9391. }
  9392. }
  9393. }
  9394. range.deleteContents();
  9395. range.select(true);
  9396. me.__hasEnterExecCommand = true;
  9397. var html = htmlContent;
  9398. if (plainType === 2) {
  9399. html = html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function (a, b, tagName, attrs) {
  9400. tagName = tagName.toLowerCase();
  9401. if ({img: 1}[tagName]) {
  9402. return a;
  9403. }
  9404. attrs = attrs.replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi, function (str, atr, val) {
  9405. if ({
  9406. 'src': 1,
  9407. 'href': 1,
  9408. 'name': 1
  9409. }[atr.toLowerCase()]) {
  9410. return atr + '=' + val + ' '
  9411. }
  9412. return ''
  9413. });
  9414. if ({
  9415. 'span': 1,
  9416. 'div': 1
  9417. }[tagName]) {
  9418. return ''
  9419. } else {
  9420. return '<' + b + tagName + ' ' + utils.trim(attrs) + '>'
  9421. }
  9422. });
  9423. } else if (plainType) {
  9424. html = txtContent;
  9425. }
  9426. me.execCommand('inserthtml', html, true);
  9427. me.__hasEnterExecCommand = false;
  9428. var rng = me.selection.getRange();
  9429. while (!domUtils.isBody(rng.startContainer) && !rng.startOffset &&
  9430. rng.startContainer[rng.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  9431. ) {
  9432. rng.setStartBefore(rng.startContainer);
  9433. }
  9434. var tmpAddress = rng.createAddress(true);
  9435. address.endAddress = tmpAddress.startAddress;
  9436. }
  9437. });
  9438. me.addListener('ready', function () {
  9439. domUtils.on(me.body, 'cut', function () {
  9440. var range = me.selection.getRange();
  9441. if (!range.collapsed && me.undoManger) {
  9442. me.undoManger.save();
  9443. }
  9444. });
  9445. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  9446. domUtils.on(me.body, browser.ie || browser.opera ? 'keydown' : 'paste', function (e) {
  9447. if ((browser.ie || browser.opera) && ((!e.ctrlKey && !e.metaKey) || e.keyCode != '86')) {
  9448. return;
  9449. }
  9450. getClipboardData.call(me, function (div) {
  9451. filter(div);
  9452. });
  9453. });
  9454. });
  9455. };
  9456. ///import core
  9457. ///commands 有序列表,无序列表
  9458. ///commandsName InsertOrderedList,InsertUnorderedList
  9459. ///commandsTitle 有序列表,无序列表
  9460. /**
  9461. * 有序列表
  9462. * @function
  9463. * @name baidu.editor.execCommand
  9464. * @param {String} cmdName insertorderlist插入有序列表
  9465. * @param {String} style 值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman
  9466. * @author zhanyi
  9467. */
  9468. /**
  9469. * 无序链接
  9470. * @function
  9471. * @name baidu.editor.execCommand
  9472. * @param {String} cmdName insertunorderlist插入无序列表
  9473. * * @param {String} style 值为:circle,disc,square
  9474. * @author zhanyi
  9475. */
  9476. UE.plugins['list'] = function () {
  9477. var me = this,
  9478. notExchange = {
  9479. 'TD': 1,
  9480. 'PRE': 1,
  9481. 'BLOCKQUOTE': 1
  9482. };
  9483. var customStyle = {
  9484. 'cn': 'cn-1-',
  9485. 'cn1': 'cn-2-',
  9486. 'cn2': 'cn-3-',
  9487. 'num': 'num-1-',
  9488. 'num1': 'num-2-',
  9489. 'num2': 'num-3-',
  9490. 'dash': 'dash',
  9491. 'dot': 'dot'
  9492. };
  9493. me.setOpt({
  9494. 'insertorderedlist': {
  9495. 'num': '',
  9496. 'num1': '',
  9497. 'num2': '',
  9498. 'cn': '',
  9499. 'cn1': '',
  9500. 'cn2': '',
  9501. 'decimal': '',
  9502. 'lower-alpha': '',
  9503. 'lower-roman': '',
  9504. 'upper-alpha': '',
  9505. 'upper-roman': ''
  9506. },
  9507. 'insertunorderedlist': {
  9508. 'circle': '',
  9509. 'disc': '',
  9510. 'square': '',
  9511. 'dash': '',
  9512. 'dot': ''
  9513. },
  9514. listDefaultPaddingLeft: '30',
  9515. listiconpath: 'http://bs.baidu.com/listicon/',
  9516. maxListLevel: -1//-1不限制
  9517. });
  9518. function listToArray(list) {
  9519. var arr = [];
  9520. for (var p in list) {
  9521. arr.push(p)
  9522. }
  9523. return arr;
  9524. }
  9525. var listStyle = {
  9526. 'OL': listToArray(me.options.insertorderedlist),
  9527. 'UL': listToArray(me.options.insertunorderedlist)
  9528. };
  9529. var liiconpath = me.options.listiconpath;
  9530. //根据用户配置,调整customStyle
  9531. for (var s in customStyle) {
  9532. if (!me.options.insertorderedlist.hasOwnProperty(s) && !me.options.insertunorderedlist.hasOwnProperty(s)) {
  9533. delete customStyle[s];
  9534. }
  9535. }
  9536. me.ready(function () {
  9537. var customCss = [];
  9538. for (var p in customStyle) {
  9539. if (p == 'dash' || p == 'dot') {
  9540. customCss.push('li.list-' + customStyle[p] + '{background-image:url(' + liiconpath + customStyle[p] + '.gif)}');
  9541. customCss.push('ul.custom_' + p + '{list-style:none;}ul.custom_' + p + ' li{background-position:0 3px;background-repeat:no-repeat}');
  9542. } else {
  9543. for (var i = 0; i < 99; i++) {
  9544. customCss.push('li.list-' + customStyle[p] + i + '{background-image:url(' + liiconpath + 'list-' + customStyle[p] + i + '.gif)}')
  9545. }
  9546. customCss.push('ol.custom_' + p + '{list-style:none;}ol.custom_' + p + ' li{background-position:0 3px;background-repeat:no-repeat}');
  9547. }
  9548. switch (p) {
  9549. case 'cn':
  9550. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}');
  9551. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}');
  9552. customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}');
  9553. break;
  9554. case 'cn1':
  9555. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:30px}');
  9556. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}');
  9557. customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}');
  9558. break;
  9559. case 'cn2':
  9560. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:40px}');
  9561. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:55px}');
  9562. customCss.push('li.list-' + p + '-paddingleft-3{padding-left:68px}');
  9563. break;
  9564. case 'num':
  9565. case 'num1':
  9566. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}');
  9567. break;
  9568. case 'num2':
  9569. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:35px}');
  9570. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}');
  9571. break;
  9572. case 'dash':
  9573. customCss.push('li.list-' + p + '-paddingleft{padding-left:35px}');
  9574. break;
  9575. case 'dot':
  9576. customCss.push('li.list-' + p + '-paddingleft{padding-left:20px}');
  9577. }
  9578. }
  9579. customCss.push('.list-paddingleft-1{padding-left:0}');
  9580. customCss.push('.list-paddingleft-2{padding-left:' + me.options.listDefaultPaddingLeft + 'px}');
  9581. customCss.push('.list-paddingleft-3{padding-left:' + me.options.listDefaultPaddingLeft * 2 + 'px}');
  9582. //如果不给宽度会在自定应样式里出现滚动条
  9583. utils.cssRule('list', 'ol,ul{margin:0;pading:0;' + (browser.ie ? '' : 'width:95%') + '}li{clear:both;}' + customCss.join('\n'), me.document);
  9584. });
  9585. //单独处理剪切的问题
  9586. me.ready(function () {
  9587. domUtils.on(me.body, 'cut', function () {
  9588. setTimeout(function () {
  9589. var rng = me.selection.getRange(), li;
  9590. //trace:3416
  9591. if (!rng.collapsed) {
  9592. if (li = domUtils.findParentByTagName(rng.startContainer, 'li', true)) {
  9593. if (!li.nextSibling && domUtils.isEmptyBlock(li)) {
  9594. var pn = li.parentNode, node;
  9595. if (node = pn.previousSibling) {
  9596. domUtils.remove(pn);
  9597. rng.setStartAtLast(node).collapse(true);
  9598. rng.select(true);
  9599. } else if (node = pn.nextSibling) {
  9600. domUtils.remove(pn);
  9601. rng.setStartAtFirst(node).collapse(true);
  9602. rng.select(true);
  9603. } else {
  9604. var tmpNode = me.document.createElement('p');
  9605. domUtils.fillNode(me.document, tmpNode);
  9606. pn.parentNode.insertBefore(tmpNode, pn);
  9607. domUtils.remove(pn);
  9608. rng.setStart(tmpNode, 0).collapse(true);
  9609. rng.select(true);
  9610. }
  9611. }
  9612. }
  9613. }
  9614. })
  9615. })
  9616. });
  9617. function getStyle(node) {
  9618. var cls = node.className;
  9619. if (domUtils.hasClass(node, /custom_/)) {
  9620. return cls.match(/custom_(\w+)/)[1]
  9621. }
  9622. return domUtils.getStyle(node, 'list-style-type')
  9623. }
  9624. me.addListener('beforepaste', function (type, html) {
  9625. var me = this,
  9626. rng = me.selection.getRange(), li;
  9627. var root = UE.htmlparser(html.html, true);
  9628. if (li = domUtils.findParentByTagName(rng.startContainer, 'li', true)) {
  9629. var list = li.parentNode, tagName = list.tagName == 'OL' ? 'ul' : 'ol';
  9630. utils.each(root.getNodesByTagName(tagName), function (n) {
  9631. n.tagName = list.tagName;
  9632. n.setAttr();
  9633. if (n.parentNode === root) {
  9634. type = getStyle(list) || (list.tagName == 'OL' ? 'decimal' : 'disc')
  9635. } else {
  9636. var className = n.parentNode.getAttr('class');
  9637. if (className && /custom_/.test(className)) {
  9638. type = className.match(/custom_(\w+)/)[1]
  9639. } else {
  9640. type = n.parentNode.getStyle('list-style-type');
  9641. }
  9642. if (!type) {
  9643. type = list.tagName == 'OL' ? 'decimal' : 'disc';
  9644. }
  9645. }
  9646. var index = utils.indexOf(listStyle[list.tagName], type);
  9647. if (n.parentNode !== root)
  9648. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  9649. var currentStyle = listStyle[list.tagName][index];
  9650. if (customStyle[currentStyle]) {
  9651. n.setAttr('class', 'custom_' + currentStyle)
  9652. } else {
  9653. n.setStyle('list-style-type', currentStyle)
  9654. }
  9655. })
  9656. }
  9657. html.html = root.toHtml();
  9658. });
  9659. //进入编辑器的li要套p标签
  9660. me.addInputRule(function (root) {
  9661. utils.each(root.getNodesByTagName('li'), function (li) {
  9662. var tmpP = UE.uNode.createElement('p');
  9663. for (var i = 0, ci; ci = li.children[i];) {
  9664. if (ci.type == 'text' || dtd.p[ci.tagName]) {
  9665. tmpP.appendChild(ci);
  9666. } else {
  9667. if (tmpP.firstChild()) {
  9668. li.insertBefore(tmpP, ci);
  9669. tmpP = UE.uNode.createElement('p');
  9670. i = i + 2;
  9671. } else {
  9672. i++;
  9673. }
  9674. }
  9675. }
  9676. if (tmpP.firstChild() && !tmpP.parentNode || !li.firstChild()) {
  9677. li.appendChild(tmpP);
  9678. }
  9679. //trace:3357
  9680. //p不能为空
  9681. if (!tmpP.firstChild()) {
  9682. tmpP.innerHTML(browser.ie ? '&nbsp;' : '<br/>')
  9683. }
  9684. //去掉末尾的空白
  9685. var p = li.firstChild();
  9686. var lastChild = p.lastChild();
  9687. if (lastChild && lastChild.type == 'text' && /^\s*$/.test(lastChild.data)) {
  9688. p.removeChild(lastChild)
  9689. }
  9690. });
  9691. var orderlisttype = {
  9692. 'num1': /^\d+\)/,
  9693. 'decimal': /^\d+\./,
  9694. 'lower-alpha': /^[a-z]+\)/,
  9695. 'upper-alpha': /^[A-Z]+\./,
  9696. 'cn': /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
  9697. 'cn2': /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
  9698. },
  9699. unorderlisttype = {
  9700. 'square': 'n'
  9701. };
  9702. function checkListType(content, container) {
  9703. var span = container.firstChild();
  9704. if (span && span.type == 'element' && span.tagName == 'span' && /Wingdings|Symbol/.test(span.getStyle('font-family'))) {
  9705. for (var p in unorderlisttype) {
  9706. if (unorderlisttype[p] == span.data) {
  9707. return p
  9708. }
  9709. }
  9710. return 'disc'
  9711. }
  9712. for (var p in orderlisttype) {
  9713. if (orderlisttype[p].test(content)) {
  9714. return p;
  9715. }
  9716. }
  9717. }
  9718. utils.each(root.getNodesByTagName('p'), function (node) {
  9719. if (node.getAttr('class') != 'MsoListParagraph') {
  9720. return
  9721. }
  9722. //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
  9723. node.setStyle('margin', '');
  9724. node.setStyle('margin-left', '');
  9725. node.setAttr('class', '');
  9726. function appendLi(list, p, type) {
  9727. if (list.tagName == 'ol') {
  9728. if (browser.ie) {
  9729. var first = p.firstChild();
  9730. if (first.type == 'element' && first.tagName == 'span' && orderlisttype[type].test(first.innerText())) {
  9731. p.removeChild(first);
  9732. }
  9733. } else {
  9734. p.innerHTML(p.innerHTML().replace(orderlisttype[type], ''));
  9735. }
  9736. } else {
  9737. p.removeChild(p.firstChild())
  9738. }
  9739. var li = UE.uNode.createElement('li');
  9740. li.appendChild(p);
  9741. list.appendChild(li);
  9742. }
  9743. var tmp = node, type, cacheNode = node;
  9744. if (node.parentNode.tagName != 'li' && (type = checkListType(node.innerText(), node))) {
  9745. var list = UE.uNode.createElement(me.options.insertorderedlist.hasOwnProperty(type) ? 'ol' : 'ul');
  9746. if (customStyle[type]) {
  9747. list.setAttr('class', 'custom_' + type)
  9748. } else {
  9749. list.setStyle('list-style-type', type)
  9750. }
  9751. while (node && node.parentNode.tagName != 'li' && checkListType(node.innerText(), node)) {
  9752. tmp = node.nextSibling();
  9753. if (!tmp) {
  9754. node.parentNode.insertBefore(list, node)
  9755. }
  9756. appendLi(list, node, type);
  9757. node = tmp;
  9758. }
  9759. if (!list.parentNode && node && node.parentNode) {
  9760. node.parentNode.insertBefore(list, node)
  9761. }
  9762. }
  9763. var span = cacheNode.firstChild();
  9764. if (span && span.type == 'element' && span.tagName == 'span' && /^\s*(&nbsp;)+\s*$/.test(span.innerText())) {
  9765. span.parentNode.removeChild(span)
  9766. }
  9767. })
  9768. });
  9769. //调整索引标签
  9770. me.addListener('contentchange', function () {
  9771. adjustListStyle(me.document)
  9772. });
  9773. function adjustListStyle(doc, ignore) {
  9774. utils.each(domUtils.getElementsByTagName(doc, 'ol ul'), function (node) {
  9775. if (!domUtils.inDoc(node, doc))
  9776. return;
  9777. var parent = node.parentNode;
  9778. if (parent.tagName == node.tagName) {
  9779. var nodeStyleType = getStyle(node) || (node.tagName == 'OL' ? 'decimal' : 'disc'),
  9780. parentStyleType = getStyle(parent) || (parent.tagName == 'OL' ? 'decimal' : 'disc');
  9781. if (nodeStyleType == parentStyleType) {
  9782. var styleIndex = utils.indexOf(listStyle[node.tagName], nodeStyleType);
  9783. styleIndex = styleIndex + 1 == listStyle[node.tagName].length ? 0 : styleIndex + 1;
  9784. setListStyle(node, listStyle[node.tagName][styleIndex])
  9785. }
  9786. }
  9787. var index = 0, type = 2;
  9788. if (domUtils.hasClass(node, /custom_/)) {
  9789. if (!(/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent, /custom_/))) {
  9790. type = 1;
  9791. }
  9792. } else {
  9793. if (/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent, /custom_/)) {
  9794. type = 3;
  9795. }
  9796. }
  9797. var style = domUtils.getStyle(node, 'list-style-type');
  9798. style && (node.style.cssText = 'list-style-type:' + style);
  9799. node.className = utils.trim(node.className.replace(/list-paddingleft-\w+/, '')) + ' list-paddingleft-' + type;
  9800. utils.each(domUtils.getElementsByTagName(node, 'li'), function (li) {
  9801. li.style.cssText && (li.style.cssText = '');
  9802. if (!li.firstChild) {
  9803. domUtils.remove(li);
  9804. return;
  9805. }
  9806. if (li.parentNode !== node) {
  9807. return;
  9808. }
  9809. index++;
  9810. if (domUtils.hasClass(node, /custom_/)) {
  9811. var paddingLeft = 1, currentStyle = getStyle(node);
  9812. if (node.tagName == 'OL') {
  9813. if (currentStyle) {
  9814. switch (currentStyle) {
  9815. case 'cn' :
  9816. case 'cn1':
  9817. case 'cn2':
  9818. if (index > 10 && (index % 10 == 0 || index > 10 && index < 20)) {
  9819. paddingLeft = 2
  9820. } else if (index > 20) {
  9821. paddingLeft = 3
  9822. }
  9823. break;
  9824. case 'num2' :
  9825. if (index > 9) {
  9826. paddingLeft = 2
  9827. }
  9828. }
  9829. }
  9830. li.className = 'list-' + customStyle[currentStyle] + index + ' ' + 'list-' + currentStyle + '-paddingleft-' + paddingLeft;
  9831. } else {
  9832. li.className = 'list-' + customStyle[currentStyle] + ' ' + 'list-' + currentStyle + '-paddingleft';
  9833. }
  9834. } else {
  9835. li.className = li.className.replace(/list-[\w\-]+/gi, '');
  9836. }
  9837. var className = li.getAttribute('class');
  9838. if (className !== null && !className.replace(/\s/g, '')) {
  9839. domUtils.removeAttributes(li, 'class')
  9840. }
  9841. });
  9842. !ignore && adjustList(node, node.tagName.toLowerCase(), getStyle(node) || domUtils.getStyle(node, 'list-style-type'), true);
  9843. })
  9844. }
  9845. function adjustList(list, tag, style, ignoreEmpty) {
  9846. var nextList = list.nextSibling;
  9847. if (nextList && nextList.nodeType == 1 && nextList.tagName.toLowerCase() == tag && (getStyle(nextList) || domUtils.getStyle(nextList, 'list-style-type') || (tag == 'ol' ? 'decimal' : 'disc')) == style) {
  9848. domUtils.moveChild(nextList, list);
  9849. if (nextList.childNodes.length == 0) {
  9850. domUtils.remove(nextList);
  9851. }
  9852. }
  9853. if (nextList && domUtils.isFillChar(nextList)) {
  9854. domUtils.remove(nextList);
  9855. }
  9856. var preList = list.previousSibling;
  9857. if (preList && preList.nodeType == 1 && preList.tagName.toLowerCase() == tag && (getStyle(preList) || domUtils.getStyle(preList, 'list-style-type') || (tag == 'ol' ? 'decimal' : 'disc')) == style) {
  9858. domUtils.moveChild(list, preList);
  9859. }
  9860. if (preList && domUtils.isFillChar(preList)) {
  9861. domUtils.remove(preList);
  9862. }
  9863. !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
  9864. if (getStyle(list)) {
  9865. adjustListStyle(list.ownerDocument, true)
  9866. }
  9867. }
  9868. function setListStyle(list, style) {
  9869. if (customStyle[style]) {
  9870. list.className = 'custom_' + style;
  9871. }
  9872. try {
  9873. domUtils.setStyle(list, 'list-style-type', style);
  9874. } catch (e) {
  9875. }
  9876. }
  9877. function clearEmptySibling(node) {
  9878. var tmpNode = node.previousSibling;
  9879. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  9880. domUtils.remove(tmpNode);
  9881. }
  9882. tmpNode = node.nextSibling;
  9883. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  9884. domUtils.remove(tmpNode);
  9885. }
  9886. }
  9887. me.addListener('keydown', function (type, evt) {
  9888. function preventAndSave() {
  9889. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  9890. me.fireEvent('contentchange');
  9891. me.undoManger && me.undoManger.save();
  9892. }
  9893. function findList(node, filterFn) {
  9894. while (node && !domUtils.isBody(node)) {
  9895. if (filterFn(node)) {
  9896. return null
  9897. }
  9898. if (node.nodeType == 1 && /[ou]l/i.test(node.tagName)) {
  9899. return node;
  9900. }
  9901. node = node.parentNode;
  9902. }
  9903. return null;
  9904. }
  9905. var keyCode = evt.keyCode || evt.which;
  9906. if (keyCode == 13 && !evt.shiftKey) {//回车
  9907. var rng = me.selection.getRange(),
  9908. parent = domUtils.findParent(rng.startContainer, function (node) {
  9909. return domUtils.isBlockElm(node)
  9910. }, true),
  9911. li = domUtils.findParentByTagName(rng.startContainer, 'li', true);
  9912. if (parent && parent.tagName != 'PRE' && !li) {
  9913. var html = parent.innerHTML.replace(new RegExp(domUtils.fillChar, 'g'), '');
  9914. if (/^\s*1\s*\.[^\d]/.test(html)) {
  9915. parent.innerHTML = html.replace(/^\s*1\s*\./, '');
  9916. rng.setStartAtLast(parent).collapse(true).select();
  9917. me.__hasEnterExecCommand = true;
  9918. me.execCommand('insertorderedlist');
  9919. me.__hasEnterExecCommand = false;
  9920. }
  9921. }
  9922. var range = me.selection.getRange(),
  9923. start = findList(range.startContainer, function (node) {
  9924. return node.tagName == 'TABLE';
  9925. }),
  9926. end = range.collapsed ? start : findList(range.endContainer, function (node) {
  9927. return node.tagName == 'TABLE';
  9928. });
  9929. if (start && end && start === end) {
  9930. if (!range.collapsed) {
  9931. start = domUtils.findParentByTagName(range.startContainer, 'li', true);
  9932. end = domUtils.findParentByTagName(range.endContainer, 'li', true);
  9933. if (start && end && start === end) {
  9934. range.deleteContents();
  9935. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  9936. if (li && domUtils.isEmptyBlock(li)) {
  9937. pre = li.previousSibling;
  9938. next = li.nextSibling;
  9939. p = me.document.createElement('p');
  9940. domUtils.fillNode(me.document, p);
  9941. parentList = li.parentNode;
  9942. if (pre && next) {
  9943. range.setStart(next, 0).collapse(true).select(true);
  9944. domUtils.remove(li);
  9945. } else {
  9946. if (!pre && !next || !pre) {
  9947. parentList.parentNode.insertBefore(p, parentList);
  9948. } else {
  9949. li.parentNode.parentNode.insertBefore(p, parentList.nextSibling);
  9950. }
  9951. domUtils.remove(li);
  9952. if (!parentList.firstChild) {
  9953. domUtils.remove(parentList);
  9954. }
  9955. range.setStart(p, 0).setCursor();
  9956. }
  9957. preventAndSave();
  9958. return;
  9959. }
  9960. } else {
  9961. var tmpRange = range.cloneRange(),
  9962. bk = tmpRange.collapse(false).createBookmark();
  9963. range.deleteContents();
  9964. tmpRange.moveToBookmark(bk);
  9965. var li = domUtils.findParentByTagName(tmpRange.startContainer, 'li', true);
  9966. clearEmptySibling(li);
  9967. tmpRange.select();
  9968. preventAndSave();
  9969. return;
  9970. }
  9971. }
  9972. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  9973. if (li) {
  9974. if (domUtils.isEmptyBlock(li)) {
  9975. bk = range.createBookmark();
  9976. var parentList = li.parentNode;
  9977. if (li !== parentList.lastChild) {
  9978. domUtils.breakParent(li, parentList);
  9979. clearEmptySibling(li);
  9980. } else {
  9981. parentList.parentNode.insertBefore(li, parentList.nextSibling);
  9982. if (domUtils.isEmptyNode(parentList)) {
  9983. domUtils.remove(parentList);
  9984. }
  9985. }
  9986. //嵌套不处理
  9987. if (!dtd.$list[li.parentNode.tagName]) {
  9988. if (!domUtils.isBlockElm(li.firstChild)) {
  9989. p = me.document.createElement('p');
  9990. li.parentNode.insertBefore(p, li);
  9991. while (li.firstChild) {
  9992. p.appendChild(li.firstChild);
  9993. }
  9994. domUtils.remove(li);
  9995. } else {
  9996. domUtils.remove(li, true);
  9997. }
  9998. }
  9999. range.moveToBookmark(bk).select();
  10000. } else {
  10001. var first = li.firstChild;
  10002. if (!first || !domUtils.isBlockElm(first)) {
  10003. var p = me.document.createElement('p');
  10004. !li.firstChild && domUtils.fillNode(me.document, p);
  10005. while (li.firstChild) {
  10006. p.appendChild(li.firstChild);
  10007. }
  10008. li.appendChild(p);
  10009. first = p;
  10010. }
  10011. var span = me.document.createElement('span');
  10012. range.insertNode(span);
  10013. domUtils.breakParent(span, li);
  10014. var nextLi = span.nextSibling;
  10015. first = nextLi.firstChild;
  10016. if (!first) {
  10017. p = me.document.createElement('p');
  10018. domUtils.fillNode(me.document, p);
  10019. nextLi.appendChild(p);
  10020. first = p;
  10021. }
  10022. if (domUtils.isEmptyNode(first)) {
  10023. first.innerHTML = '';
  10024. domUtils.fillNode(me.document, first);
  10025. }
  10026. range.setStart(first, 0).collapse(true).shrinkBoundary().select();
  10027. domUtils.remove(span);
  10028. var pre = nextLi.previousSibling;
  10029. if (pre && domUtils.isEmptyBlock(pre)) {
  10030. pre.innerHTML = '<p></p>';
  10031. domUtils.fillNode(me.document, pre.firstChild);
  10032. }
  10033. }
  10034. // }
  10035. preventAndSave();
  10036. }
  10037. }
  10038. }
  10039. if (keyCode == 8) {
  10040. //修中ie中li下的问题
  10041. range = me.selection.getRange();
  10042. if (range.collapsed && domUtils.isStartInblock(range)) {
  10043. tmpRange = range.cloneRange().trimBoundary();
  10044. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  10045. //要在li的最左边,才能处理
  10046. if (li && domUtils.isStartInblock(tmpRange)) {
  10047. start = domUtils.findParentByTagName(range.startContainer, 'p', true);
  10048. if (start && start !== li.firstChild) {
  10049. var parentList = domUtils.findParentByTagName(start, ['ol', 'ul']);
  10050. domUtils.breakParent(start, parentList);
  10051. clearEmptySibling(start);
  10052. me.fireEvent('contentchange');
  10053. range.setStart(start, 0).setCursor(false, true);
  10054. me.fireEvent('saveScene');
  10055. domUtils.preventDefault(evt);
  10056. return;
  10057. }
  10058. if (li && (pre = li.previousSibling)) {
  10059. if (keyCode == 46 && li.childNodes.length) {
  10060. return;
  10061. }
  10062. //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
  10063. if (dtd.$list[pre.tagName]) {
  10064. pre = pre.lastChild;
  10065. }
  10066. me.undoManger && me.undoManger.save();
  10067. first = li.firstChild;
  10068. if (domUtils.isBlockElm(first)) {
  10069. if (domUtils.isEmptyNode(first)) {
  10070. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  10071. pre.appendChild(first);
  10072. range.setStart(first, 0).setCursor(false, true);
  10073. //first不是唯一的节点
  10074. while (li.firstChild) {
  10075. pre.appendChild(li.firstChild);
  10076. }
  10077. } else {
  10078. span = me.document.createElement('span');
  10079. range.insertNode(span);
  10080. //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
  10081. if (domUtils.isEmptyBlock(pre)) {
  10082. pre.innerHTML = '';
  10083. }
  10084. domUtils.moveChild(li, pre);
  10085. range.setStartBefore(span).collapse(true).select(true);
  10086. domUtils.remove(span);
  10087. }
  10088. } else {
  10089. if (domUtils.isEmptyNode(li)) {
  10090. var p = me.document.createElement('p');
  10091. pre.appendChild(p);
  10092. range.setStart(p, 0).setCursor();
  10093. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  10094. } else {
  10095. range.setEnd(pre, pre.childNodes.length).collapse().select(true);
  10096. while (li.firstChild) {
  10097. pre.appendChild(li.firstChild);
  10098. }
  10099. }
  10100. }
  10101. domUtils.remove(li);
  10102. me.fireEvent('contentchange');
  10103. me.fireEvent('saveScene');
  10104. domUtils.preventDefault(evt);
  10105. return;
  10106. }
  10107. //trace:980
  10108. if (li && !li.previousSibling) {
  10109. var parentList = li.parentNode;
  10110. var bk = range.createBookmark();
  10111. if (domUtils.isTagNode(parentList.parentNode, 'ol ul')) {
  10112. parentList.parentNode.insertBefore(li, parentList);
  10113. if (domUtils.isEmptyNode(parentList)) {
  10114. domUtils.remove(parentList)
  10115. }
  10116. } else {
  10117. while (li.firstChild) {
  10118. parentList.parentNode.insertBefore(li.firstChild, parentList);
  10119. }
  10120. domUtils.remove(li);
  10121. if (domUtils.isEmptyNode(parentList)) {
  10122. domUtils.remove(parentList)
  10123. }
  10124. }
  10125. range.moveToBookmark(bk).setCursor(false, true);
  10126. me.fireEvent('contentchange');
  10127. me.fireEvent('saveScene');
  10128. domUtils.preventDefault(evt);
  10129. return;
  10130. }
  10131. }
  10132. }
  10133. }
  10134. });
  10135. me.addListener('keyup', function (type, evt) {
  10136. var keyCode = evt.keyCode || evt.which;
  10137. if (keyCode == 8) {
  10138. var rng = me.selection.getRange(), list;
  10139. if (list = domUtils.findParentByTagName(rng.startContainer, ['ol', 'ul'], true)) {
  10140. adjustList(list, list.tagName.toLowerCase(), getStyle(list) || domUtils.getComputedStyle(list, 'list-style-type'), true)
  10141. }
  10142. }
  10143. });
  10144. //处理tab键
  10145. me.addListener('tabkeydown', function () {
  10146. var range = me.selection.getRange();
  10147. //控制级数
  10148. function checkLevel(li) {
  10149. if (me.options.maxListLevel != -1) {
  10150. var level = li.parentNode, levelNum = 0;
  10151. while (/[ou]l/i.test(level.tagName)) {
  10152. levelNum++;
  10153. level = level.parentNode;
  10154. }
  10155. if (levelNum >= me.options.maxListLevel) {
  10156. return true;
  10157. }
  10158. }
  10159. }
  10160. //只以开始为准
  10161. //todo 后续改进
  10162. var li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  10163. if (li) {
  10164. var bk;
  10165. if (range.collapsed) {
  10166. if (checkLevel(li))
  10167. return true;
  10168. var parentLi = li.parentNode,
  10169. list = me.document.createElement(parentLi.tagName),
  10170. index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils.getComputedStyle(parentLi, 'list-style-type'));
  10171. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  10172. var currentStyle = listStyle[list.tagName][index];
  10173. setListStyle(list, currentStyle);
  10174. if (domUtils.isStartInblock(range)) {
  10175. me.fireEvent('saveScene');
  10176. bk = range.createBookmark();
  10177. parentLi.insertBefore(list, li);
  10178. list.appendChild(li);
  10179. adjustList(list, list.tagName.toLowerCase(), currentStyle);
  10180. me.fireEvent('contentchange');
  10181. range.moveToBookmark(bk).select(true);
  10182. return true;
  10183. }
  10184. } else {
  10185. me.fireEvent('saveScene');
  10186. bk = range.createBookmark();
  10187. for (var i = 0, closeList, parents = domUtils.findParents(li), ci; ci = parents[i++];) {
  10188. if (domUtils.isTagNode(ci, 'ol ul')) {
  10189. closeList = ci;
  10190. break;
  10191. }
  10192. }
  10193. var current = li;
  10194. if (bk.end) {
  10195. while (current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)) {
  10196. if (checkLevel(current)) {
  10197. current = domUtils.getNextDomNode(current, false, null, function (node) {
  10198. return node !== closeList
  10199. });
  10200. continue;
  10201. }
  10202. var parentLi = current.parentNode,
  10203. list = me.document.createElement(parentLi.tagName),
  10204. index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils.getComputedStyle(parentLi, 'list-style-type'));
  10205. var currentIndex = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  10206. var currentStyle = listStyle[list.tagName][currentIndex];
  10207. setListStyle(list, currentStyle);
  10208. parentLi.insertBefore(list, current);
  10209. while (current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)) {
  10210. li = current.nextSibling;
  10211. list.appendChild(current);
  10212. if (!li || domUtils.isTagNode(li, 'ol ul')) {
  10213. if (li) {
  10214. while (li = li.firstChild) {
  10215. if (li.tagName == 'LI') {
  10216. break;
  10217. }
  10218. }
  10219. } else {
  10220. li = domUtils.getNextDomNode(current, false, null, function (node) {
  10221. return node !== closeList
  10222. });
  10223. }
  10224. break;
  10225. }
  10226. current = li;
  10227. }
  10228. adjustList(list, list.tagName.toLowerCase(), currentStyle);
  10229. current = li;
  10230. }
  10231. }
  10232. me.fireEvent('contentchange');
  10233. range.moveToBookmark(bk).select();
  10234. return true;
  10235. }
  10236. }
  10237. });
  10238. function getLi(start) {
  10239. while (start && !domUtils.isBody(start)) {
  10240. if (start.nodeName == 'TABLE') {
  10241. return null;
  10242. }
  10243. if (start.nodeName == 'LI') {
  10244. return start
  10245. }
  10246. start = start.parentNode;
  10247. }
  10248. }
  10249. me.commands['insertorderedlist'] =
  10250. me.commands['insertunorderedlist'] = {
  10251. execCommand: function (command, style) {
  10252. if (!style) {
  10253. style = command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc';
  10254. }
  10255. var me = this,
  10256. range = this.selection.getRange(),
  10257. filterFn = function (node) {
  10258. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node);
  10259. },
  10260. tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul',
  10261. frag = me.document.createDocumentFragment();
  10262. //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
  10263. //range.shrinkBoundary();//.adjustmentBoundary();
  10264. range.adjustmentBoundary().shrinkBoundary();
  10265. var bko = range.createBookmark(true),
  10266. start = getLi(me.document.getElementById(bko.start)),
  10267. modifyStart = 0,
  10268. end = getLi(me.document.getElementById(bko.end)),
  10269. modifyEnd = 0,
  10270. startParent, endParent,
  10271. list, tmp;
  10272. if (start || end) {
  10273. start && (startParent = start.parentNode);
  10274. if (!bko.end) {
  10275. end = start;
  10276. }
  10277. end && (endParent = end.parentNode);
  10278. if (startParent === endParent) {
  10279. while (start !== end) {
  10280. tmp = start;
  10281. start = start.nextSibling;
  10282. if (!domUtils.isBlockElm(tmp.firstChild)) {
  10283. var p = me.document.createElement('p');
  10284. while (tmp.firstChild) {
  10285. p.appendChild(tmp.firstChild);
  10286. }
  10287. tmp.appendChild(p);
  10288. }
  10289. frag.appendChild(tmp);
  10290. }
  10291. tmp = me.document.createElement('span');
  10292. startParent.insertBefore(tmp, end);
  10293. if (!domUtils.isBlockElm(end.firstChild)) {
  10294. p = me.document.createElement('p');
  10295. while (end.firstChild) {
  10296. p.appendChild(end.firstChild);
  10297. }
  10298. end.appendChild(p);
  10299. }
  10300. frag.appendChild(end);
  10301. domUtils.breakParent(tmp, startParent);
  10302. if (domUtils.isEmptyNode(tmp.previousSibling)) {
  10303. domUtils.remove(tmp.previousSibling);
  10304. }
  10305. if (domUtils.isEmptyNode(tmp.nextSibling)) {
  10306. domUtils.remove(tmp.nextSibling)
  10307. }
  10308. var nodeStyle = getStyle(startParent) || domUtils.getComputedStyle(startParent, 'list-style-type') || (command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc');
  10309. if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
  10310. for (var i = 0, ci, tmpFrag = me.document.createDocumentFragment(); ci = frag.childNodes[i++];) {
  10311. if (domUtils.isTagNode(ci, 'ol ul')) {
  10312. utils.each(domUtils.getElementsByTagName(ci, 'li'), function (li) {
  10313. while (li.firstChild) {
  10314. tmpFrag.appendChild(li.firstChild);
  10315. }
  10316. });
  10317. } else {
  10318. while (ci.firstChild) {
  10319. tmpFrag.appendChild(ci.firstChild);
  10320. }
  10321. }
  10322. }
  10323. tmp.parentNode.insertBefore(tmpFrag, tmp);
  10324. } else {
  10325. list = me.document.createElement(tag);
  10326. setListStyle(list, style);
  10327. list.appendChild(frag);
  10328. tmp.parentNode.insertBefore(list, tmp);
  10329. }
  10330. domUtils.remove(tmp);
  10331. list && adjustList(list, tag, style);
  10332. range.moveToBookmark(bko).select();
  10333. return;
  10334. }
  10335. //开始
  10336. if (start) {
  10337. while (start) {
  10338. tmp = start.nextSibling;
  10339. if (domUtils.isTagNode(start, 'ol ul')) {
  10340. frag.appendChild(start);
  10341. } else {
  10342. var tmpfrag = me.document.createDocumentFragment(),
  10343. hasBlock = 0;
  10344. while (start.firstChild) {
  10345. if (domUtils.isBlockElm(start.firstChild)) {
  10346. hasBlock = 1;
  10347. }
  10348. tmpfrag.appendChild(start.firstChild);
  10349. }
  10350. if (!hasBlock) {
  10351. var tmpP = me.document.createElement('p');
  10352. tmpP.appendChild(tmpfrag);
  10353. frag.appendChild(tmpP);
  10354. } else {
  10355. frag.appendChild(tmpfrag);
  10356. }
  10357. domUtils.remove(start);
  10358. }
  10359. start = tmp;
  10360. }
  10361. startParent.parentNode.insertBefore(frag, startParent.nextSibling);
  10362. if (domUtils.isEmptyNode(startParent)) {
  10363. range.setStartBefore(startParent);
  10364. domUtils.remove(startParent);
  10365. } else {
  10366. range.setStartAfter(startParent);
  10367. }
  10368. modifyStart = 1;
  10369. }
  10370. if (end && domUtils.inDoc(endParent, me.document)) {
  10371. //结束
  10372. start = endParent.firstChild;
  10373. while (start && start !== end) {
  10374. tmp = start.nextSibling;
  10375. if (domUtils.isTagNode(start, 'ol ul')) {
  10376. frag.appendChild(start);
  10377. } else {
  10378. tmpfrag = me.document.createDocumentFragment();
  10379. hasBlock = 0;
  10380. while (start.firstChild) {
  10381. if (domUtils.isBlockElm(start.firstChild)) {
  10382. hasBlock = 1;
  10383. }
  10384. tmpfrag.appendChild(start.firstChild);
  10385. }
  10386. if (!hasBlock) {
  10387. tmpP = me.document.createElement('p');
  10388. tmpP.appendChild(tmpfrag);
  10389. frag.appendChild(tmpP);
  10390. } else {
  10391. frag.appendChild(tmpfrag);
  10392. }
  10393. domUtils.remove(start);
  10394. }
  10395. start = tmp;
  10396. }
  10397. var tmpDiv = domUtils.createElement(me.document, 'div', {
  10398. 'tmpDiv': 1
  10399. });
  10400. domUtils.moveChild(end, tmpDiv);
  10401. frag.appendChild(tmpDiv);
  10402. domUtils.remove(end);
  10403. endParent.parentNode.insertBefore(frag, endParent);
  10404. range.setEndBefore(endParent);
  10405. if (domUtils.isEmptyNode(endParent)) {
  10406. domUtils.remove(endParent);
  10407. }
  10408. modifyEnd = 1;
  10409. }
  10410. }
  10411. if (!modifyStart) {
  10412. range.setStartBefore(me.document.getElementById(bko.start));
  10413. }
  10414. if (bko.end && !modifyEnd) {
  10415. range.setEndAfter(me.document.getElementById(bko.end));
  10416. }
  10417. range.enlarge(true, function (node) {
  10418. return notExchange[node.tagName];
  10419. });
  10420. frag = me.document.createDocumentFragment();
  10421. var bk = range.createBookmark(),
  10422. current = domUtils.getNextDomNode(bk.start, false, filterFn),
  10423. tmpRange = range.cloneRange(),
  10424. tmpNode,
  10425. block = domUtils.isBlockElm;
  10426. while (current && current !== bk.end && (domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING)) {
  10427. if (current.nodeType == 3 || dtd.li[current.tagName]) {
  10428. if (current.nodeType == 1 && dtd.$list[current.tagName]) {
  10429. while (current.firstChild) {
  10430. frag.appendChild(current.firstChild);
  10431. }
  10432. tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  10433. domUtils.remove(current);
  10434. current = tmpNode;
  10435. continue;
  10436. }
  10437. tmpNode = current;
  10438. tmpRange.setStartBefore(current);
  10439. while (current && current !== bk.end && (!block(current) || domUtils.isBookmarkNode(current) )) {
  10440. tmpNode = current;
  10441. current = domUtils.getNextDomNode(current, false, null, function (node) {
  10442. return !notExchange[node.tagName];
  10443. });
  10444. }
  10445. if (current && block(current)) {
  10446. tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
  10447. if (tmp && domUtils.isBookmarkNode(tmp)) {
  10448. current = domUtils.getNextDomNode(tmp, false, filterFn);
  10449. tmpNode = tmp;
  10450. }
  10451. }
  10452. tmpRange.setEndAfter(tmpNode);
  10453. current = domUtils.getNextDomNode(tmpNode, false, filterFn);
  10454. var li = range.document.createElement('li');
  10455. li.appendChild(tmpRange.extractContents());
  10456. if (domUtils.isEmptyNode(li)) {
  10457. var tmpNode = range.document.createElement('p');
  10458. while (li.firstChild) {
  10459. tmpNode.appendChild(li.firstChild)
  10460. }
  10461. li.appendChild(tmpNode);
  10462. }
  10463. frag.appendChild(li);
  10464. } else {
  10465. current = domUtils.getNextDomNode(current, true, filterFn);
  10466. }
  10467. }
  10468. range.moveToBookmark(bk).collapse(true);
  10469. list = me.document.createElement(tag);
  10470. setListStyle(list, style);
  10471. list.appendChild(frag);
  10472. range.insertNode(list);
  10473. //当前list上下看能否合并
  10474. adjustList(list, tag, style);
  10475. //去掉冗余的tmpDiv
  10476. for (var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, 'div'); ci = tmpDivs[i++];) {
  10477. if (ci.getAttribute('tmpDiv')) {
  10478. domUtils.remove(ci, true)
  10479. }
  10480. }
  10481. range.moveToBookmark(bko).select();
  10482. },
  10483. queryCommandState: function (command) {
  10484. var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul';
  10485. var path = this.selection.getStartElementPath();
  10486. for (var i = 0, ci; ci = path[i++];) {
  10487. if (ci.nodeName == 'TABLE') {
  10488. return 0
  10489. }
  10490. if (tag == ci.nodeName.toLowerCase()) {
  10491. return 1
  10492. }
  10493. ;
  10494. }
  10495. return 0;
  10496. },
  10497. queryCommandValue: function (command) {
  10498. var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul';
  10499. var path = this.selection.getStartElementPath(),
  10500. node;
  10501. for (var i = 0, ci; ci = path[i++];) {
  10502. if (ci.nodeName == 'TABLE') {
  10503. node = null;
  10504. break;
  10505. }
  10506. if (tag == ci.nodeName.toLowerCase()) {
  10507. node = ci;
  10508. break;
  10509. }
  10510. ;
  10511. }
  10512. return node ? getStyle(node) || domUtils.getComputedStyle(node, 'list-style-type') : null;
  10513. }
  10514. };
  10515. };
  10516. ///import core
  10517. ///import plugins/serialize.js
  10518. ///import plugins/undo.js
  10519. ///commands 查看源码
  10520. ///commandsName Source
  10521. ///commandsTitle 查看源码
  10522. (function () {
  10523. var sourceEditors = {
  10524. textarea: function (editor, holder) {
  10525. var textarea = holder.ownerDocument.createElement('textarea');
  10526. textarea.style.cssText = 'position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;';
  10527. // todo: IE下只有onresize属性可用... 很纠结
  10528. if (browser.ie && browser.version < 8) {
  10529. textarea.style.width = holder.offsetWidth + 'px';
  10530. textarea.style.height = holder.offsetHeight + 'px';
  10531. holder.onresize = function () {
  10532. textarea.style.width = holder.offsetWidth + 'px';
  10533. textarea.style.height = holder.offsetHeight + 'px';
  10534. };
  10535. }
  10536. holder.appendChild(textarea);
  10537. return {
  10538. setContent: function (content) {
  10539. textarea.value = content;
  10540. },
  10541. getContent: function () {
  10542. return textarea.value;
  10543. },
  10544. select: function () {
  10545. var range;
  10546. if (browser.ie) {
  10547. range = textarea.createTextRange();
  10548. range.collapse(true);
  10549. range.select();
  10550. } else {
  10551. //todo: chrome下无法设置焦点
  10552. textarea.setSelectionRange(0, 0);
  10553. textarea.focus();
  10554. }
  10555. },
  10556. dispose: function () {
  10557. holder.removeChild(textarea);
  10558. // todo
  10559. holder.onresize = null;
  10560. textarea = null;
  10561. holder = null;
  10562. }
  10563. };
  10564. },
  10565. codemirror: function (editor, holder) {
  10566. var codeEditor = window.CodeMirror(holder, {
  10567. mode: "text/html",
  10568. tabMode: "indent",
  10569. lineNumbers: true,
  10570. lineWrapping: true
  10571. });
  10572. var dom = codeEditor.getWrapperElement();
  10573. dom.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
  10574. codeEditor.getScrollerElement().style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;';
  10575. codeEditor.refresh();
  10576. return {
  10577. getCodeMirror: function () {
  10578. return codeEditor;
  10579. },
  10580. setContent: function (content) {
  10581. codeEditor.setValue(content);
  10582. },
  10583. getContent: function () {
  10584. return codeEditor.getValue();
  10585. },
  10586. select: function () {
  10587. codeEditor.focus();
  10588. },
  10589. dispose: function () {
  10590. holder.removeChild(dom);
  10591. dom = null;
  10592. codeEditor = null;
  10593. }
  10594. };
  10595. }
  10596. };
  10597. UE.plugins['source'] = function () {
  10598. var me = this;
  10599. var opt = this.options;
  10600. var sourceMode = false;
  10601. var sourceEditor;
  10602. opt.sourceEditor = browser.ie ? 'textarea' : (opt.sourceEditor || 'codemirror');
  10603. me.setOpt({
  10604. sourceEditorFirst: false
  10605. });
  10606. function createSourceEditor(holder) {
  10607. return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder);
  10608. }
  10609. var bakCssText;
  10610. //解决在源码模式下getContent不能得到最新的内容问题
  10611. var oldGetContent = me.getContent,
  10612. bakAddress;
  10613. me.commands['source'] = {
  10614. execCommand: function () {
  10615. sourceMode = !sourceMode;
  10616. if (sourceMode) {
  10617. bakAddress = me.selection.getRange().createAddress(false, true);
  10618. me.undoManger && me.undoManger.save(true);
  10619. if (browser.gecko) {
  10620. me.body.contentEditable = false;
  10621. }
  10622. bakCssText = me.iframe.style.cssText;
  10623. me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;';
  10624. me.fireEvent('beforegetcontent');
  10625. var root = UE.htmlparser(me.body.innerHTML);
  10626. me.filterOutputRule(root);
  10627. root.traversal(function (node) {
  10628. if (node.type == 'element') {
  10629. switch (node.tagName) {
  10630. case 'td':
  10631. case 'th':
  10632. case 'caption':
  10633. if (node.children && node.children.length == 1) {
  10634. if (node.firstChild().tagName == 'br') {
  10635. node.removeChild(node.firstChild())
  10636. }
  10637. }
  10638. ;
  10639. break;
  10640. case 'pre':
  10641. node.innerText(node.innerText().replace(/&nbsp;/g, ' '))
  10642. }
  10643. }
  10644. });
  10645. me.fireEvent('aftergetcontent');
  10646. var content = root.toHtml(true);
  10647. sourceEditor = createSourceEditor(me.iframe.parentNode);
  10648. sourceEditor.setContent(content);
  10649. setTimeout(function () {
  10650. sourceEditor.select();
  10651. me.addListener('fullscreenchanged', function () {
  10652. try {
  10653. sourceEditor.getCodeMirror().refresh()
  10654. } catch (e) {
  10655. }
  10656. });
  10657. });
  10658. //重置getContent,源码模式下取值也能是最新的数据
  10659. me.getContent = function () {
  10660. return sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  10661. };
  10662. } else {
  10663. me.iframe.style.cssText = bakCssText;
  10664. var cont = sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  10665. //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
  10666. cont = cont.replace(new RegExp('[\\r\\t\\n ]*<\/?(\\w+)\\s*(?:[^>]*)>', 'g'), function (a, b) {
  10667. if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
  10668. return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, '');
  10669. }
  10670. return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, '')
  10671. });
  10672. me.setContent(cont);
  10673. sourceEditor.dispose();
  10674. sourceEditor = null;
  10675. //还原getContent方法
  10676. me.getContent = oldGetContent;
  10677. var first = me.body.firstChild;
  10678. //trace:1106 都删除空了,下边会报错,所以补充一个p占位
  10679. if (!first) {
  10680. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  10681. first = me.body.firstChild;
  10682. }
  10683. //要在ifm为显示时ff才能取到selection,否则报错
  10684. //这里不能比较位置了
  10685. me.undoManger && me.undoManger.save(true);
  10686. if (browser.gecko) {
  10687. var input = document.createElement('input');
  10688. input.style.cssText = 'position:absolute;left:0;top:-32768px';
  10689. document.body.appendChild(input);
  10690. me.body.contentEditable = false;
  10691. setTimeout(function () {
  10692. domUtils.setViewportOffset(input, { left: -32768, top: 0 });
  10693. input.focus();
  10694. setTimeout(function () {
  10695. me.body.contentEditable = true;
  10696. me.selection.getRange().moveToAddress(bakAddress).select(true);
  10697. domUtils.remove(input);
  10698. });
  10699. });
  10700. } else {
  10701. //ie下有可能报错,比如在代码顶头的情况
  10702. try {
  10703. me.selection.getRange().moveToAddress(bakAddress).select(true);
  10704. } catch (e) {
  10705. }
  10706. }
  10707. }
  10708. this.fireEvent('sourcemodechanged', sourceMode);
  10709. },
  10710. queryCommandState: function () {
  10711. return sourceMode | 0;
  10712. },
  10713. notNeedUndo: 1
  10714. };
  10715. var oldQueryCommandState = me.queryCommandState;
  10716. me.queryCommandState = function (cmdName) {
  10717. cmdName = cmdName.toLowerCase();
  10718. if (sourceMode) {
  10719. //源码模式下可以开启的命令
  10720. return cmdName in {
  10721. 'source': 1,
  10722. 'fullscreen': 1
  10723. } ? 1 : -1
  10724. }
  10725. return oldQueryCommandState.apply(this, arguments);
  10726. };
  10727. if (opt.sourceEditor == "codemirror") {
  10728. me.addListener("ready", function () {
  10729. utils.loadFile(document, {
  10730. src: opt.codeMirrorJsUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js",
  10731. tag: "script",
  10732. type: "text/javascript",
  10733. defer: "defer"
  10734. }, function () {
  10735. if (opt.sourceEditorFirst) {
  10736. setTimeout(function () {
  10737. me.execCommand("source");
  10738. }, 0);
  10739. }
  10740. });
  10741. utils.loadFile(document, {
  10742. tag: "link",
  10743. rel: "stylesheet",
  10744. type: "text/css",
  10745. href: opt.codeMirrorCssUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css"
  10746. });
  10747. });
  10748. }
  10749. };
  10750. })();
  10751. ///import core
  10752. ///import plugins/undo.js
  10753. ///commands 设置回车标签p或br
  10754. ///commandsName EnterKey
  10755. ///commandsTitle 设置回车标签p或br
  10756. /**
  10757. * @description 处理回车
  10758. * @author zhanyi
  10759. */
  10760. UE.plugins['enterkey'] = function () {
  10761. var hTag,
  10762. me = this,
  10763. tag = me.options.enterTag;
  10764. me.addListener('keyup', function (type, evt) {
  10765. var keyCode = evt.keyCode || evt.which;
  10766. if (keyCode == 13) {
  10767. var range = me.selection.getRange(),
  10768. start = range.startContainer,
  10769. doSave;
  10770. //修正在h1-h6里边回车后不能嵌套p的问题
  10771. if (!browser.ie) {
  10772. if (/h\d/i.test(hTag)) {
  10773. if (browser.gecko) {
  10774. var h = domUtils.findParentByTagName(start, [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption', 'table'], true);
  10775. if (!h) {
  10776. me.document.execCommand('formatBlock', false, '<p>');
  10777. doSave = 1;
  10778. }
  10779. } else {
  10780. //chrome remove div
  10781. if (start.nodeType == 1) {
  10782. var tmp = me.document.createTextNode(''), div;
  10783. range.insertNode(tmp);
  10784. div = domUtils.findParentByTagName(tmp, 'div', true);
  10785. if (div) {
  10786. var p = me.document.createElement('p');
  10787. while (div.firstChild) {
  10788. p.appendChild(div.firstChild);
  10789. }
  10790. div.parentNode.insertBefore(p, div);
  10791. domUtils.remove(div);
  10792. range.setStartBefore(tmp).setCursor();
  10793. doSave = 1;
  10794. }
  10795. domUtils.remove(tmp);
  10796. }
  10797. }
  10798. if (me.undoManger && doSave) {
  10799. me.undoManger.save();
  10800. }
  10801. }
  10802. //没有站位符,会出现多行的问题
  10803. browser.opera && range.select();
  10804. } else {
  10805. me.fireEvent('saveScene', true, true)
  10806. }
  10807. }
  10808. });
  10809. me.addListener('keydown', function (type, evt) {
  10810. var keyCode = evt.keyCode || evt.which;
  10811. if (keyCode == 13) {//回车
  10812. if (me.fireEvent('beforeenterkeydown')) {
  10813. domUtils.preventDefault(evt);
  10814. return;
  10815. }
  10816. me.fireEvent('saveScene', true, true);
  10817. hTag = '';
  10818. var range = me.selection.getRange();
  10819. if (!range.collapsed) {
  10820. //跨td不能删
  10821. var start = range.startContainer,
  10822. end = range.endContainer,
  10823. startTd = domUtils.findParentByTagName(start, 'td', true),
  10824. endTd = domUtils.findParentByTagName(end, 'td', true);
  10825. if (startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !endTd) {
  10826. evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false);
  10827. return;
  10828. }
  10829. }
  10830. if (tag == 'p') {
  10831. if (!browser.ie) {
  10832. start = domUtils.findParentByTagName(range.startContainer, ['ol', 'ul', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption'], true);
  10833. //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
  10834. //trace:2431
  10835. if (!start && !browser.opera) {
  10836. me.document.execCommand('formatBlock', false, '<p>');
  10837. if (browser.gecko) {
  10838. range = me.selection.getRange();
  10839. start = domUtils.findParentByTagName(range.startContainer, 'p', true);
  10840. start && domUtils.removeDirtyAttr(start);
  10841. }
  10842. } else {
  10843. hTag = start.tagName;
  10844. start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start);
  10845. }
  10846. }
  10847. } else {
  10848. evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false);
  10849. if (!range.collapsed) {
  10850. range.deleteContents();
  10851. start = range.startContainer;
  10852. if (start.nodeType == 1 && (start = start.childNodes[range.startOffset])) {
  10853. while (start.nodeType == 1) {
  10854. if (dtd.$empty[start.tagName]) {
  10855. range.setStartBefore(start).setCursor();
  10856. if (me.undoManger) {
  10857. me.undoManger.save();
  10858. }
  10859. return false;
  10860. }
  10861. if (!start.firstChild) {
  10862. var br = range.document.createElement('br');
  10863. start.appendChild(br);
  10864. range.setStart(start, 0).setCursor();
  10865. if (me.undoManger) {
  10866. me.undoManger.save();
  10867. }
  10868. return false;
  10869. }
  10870. start = start.firstChild;
  10871. }
  10872. if (start === range.startContainer.childNodes[range.startOffset]) {
  10873. br = range.document.createElement('br');
  10874. range.insertNode(br).setCursor();
  10875. } else {
  10876. range.setStart(start, 0).setCursor();
  10877. }
  10878. } else {
  10879. br = range.document.createElement('br');
  10880. range.insertNode(br).setStartAfter(br).setCursor();
  10881. }
  10882. } else {
  10883. br = range.document.createElement('br');
  10884. range.insertNode(br);
  10885. var parent = br.parentNode;
  10886. if (parent.lastChild === br) {
  10887. br.parentNode.insertBefore(br.cloneNode(true), br);
  10888. range.setStartBefore(br);
  10889. } else {
  10890. range.setStartAfter(br);
  10891. }
  10892. range.setCursor();
  10893. }
  10894. }
  10895. }
  10896. });
  10897. };
  10898. /*
  10899. * 处理特殊键的兼容性问题
  10900. */
  10901. UE.plugins['keystrokes'] = function () {
  10902. var me = this;
  10903. var collapsed = true;
  10904. me.addListener('keydown', function (type, evt) {
  10905. var keyCode = evt.keyCode || evt.which,
  10906. rng = me.selection.getRange();
  10907. //处理全选的情况
  10908. if (!rng.collapsed && !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) && (keyCode >= 65 && keyCode <= 90
  10909. || keyCode >= 48 && keyCode <= 57 ||
  10910. keyCode >= 96 && keyCode <= 111 || {
  10911. 13: 1,
  10912. 8: 1,
  10913. 46: 1
  10914. }[keyCode])
  10915. ) {
  10916. var tmpNode = rng.startContainer;
  10917. if (domUtils.isFillChar(tmpNode)) {
  10918. rng.setStartBefore(tmpNode)
  10919. }
  10920. tmpNode = rng.endContainer;
  10921. if (domUtils.isFillChar(tmpNode)) {
  10922. rng.setEndAfter(tmpNode)
  10923. }
  10924. rng.txtToElmBoundary();
  10925. //结束边界可能放到了br的前边,要把br包含进来
  10926. // x[xxx]<br/>
  10927. if (rng.endContainer && rng.endContainer.nodeType == 1) {
  10928. tmpNode = rng.endContainer.childNodes[rng.endOffset];
  10929. if (tmpNode && domUtils.isBr(tmpNode)) {
  10930. rng.setEndAfter(tmpNode);
  10931. }
  10932. }
  10933. if (rng.startOffset == 0) {
  10934. tmpNode = rng.startContainer;
  10935. if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
  10936. tmpNode = rng.endContainer;
  10937. if (rng.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) {
  10938. me.fireEvent('saveScene');
  10939. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  10940. rng.setStart(me.body.firstChild, 0).setCursor(false, true);
  10941. me._selectionChange();
  10942. return;
  10943. }
  10944. }
  10945. }
  10946. }
  10947. //处理backspace
  10948. if (keyCode == 8) {
  10949. rng = me.selection.getRange();
  10950. collapsed = rng.collapsed;
  10951. if (me.fireEvent('delkeydown', evt)) {
  10952. return;
  10953. }
  10954. var start, end;
  10955. //避免按两次删除才能生效的问题
  10956. if (rng.collapsed && rng.inFillChar()) {
  10957. start = rng.startContainer;
  10958. if (domUtils.isFillChar(start)) {
  10959. rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
  10960. domUtils.remove(start)
  10961. } else {
  10962. start.nodeValue = start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '');
  10963. rng.startOffset--;
  10964. rng.collapse(true).select(true)
  10965. }
  10966. }
  10967. //解决选中control元素不能删除的问题
  10968. if (start = rng.getClosedNode()) {
  10969. me.fireEvent('saveScene');
  10970. rng.setStartBefore(start);
  10971. domUtils.remove(start);
  10972. rng.setCursor();
  10973. me.fireEvent('saveScene');
  10974. domUtils.preventDefault(evt);
  10975. return;
  10976. }
  10977. //阻止在table上的删除
  10978. if (!browser.ie) {
  10979. start = domUtils.findParentByTagName(rng.startContainer, 'table', true);
  10980. end = domUtils.findParentByTagName(rng.endContainer, 'table', true);
  10981. if (start && !end || !start && end || start !== end) {
  10982. evt.preventDefault();
  10983. return;
  10984. }
  10985. }
  10986. }
  10987. //处理tab键的逻辑
  10988. if (keyCode == 9) {
  10989. //不处理以下标签
  10990. var excludeTagNameForTabKey = {
  10991. 'ol': 1,
  10992. 'ul': 1,
  10993. 'table': 1
  10994. };
  10995. //处理组件里的tab按下事件
  10996. if (me.fireEvent('tabkeydown', evt)) {
  10997. domUtils.preventDefault(evt);
  10998. return;
  10999. }
  11000. var range = me.selection.getRange();
  11001. me.fireEvent('saveScene');
  11002. for (var i = 0, txt = '', tabSize = me.options.tabSize || 4, tabNode = me.options.tabNode || '&nbsp;'; i < tabSize; i++) {
  11003. txt += tabNode;
  11004. }
  11005. var span = me.document.createElement('span');
  11006. span.innerHTML = txt + domUtils.fillChar;
  11007. if (range.collapsed) {
  11008. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  11009. } else {
  11010. //普通的情况
  11011. start = domUtils.findParent(range.startContainer, filterFn);
  11012. end = domUtils.findParent(range.endContainer, filterFn);
  11013. if (start && end && start === end) {
  11014. range.deleteContents();
  11015. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  11016. } else {
  11017. var bookmark = range.createBookmark(),
  11018. filterFn = function (node) {
  11019. return domUtils.isBlockElm(node) && !excludeTagNameForTabKey[node.tagName.toLowerCase()]
  11020. };
  11021. range.enlarge(true);
  11022. var bookmark2 = range.createBookmark(),
  11023. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
  11024. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  11025. current.insertBefore(span.cloneNode(true).firstChild, current.firstChild);
  11026. current = domUtils.getNextDomNode(current, false, filterFn);
  11027. }
  11028. range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
  11029. }
  11030. }
  11031. domUtils.preventDefault(evt)
  11032. }
  11033. //trace:1634
  11034. //ff的del键在容器空的时候,也会删除
  11035. if (browser.gecko && keyCode == 46) {
  11036. range = me.selection.getRange();
  11037. if (range.collapsed) {
  11038. start = range.startContainer;
  11039. if (domUtils.isEmptyBlock(start)) {
  11040. var parent = start.parentNode;
  11041. while (domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)) {
  11042. start = parent;
  11043. parent = parent.parentNode;
  11044. }
  11045. if (start === parent.lastChild)
  11046. evt.preventDefault();
  11047. return;
  11048. }
  11049. }
  11050. }
  11051. });
  11052. me.addListener('keyup', function (type, evt) {
  11053. var keyCode = evt.keyCode || evt.which,
  11054. rng, me = this;
  11055. if (keyCode == 8) {
  11056. if (me.fireEvent('delkeyup')) {
  11057. return;
  11058. }
  11059. rng = me.selection.getRange();
  11060. if (rng.collapsed) {
  11061. var tmpNode,
  11062. autoClearTagName = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
  11063. if (tmpNode = domUtils.findParentByTagName(rng.startContainer, autoClearTagName, true)) {
  11064. if (domUtils.isEmptyBlock(tmpNode)) {
  11065. var pre = tmpNode.previousSibling;
  11066. if (pre && pre.nodeName != 'TABLE') {
  11067. domUtils.remove(tmpNode);
  11068. rng.setStartAtLast(pre).setCursor(false, true);
  11069. return;
  11070. } else {
  11071. var next = tmpNode.nextSibling;
  11072. if (next && next.nodeName != 'TABLE') {
  11073. domUtils.remove(tmpNode);
  11074. rng.setStartAtFirst(next).setCursor(false, true);
  11075. return;
  11076. }
  11077. }
  11078. }
  11079. }
  11080. //处理当删除到body时,要重新给p标签展位
  11081. if (domUtils.isBody(rng.startContainer)) {
  11082. var tmpNode = domUtils.createElement(me.document, 'p', {
  11083. 'innerHTML': browser.ie ? domUtils.fillChar : '<br/>'
  11084. });
  11085. rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true);
  11086. }
  11087. }
  11088. //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
  11089. if (!collapsed && (rng.startContainer.nodeType == 3 || rng.startContainer.nodeType == 1 && domUtils.isEmptyBlock(rng.startContainer))) {
  11090. if (browser.ie) {
  11091. var span = rng.document.createElement('span');
  11092. rng.insertNode(span).setStartBefore(span).collapse(true);
  11093. rng.select();
  11094. domUtils.remove(span)
  11095. } else {
  11096. rng.select()
  11097. }
  11098. }
  11099. }
  11100. })
  11101. };
  11102. ///import core
  11103. ///commands 修复chrome下图片不能点击的问题
  11104. ///commandsName FixImgClick
  11105. ///commandsTitle 修复chrome下图片不能点击的问题
  11106. //修复chrome下图片不能点击的问题
  11107. //todo 可以改大小
  11108. UE.plugins['fiximgclick'] = function () {
  11109. var me = this;
  11110. if (browser.webkit) {
  11111. me.addListener('click', function (type, e) {
  11112. if (e.target.tagName == 'IMG') {
  11113. var range = new dom.Range(me.document);
  11114. range.selectNode(e.target).select();
  11115. }
  11116. });
  11117. }
  11118. };
  11119. ///import core
  11120. ///commands 为非ie浏览器自动添加a标签
  11121. ///commandsName AutoLink
  11122. ///commandsTitle 自动增加链接
  11123. /**
  11124. * @description 为非ie浏览器自动添加a标签
  11125. * @author zhanyi
  11126. */
  11127. UE.plugins['autolink'] = function () {
  11128. var cont = 0;
  11129. if (browser.ie) {
  11130. return;
  11131. }
  11132. var me = this;
  11133. me.addListener('reset', function () {
  11134. cont = 0;
  11135. });
  11136. me.addListener('keydown', function (type, evt) {
  11137. var keyCode = evt.keyCode || evt.which;
  11138. if (keyCode == 32 || keyCode == 13) {
  11139. var sel = me.selection.getNative(),
  11140. range = sel.getRangeAt(0).cloneRange(),
  11141. offset,
  11142. charCode;
  11143. var start = range.startContainer;
  11144. while (start.nodeType == 1 && range.startOffset > 0) {
  11145. start = range.startContainer.childNodes[range.startOffset - 1];
  11146. if (!start) {
  11147. break;
  11148. }
  11149. range.setStart(start, start.nodeType == 1 ? start.childNodes.length : start.nodeValue.length);
  11150. range.collapse(true);
  11151. start = range.startContainer;
  11152. }
  11153. do {
  11154. if (range.startOffset == 0) {
  11155. start = range.startContainer.previousSibling;
  11156. while (start && start.nodeType == 1) {
  11157. start = start.lastChild;
  11158. }
  11159. if (!start || domUtils.isFillChar(start)) {
  11160. break;
  11161. }
  11162. offset = start.nodeValue.length;
  11163. } else {
  11164. start = range.startContainer;
  11165. offset = range.startOffset;
  11166. }
  11167. range.setStart(start, offset - 1);
  11168. charCode = range.toString().charCodeAt(0);
  11169. } while (charCode != 160 && charCode != 32);
  11170. if (range.toString().replace(new RegExp(domUtils.fillChar, 'g'), '').match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)) {
  11171. while (range.toString().length) {
  11172. if (/^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(range.toString())) {
  11173. break;
  11174. }
  11175. try {
  11176. range.setStart(range.startContainer, range.startOffset + 1);
  11177. } catch (e) {
  11178. //trace:2121
  11179. var start = range.startContainer;
  11180. while (!(next = start.nextSibling)) {
  11181. if (domUtils.isBody(start)) {
  11182. return;
  11183. }
  11184. start = start.parentNode;
  11185. }
  11186. range.setStart(next, 0);
  11187. }
  11188. }
  11189. //range的开始边界已经在a标签里的不再处理
  11190. if (domUtils.findParentByTagName(range.startContainer, 'a', true)) {
  11191. return;
  11192. }
  11193. var a = me.document.createElement('a'), text = me.document.createTextNode(' '), href;
  11194. me.undoManger && me.undoManger.save();
  11195. a.appendChild(range.extractContents());
  11196. a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, '');
  11197. href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar, 'g'), '');
  11198. href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://" + href;
  11199. a.setAttribute('_src', utils.html(href));
  11200. a.href = utils.html(href);
  11201. range.insertNode(a);
  11202. a.parentNode.insertBefore(text, a.nextSibling);
  11203. range.setStart(text, 0);
  11204. range.collapse(true);
  11205. sel.removeAllRanges();
  11206. sel.addRange(range);
  11207. me.undoManger && me.undoManger.save();
  11208. }
  11209. }
  11210. });
  11211. };
  11212. ///import core
  11213. ///commands 当输入内容超过编辑器高度时,编辑器自动增高
  11214. ///commandsName AutoHeight,autoHeightEnabled
  11215. ///commandsTitle 自动增高
  11216. /**
  11217. * @description 自动伸展
  11218. * @author zhanyi
  11219. */
  11220. UE.plugins['autoheight'] = function () {
  11221. var me = this;
  11222. //提供开关,就算加载也可以关闭
  11223. me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
  11224. if (!me.autoHeightEnabled) {
  11225. return;
  11226. }
  11227. var bakOverflow,
  11228. span, tmpNode,
  11229. lastHeight = 0,
  11230. options = me.options,
  11231. currentHeight,
  11232. timer;
  11233. function adjustHeight() {
  11234. var me = this;
  11235. clearTimeout(timer);
  11236. if (isFullscreen)return;
  11237. timer = setTimeout(function () {
  11238. if (!me.queryCommandState || me.queryCommandState && me.queryCommandState('source') != 1) {
  11239. if (!span) {
  11240. span = me.document.createElement('span');
  11241. //trace:1764
  11242. span.style.cssText = 'display:block;width:0;margin:0;padding:0;border:0;clear:both;';
  11243. span.innerHTML = '.';
  11244. }
  11245. tmpNode = span.cloneNode(true);
  11246. me.body.appendChild(tmpNode);
  11247. currentHeight = Math.max(domUtils.getXY(tmpNode).y + tmpNode.offsetHeight, Math.max(options.minFrameHeight, options.initialFrameHeight));
  11248. if (currentHeight != lastHeight) {
  11249. me.setHeight(currentHeight, true);
  11250. lastHeight = currentHeight;
  11251. }
  11252. domUtils.remove(tmpNode);
  11253. }
  11254. }, 50);
  11255. }
  11256. var isFullscreen;
  11257. me.addListener('fullscreenchanged', function (cmd, f) {
  11258. isFullscreen = f
  11259. });
  11260. me.addListener('destroy', function () {
  11261. me.removeListener('contentchange afterinserthtml keyup mouseup', adjustHeight)
  11262. });
  11263. me.enableAutoHeight = function () {
  11264. var me = this;
  11265. if (!me.autoHeightEnabled) {
  11266. return;
  11267. }
  11268. var doc = me.document;
  11269. me.autoHeightEnabled = true;
  11270. bakOverflow = doc.body.style.overflowY;
  11271. doc.body.style.overflowY = 'hidden';
  11272. me.addListener('contentchange afterinserthtml keyup mouseup', adjustHeight);
  11273. //ff不给事件算得不对
  11274. setTimeout(function () {
  11275. adjustHeight.call(me);
  11276. }, browser.gecko ? 100 : 0);
  11277. me.fireEvent('autoheightchanged', me.autoHeightEnabled);
  11278. };
  11279. me.disableAutoHeight = function () {
  11280. me.body.style.overflowY = bakOverflow || '';
  11281. me.removeListener('contentchange', adjustHeight);
  11282. me.removeListener('keyup', adjustHeight);
  11283. me.removeListener('mouseup', adjustHeight);
  11284. me.autoHeightEnabled = false;
  11285. me.fireEvent('autoheightchanged', me.autoHeightEnabled);
  11286. };
  11287. me.addListener('ready', function () {
  11288. me.enableAutoHeight();
  11289. //trace:1764
  11290. var timer;
  11291. domUtils.on(browser.ie ? me.body : me.document, browser.webkit ? 'dragover' : 'drop', function () {
  11292. clearTimeout(timer);
  11293. timer = setTimeout(function () {
  11294. adjustHeight.call(this);
  11295. }, 100);
  11296. });
  11297. });
  11298. };
  11299. ///import core
  11300. ///commands 悬浮工具栏
  11301. ///commandsName AutoFloat,autoFloatEnabled
  11302. ///commandsTitle 悬浮工具栏
  11303. /*
  11304. * modified by chengchao01
  11305. *
  11306. * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
  11307. */
  11308. UE.plugins['autofloat'] = function () {
  11309. var me = this,
  11310. lang = me.getLang();
  11311. me.setOpt({
  11312. topOffset: 0
  11313. });
  11314. var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
  11315. topOffset = me.options.topOffset;
  11316. //如果不固定toolbar的位置,则直接退出
  11317. if (!optsAutoFloatEnabled) {
  11318. return;
  11319. }
  11320. var uiUtils = UE.ui.uiUtils,
  11321. LteIE6 = browser.ie && browser.version <= 6,
  11322. quirks = browser.quirks;
  11323. function checkHasUI() {
  11324. if (!UE.ui) {
  11325. alert(lang.autofloatMsg);
  11326. return 0;
  11327. }
  11328. return 1;
  11329. }
  11330. function fixIE6FixedPos() {
  11331. var docStyle = document.body.style;
  11332. docStyle.backgroundImage = 'url("about:blank")';
  11333. docStyle.backgroundAttachment = 'fixed';
  11334. }
  11335. var bakCssText,
  11336. placeHolder = document.createElement('div'),
  11337. toolbarBox, orgTop,
  11338. getPosition,
  11339. flag = true; //ie7模式下需要偏移
  11340. function setFloating() {
  11341. var toobarBoxPos = domUtils.getXY(toolbarBox),
  11342. origalFloat = domUtils.getComputedStyle(toolbarBox, 'position'),
  11343. origalLeft = domUtils.getComputedStyle(toolbarBox, 'left');
  11344. toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
  11345. toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
  11346. toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
  11347. if (LteIE6 || (quirks && browser.ie)) {
  11348. if (toolbarBox.style.position != 'absolute') {
  11349. toolbarBox.style.position = 'absolute';
  11350. }
  11351. toolbarBox.style.top = (document.body.scrollTop || document.documentElement.scrollTop) - orgTop + topOffset + 'px';
  11352. } else {
  11353. if (browser.ie7Compat && flag) {
  11354. flag = false;
  11355. toolbarBox.style.left = domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left + 2 + 'px';
  11356. }
  11357. if (toolbarBox.style.position != 'fixed') {
  11358. toolbarBox.style.position = 'fixed';
  11359. toolbarBox.style.top = topOffset + "px";
  11360. ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
  11361. }
  11362. }
  11363. }
  11364. function unsetFloating() {
  11365. flag = true;
  11366. if (placeHolder.parentNode) {
  11367. placeHolder.parentNode.removeChild(placeHolder);
  11368. }
  11369. toolbarBox.style.cssText = bakCssText;
  11370. }
  11371. function updateFloating() {
  11372. var rect3 = getPosition(me.container);
  11373. var offset = me.options.toolbarTopOffset || 0;
  11374. if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
  11375. setFloating();
  11376. } else {
  11377. unsetFloating();
  11378. }
  11379. }
  11380. var defer_updateFloating = utils.defer(function () {
  11381. updateFloating();
  11382. }, browser.ie ? 200 : 100, true);
  11383. me.addListener('destroy', function () {
  11384. domUtils.un(window, ['scroll', 'resize'], updateFloating);
  11385. me.removeListener('keydown', defer_updateFloating);
  11386. });
  11387. me.addListener('ready', function () {
  11388. if (checkHasUI(me)) {
  11389. getPosition = uiUtils.getClientRect;
  11390. toolbarBox = me.ui.getDom('toolbarbox');
  11391. orgTop = getPosition(toolbarBox).top;
  11392. bakCssText = toolbarBox.style.cssText;
  11393. placeHolder.style.height = toolbarBox.offsetHeight + 'px';
  11394. if (LteIE6) {
  11395. fixIE6FixedPos();
  11396. }
  11397. domUtils.on(window, ['scroll', 'resize'], updateFloating);
  11398. me.addListener('keydown', defer_updateFloating);
  11399. me.addListener('beforefullscreenchange', function (t, enabled) {
  11400. if (enabled) {
  11401. unsetFloating();
  11402. }
  11403. });
  11404. me.addListener('fullscreenchanged', function (t, enabled) {
  11405. if (!enabled) {
  11406. updateFloating();
  11407. }
  11408. });
  11409. me.addListener('sourcemodechanged', function (t, enabled) {
  11410. setTimeout(function () {
  11411. updateFloating();
  11412. }, 0);
  11413. });
  11414. me.addListener("clearDoc", function () {
  11415. setTimeout(function () {
  11416. updateFloating();
  11417. }, 0);
  11418. })
  11419. }
  11420. });
  11421. };
  11422. /**
  11423. * @description 纯文本粘贴
  11424. * @name puretxtpaste
  11425. * @author zhanyi
  11426. */
  11427. UE.plugins['pasteplain'] = function () {
  11428. var me = this;
  11429. me.setOpt({
  11430. 'pasteplain': false,
  11431. 'filterTxtRules': function () {
  11432. function transP(node) {
  11433. node.tagName = 'p';
  11434. node.setStyle();
  11435. }
  11436. function removeNode(node) {
  11437. node.parentNode.removeChild(node, true)
  11438. }
  11439. return {
  11440. //直接删除及其字节点内容
  11441. '-': 'script style object iframe embed input select',
  11442. 'p': {$: {}},
  11443. 'br': {$: {}},
  11444. div: function (node) {
  11445. var tmpNode, p = UE.uNode.createElement('p');
  11446. while (tmpNode = node.firstChild()) {
  11447. if (tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) {
  11448. p.appendChild(tmpNode);
  11449. } else {
  11450. if (p.firstChild()) {
  11451. node.parentNode.insertBefore(p, node);
  11452. p = UE.uNode.createElement('p');
  11453. } else {
  11454. node.parentNode.insertBefore(tmpNode, node);
  11455. }
  11456. }
  11457. }
  11458. if (p.firstChild()) {
  11459. node.parentNode.insertBefore(p, node);
  11460. }
  11461. node.parentNode.removeChild(node);
  11462. },
  11463. ol: removeNode,
  11464. ul: removeNode,
  11465. dl: removeNode,
  11466. dt: removeNode,
  11467. dd: removeNode,
  11468. 'li': removeNode,
  11469. 'caption': transP,
  11470. 'th': transP,
  11471. 'tr': transP,
  11472. 'h1': transP, 'h2': transP, 'h3': transP, 'h4': transP, 'h5': transP, 'h6': transP,
  11473. 'td': function (node) {
  11474. //没有内容的td直接删掉
  11475. var txt = !!node.innerText();
  11476. if (txt) {
  11477. node.parentNode.insertAfter(UE.uNode.createText(' &nbsp; &nbsp;'), node);
  11478. }
  11479. node.parentNode.removeChild(node, node.innerText())
  11480. }
  11481. }
  11482. }()
  11483. });
  11484. //暂时这里支持一下老版本的属性
  11485. var pasteplain = me.options.pasteplain;
  11486. me.commands['pasteplain'] = {
  11487. queryCommandState: function () {
  11488. return pasteplain ? 1 : 0;
  11489. },
  11490. execCommand: function () {
  11491. pasteplain = !pasteplain | 0;
  11492. },
  11493. notNeedUndo: 1
  11494. };
  11495. };
  11496. ///import core
  11497. ///import plugins/inserthtml.js
  11498. ///commands 视频
  11499. ///commandsName InsertVideo
  11500. ///commandsTitle 插入视频
  11501. ///commandsDialog dialogs\video
  11502. UE.plugins['video'] = function () {
  11503. var me = this,
  11504. div;
  11505. /**
  11506. * 创建插入视频字符窜
  11507. * @param url 视频地址
  11508. * @param width 视频宽度
  11509. * @param height 视频高度
  11510. * @param align 视频对齐
  11511. * @param toEmbed 是否以flash代替显示
  11512. * @param addParagraph 是否需要添加P 标签
  11513. */
  11514. function creatInsertStr(url, width, height, id, align, toEmbed) {
  11515. return !toEmbed ?
  11516. '<img ' + (id ? 'id="' + id + '"' : '') + ' width="' + width + '" height="' + height + '" _url="' + url + '" class="edui-faked-video"' +
  11517. ' 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;' + (align ? 'float:' + align + ';' : '') + '" />'
  11518. :
  11519. '<embed type="application/x-shockwave-flash" class="edui-faked-video" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  11520. ' src="' + url + '" width="' + width + '" height="' + height + '"' + (align ? ' style="float:' + align + '"' : '') +
  11521. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  11522. }
  11523. function switchImgAndEmbed(root, img2embed) {
  11524. utils.each(root.getNodesByTagName(img2embed ? 'img' : 'embed'), function (node) {
  11525. if (node.getAttr('class') == 'edui-faked-video') {
  11526. var html = creatInsertStr(img2embed ? node.getAttr('_url') : node.getAttr('src'), node.getAttr('width'), node.getAttr('height'), null, node.getStyle('float') || '', img2embed);
  11527. node.parentNode.replaceChild(UE.uNode.createElement(html), node)
  11528. }
  11529. })
  11530. }
  11531. me.addOutputRule(function (root) {
  11532. switchImgAndEmbed(root, true)
  11533. });
  11534. me.addInputRule(function (root) {
  11535. switchImgAndEmbed(root)
  11536. });
  11537. me.commands["insertvideo"] = {
  11538. execCommand: function (cmd, videoObjs) {
  11539. videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs];
  11540. var html = [], id = 'tmpVedio';
  11541. for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
  11542. vi = videoObjs[i];
  11543. html.push(creatInsertStr(vi.url, vi.width || 420, vi.height || 280, id + i, null, false));
  11544. }
  11545. me.execCommand("inserthtml", html.join(""), true);
  11546. var rng = this.selection.getRange();
  11547. for (var i = 0, len = videoObjs.length; i < len; i++) {
  11548. var img = this.document.getElementById('tmpVedio' + i);
  11549. domUtils.removeAttributes(img, 'id');
  11550. rng.selectNode(img).select();
  11551. me.execCommand('imagefloat', videoObjs[i].align)
  11552. }
  11553. },
  11554. queryCommandState: function () {
  11555. var img = me.selection.getRange().getClosedNode(),
  11556. flag = img && (img.className == "edui-faked-video");
  11557. return flag ? 1 : 0;
  11558. }
  11559. };
  11560. };
  11561. /**
  11562. * Created with JetBrains WebStorm.
  11563. * User: taoqili
  11564. * Date: 13-1-18
  11565. * Time: 上午11:09
  11566. * To change this template use File | Settings | File Templates.
  11567. */
  11568. /**
  11569. * UE表格操作类
  11570. * @param table
  11571. * @constructor
  11572. */
  11573. (function () {
  11574. var UETable = UE.UETable = function (table) {
  11575. this.table = table;
  11576. this.indexTable = [];
  11577. this.selectedTds = [];
  11578. this.cellsRange = {};
  11579. this.update(table);
  11580. };
  11581. //===以下为静态工具方法===
  11582. UETable.removeSelectedClass = function (cells) {
  11583. utils.each(cells, function (cell) {
  11584. domUtils.removeClasses(cell, "selectTdClass");
  11585. })
  11586. };
  11587. UETable.addSelectedClass = function (cells) {
  11588. utils.each(cells, function (cell) {
  11589. domUtils.addClass(cell, "selectTdClass");
  11590. })
  11591. };
  11592. UETable.isEmptyBlock = function (node) {
  11593. var reg = new RegExp(domUtils.fillChar, 'g');
  11594. if (node[browser.ie ? 'innerText' : 'textContent'].replace(/^\s*$/, '').replace(reg, '').length > 0) {
  11595. return 0;
  11596. }
  11597. for (var i in dtd.$isNotEmpty) if (dtd.$isNotEmpty.hasOwnProperty(i)) {
  11598. if (node.getElementsByTagName(i).length) {
  11599. return 0;
  11600. }
  11601. }
  11602. return 1;
  11603. };
  11604. UETable.getWidth = function (cell) {
  11605. if (!cell)return 0;
  11606. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  11607. };
  11608. /**
  11609. * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
  11610. * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
  11611. * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
  11612. * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
  11613. */
  11614. UETable.getTableCellAlignState = function (cells) {
  11615. !utils.isArray(cells) && ( cells = [cells] );
  11616. var result = {},
  11617. status = ['align', 'valign'],
  11618. tempStatus = null,
  11619. isSame = true;//状态是否相同
  11620. utils.each(cells, function (cellNode) {
  11621. utils.each(status, function (currentState) {
  11622. tempStatus = cellNode.getAttribute(currentState);
  11623. if (!result[ currentState ] && tempStatus) {
  11624. result[ currentState ] = tempStatus;
  11625. } else if (!result[ currentState ] || ( tempStatus !== result[ currentState ] )) {
  11626. isSame = false;
  11627. return false;
  11628. }
  11629. });
  11630. return isSame;
  11631. });
  11632. return isSame ? result : null;
  11633. };
  11634. /**
  11635. * 根据当前选区获取相关的table信息
  11636. * @return {Object}
  11637. */
  11638. UETable.getTableItemsByRange = function (editor) {
  11639. var start = editor.selection.getStart();
  11640. //ff下会选中bookmark
  11641. if (start && start.id && start.id.indexOf('_baidu_bookmark_start_') === 0) {
  11642. start = start.nextSibling;
  11643. }
  11644. //在table或者td边缘有可能存在选中tr的情况
  11645. var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
  11646. tr = cell && cell.parentNode,
  11647. caption = start && domUtils.findParentByTagName(start, 'caption', true),
  11648. table = caption ? caption.parentNode : tr && tr.parentNode.parentNode;
  11649. return {
  11650. cell: cell,
  11651. tr: tr,
  11652. table: table,
  11653. caption: caption
  11654. }
  11655. };
  11656. UETable.getUETableBySelected = function (editor) {
  11657. var table = UETable.getTableItemsByRange(editor).table;
  11658. if (table && table.ueTable && table.ueTable.selectedTds.length) {
  11659. return table.ueTable;
  11660. }
  11661. return null;
  11662. };
  11663. UETable.getDefaultValue = function (editor, table) {
  11664. var borderMap = {
  11665. thin: '0px',
  11666. medium: '1px',
  11667. thick: '2px'
  11668. },
  11669. tableBorder, tdPadding, tdBorder, tmpValue;
  11670. if (!table) {
  11671. table = editor.document.createElement('table');
  11672. table.insertRow(0).insertCell(0).innerHTML = 'xxx';
  11673. editor.body.appendChild(table);
  11674. var td = table.getElementsByTagName('td')[0];
  11675. tmpValue = domUtils.getComputedStyle(table, 'border-left-width');
  11676. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  11677. tmpValue = domUtils.getComputedStyle(td, 'padding-left');
  11678. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  11679. tmpValue = domUtils.getComputedStyle(td, 'border-left-width');
  11680. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  11681. domUtils.remove(table);
  11682. return {
  11683. tableBorder: tableBorder,
  11684. tdPadding: tdPadding,
  11685. tdBorder: tdBorder
  11686. };
  11687. } else {
  11688. td = table.getElementsByTagName('td')[0];
  11689. tmpValue = domUtils.getComputedStyle(table, 'border-left-width');
  11690. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  11691. tmpValue = domUtils.getComputedStyle(td, 'padding-left');
  11692. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  11693. tmpValue = domUtils.getComputedStyle(td, 'border-left-width');
  11694. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  11695. return {
  11696. tableBorder: tableBorder,
  11697. tdPadding: tdPadding,
  11698. tdBorder: tdBorder
  11699. };
  11700. }
  11701. };
  11702. /**
  11703. * 根据当前点击的td或者table获取索引对象
  11704. * @param tdOrTable
  11705. */
  11706. UETable.getUETable = function (tdOrTable) {
  11707. var tag = tdOrTable.tagName.toLowerCase();
  11708. tdOrTable = (tag == "td" || tag == "th" || tag == 'caption') ? domUtils.findParentByTagName(tdOrTable, "table", true) : tdOrTable;
  11709. if (!tdOrTable.ueTable) {
  11710. tdOrTable.ueTable = new UETable(tdOrTable);
  11711. }
  11712. return tdOrTable.ueTable;
  11713. };
  11714. UETable.cloneCell = function (cell, ignoreMerge, keepPro) {
  11715. if (!cell || utils.isString(cell)) {
  11716. return this.table.ownerDocument.createElement(cell || 'td');
  11717. }
  11718. var flag = domUtils.hasClass(cell, "selectTdClass");
  11719. flag && domUtils.removeClasses(cell, "selectTdClass");
  11720. var tmpCell = cell.cloneNode(true);
  11721. if (ignoreMerge) {
  11722. tmpCell.rowSpan = tmpCell.colSpan = 1;
  11723. }
  11724. //去掉宽高
  11725. !keepPro && domUtils.removeAttributes(tmpCell, 'width height');
  11726. !keepPro && domUtils.removeAttributes(tmpCell, 'style');
  11727. tmpCell.style.borderLeftStyle = "";
  11728. tmpCell.style.borderTopStyle = "";
  11729. tmpCell.style.borderLeftColor = cell.style.borderRightColor;
  11730. tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
  11731. tmpCell.style.borderTopColor = cell.style.borderBottomColor;
  11732. tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
  11733. flag && domUtils.addClass(cell, "selectTdClass");
  11734. return tmpCell;
  11735. }
  11736. UETable.prototype = {
  11737. getMaxRows: function () {
  11738. var rows = this.table.rows, maxLen = 1;
  11739. for (var i = 0, row; row = rows[i]; i++) {
  11740. var currentMax = 1;
  11741. for (var j = 0, cj; cj = row.cells[j++];) {
  11742. currentMax = Math.max(cj.rowSpan || 1, currentMax);
  11743. }
  11744. maxLen = Math.max(currentMax + i, maxLen);
  11745. }
  11746. return maxLen;
  11747. },
  11748. /**
  11749. * 获取当前表格的最大列数
  11750. */
  11751. getMaxCols: function () {
  11752. var rows = this.table.rows, maxLen = 0, cellRows = {};
  11753. for (var i = 0, row; row = rows[i]; i++) {
  11754. var cellsNum = 0;
  11755. for (var j = 0, cj; cj = row.cells[j++];) {
  11756. cellsNum += (cj.colSpan || 1);
  11757. if (cj.rowSpan && cj.rowSpan > 1) {
  11758. for (var k = 1; k < cj.rowSpan; k++) {
  11759. if (!cellRows['row_' + (i + k)]) {
  11760. cellRows['row_' + (i + k)] = (cj.colSpan || 1);
  11761. } else {
  11762. cellRows['row_' + (i + k)]++
  11763. }
  11764. }
  11765. }
  11766. }
  11767. cellsNum += cellRows['row_' + i] || 0;
  11768. maxLen = Math.max(cellsNum, maxLen);
  11769. }
  11770. return maxLen;
  11771. },
  11772. getCellColIndex: function (cell) {
  11773. },
  11774. /**
  11775. * 获取当前cell旁边的单元格,
  11776. * @param cell
  11777. * @param right
  11778. */
  11779. getHSideCell: function (cell, right) {
  11780. try {
  11781. var cellInfo = this.getCellInfo(cell),
  11782. previewRowIndex, previewColIndex;
  11783. var len = this.selectedTds.length,
  11784. range = this.cellsRange;
  11785. //首行或者首列没有前置单元格
  11786. if ((!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) || (right && (!len ? (cellInfo.colIndex == (this.colsNum - 1)) : (range.endColIndex == this.colsNum - 1)))) return null;
  11787. previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
  11788. previewColIndex = !right ? ( !len ? (cellInfo.colIndex < 1 ? 0 : (cellInfo.colIndex - 1)) : range.beginColIndex - 1)
  11789. : ( !len ? cellInfo.colIndex + 1 : range.endColIndex + 1);
  11790. return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this.indexTable[previewRowIndex][previewColIndex].cellIndex);
  11791. } catch (e) {
  11792. showError(e);
  11793. }
  11794. },
  11795. getTabNextCell: function (cell, preRowIndex) {
  11796. var cellInfo = this.getCellInfo(cell),
  11797. rowIndex = preRowIndex || cellInfo.rowIndex,
  11798. colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
  11799. nextCell;
  11800. try {
  11801. nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this.indexTable[rowIndex][colIndex].cellIndex);
  11802. } catch (e) {
  11803. try {
  11804. rowIndex = rowIndex * 1 + 1;
  11805. colIndex = 0;
  11806. nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this.indexTable[rowIndex][colIndex].cellIndex);
  11807. } catch (e) {
  11808. }
  11809. }
  11810. return nextCell;
  11811. },
  11812. /**
  11813. * 获取视觉上的后置单元格
  11814. * @param cell
  11815. * @param bottom
  11816. */
  11817. getVSideCell: function (cell, bottom, ignoreRange) {
  11818. try {
  11819. var cellInfo = this.getCellInfo(cell),
  11820. nextRowIndex, nextColIndex;
  11821. var len = this.selectedTds.length && !ignoreRange,
  11822. range = this.cellsRange;
  11823. //末行或者末列没有后置单元格
  11824. if ((!bottom && (cellInfo.rowIndex == 0)) || (bottom && (!len ? (cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1) : (range.endRowIndex == this.rowsNum - 1)))) return null;
  11825. nextRowIndex = !bottom ? ( !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1)
  11826. : ( !len ? (cellInfo.rowIndex + cellInfo.rowSpan) : range.endRowIndex + 1);
  11827. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  11828. return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this.indexTable[nextRowIndex][nextColIndex].cellIndex);
  11829. } catch (e) {
  11830. showError(e);
  11831. }
  11832. },
  11833. /**
  11834. * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
  11835. */
  11836. getSameEndPosCells: function (cell, xOrY) {
  11837. try {
  11838. var flag = (xOrY.toLowerCase() === "x"),
  11839. end = domUtils.getXY(cell)[flag ? 'x' : 'y'] + cell["offset" + (flag ? 'Width' : 'Height')],
  11840. rows = this.table.rows,
  11841. cells = null, returns = [];
  11842. for (var i = 0; i < this.rowsNum; i++) {
  11843. cells = rows[i].cells;
  11844. for (var j = 0, tmpCell; tmpCell = cells[j++];) {
  11845. var tmpEnd = domUtils.getXY(tmpCell)[flag ? 'x' : 'y'] + tmpCell["offset" + (flag ? 'Width' : 'Height')];
  11846. //对应行的td已经被上面行rowSpan了
  11847. if (tmpEnd > end && flag) break;
  11848. if (cell == tmpCell || end == tmpEnd) {
  11849. //只获取单一的单元格
  11850. //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
  11851. if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
  11852. returns.push(tmpCell);
  11853. }
  11854. if (flag) break;
  11855. }
  11856. }
  11857. }
  11858. return returns;
  11859. } catch (e) {
  11860. showError(e);
  11861. }
  11862. },
  11863. setCellContent: function (cell, content) {
  11864. cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />");
  11865. },
  11866. cloneCell: UETable.cloneCell,
  11867. /**
  11868. * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
  11869. */
  11870. getSameStartPosXCells: function (cell) {
  11871. try {
  11872. var start = domUtils.getXY(cell).x + cell.offsetWidth,
  11873. rows = this.table.rows, cells , returns = [];
  11874. for (var i = 0; i < this.rowsNum; i++) {
  11875. cells = rows[i].cells;
  11876. for (var j = 0, tmpCell; tmpCell = cells[j++];) {
  11877. var tmpStart = domUtils.getXY(tmpCell).x;
  11878. if (tmpStart > start) break;
  11879. if (tmpStart == start && tmpCell.colSpan == 1) {
  11880. returns.push(tmpCell);
  11881. break;
  11882. }
  11883. }
  11884. }
  11885. return returns;
  11886. } catch (e) {
  11887. showError(e);
  11888. }
  11889. },
  11890. /**
  11891. * 更新table对应的索引表
  11892. */
  11893. update: function (table) {
  11894. this.table = table || this.table;
  11895. this.selectedTds = [];
  11896. this.cellsRange = {};
  11897. this.indexTable = [];
  11898. var rows = this.table.rows,
  11899. rowsNum = this.getMaxRows(),
  11900. dNum = rowsNum - rows.length,
  11901. colsNum = this.getMaxCols();
  11902. while (dNum--) {
  11903. this.table.insertRow(rows.length);
  11904. }
  11905. this.rowsNum = rowsNum;
  11906. this.colsNum = colsNum;
  11907. for (var i = 0, len = rows.length; i < len; i++) {
  11908. this.indexTable[i] = new Array(colsNum);
  11909. }
  11910. //填充索引表
  11911. for (var rowIndex = 0, row; row = rows[rowIndex]; rowIndex++) {
  11912. for (var cellIndex = 0, cell, cells = row.cells; cell = cells[cellIndex]; cellIndex++) {
  11913. //修正整行被rowSpan时导致的行数计算错误
  11914. if (cell.rowSpan > rowsNum) {
  11915. cell.rowSpan = rowsNum;
  11916. }
  11917. var colIndex = cellIndex,
  11918. rowSpan = cell.rowSpan || 1,
  11919. colSpan = cell.colSpan || 1;
  11920. //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
  11921. while (this.indexTable[rowIndex][colIndex]) colIndex++;
  11922. for (var j = 0; j < rowSpan; j++) {
  11923. for (var k = 0; k < colSpan; k++) {
  11924. this.indexTable[rowIndex + j][colIndex + k] = {
  11925. rowIndex: rowIndex,
  11926. cellIndex: cellIndex,
  11927. colIndex: colIndex,
  11928. rowSpan: rowSpan,
  11929. colSpan: colSpan
  11930. }
  11931. }
  11932. }
  11933. }
  11934. }
  11935. //修复残缺td
  11936. for (j = 0; j < rowsNum; j++) {
  11937. for (k = 0; k < colsNum; k++) {
  11938. if (this.indexTable[j][k] === undefined) {
  11939. row = rows[j];
  11940. cell = row.cells[row.cells.length - 1];
  11941. cell = cell ? cell.cloneNode(true) : this.table.ownerDocument.createElement("td");
  11942. this.setCellContent(cell);
  11943. if (cell.colSpan !== 1)cell.colSpan = 1;
  11944. if (cell.rowSpan !== 1)cell.rowSpan = 1;
  11945. row.appendChild(cell);
  11946. this.indexTable[j][k] = {
  11947. rowIndex: j,
  11948. cellIndex: cell.cellIndex,
  11949. colIndex: k,
  11950. rowSpan: 1,
  11951. colSpan: 1
  11952. }
  11953. }
  11954. }
  11955. }
  11956. //当框选后删除行或者列后撤销,需要重建选区。
  11957. var tds = domUtils.getElementsByTagName(this.table, "td"),
  11958. selectTds = [];
  11959. utils.each(tds, function (td) {
  11960. if (domUtils.hasClass(td, "selectTdClass")) {
  11961. selectTds.push(td);
  11962. }
  11963. });
  11964. if (selectTds.length) {
  11965. var start = selectTds[0],
  11966. end = selectTds[selectTds.length - 1],
  11967. startInfo = this.getCellInfo(start),
  11968. endInfo = this.getCellInfo(end);
  11969. this.selectedTds = selectTds;
  11970. this.cellsRange = {
  11971. beginRowIndex: startInfo.rowIndex,
  11972. beginColIndex: startInfo.colIndex,
  11973. endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
  11974. endColIndex: endInfo.colIndex + endInfo.colSpan - 1
  11975. };
  11976. }
  11977. },
  11978. /**
  11979. * 获取单元格的索引信息
  11980. */
  11981. getCellInfo: function (cell) {
  11982. if (!cell) return;
  11983. var cellIndex = cell.cellIndex,
  11984. rowIndex = cell.parentNode.rowIndex,
  11985. rowInfo = this.indexTable[rowIndex],
  11986. numCols = this.colsNum;
  11987. for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
  11988. var cellInfo = rowInfo[colIndex];
  11989. if (cellInfo.rowIndex === rowIndex && cellInfo.cellIndex === cellIndex) {
  11990. return cellInfo;
  11991. }
  11992. }
  11993. },
  11994. /**
  11995. * 根据行列号获取单元格
  11996. */
  11997. getCell: function (rowIndex, cellIndex) {
  11998. return rowIndex < this.rowsNum && this.table.rows[rowIndex].cells[cellIndex] || null;
  11999. },
  12000. /**
  12001. * 删除单元格
  12002. */
  12003. deleteCell: function (cell, rowIndex) {
  12004. rowIndex = typeof rowIndex == 'number' ? rowIndex : cell.parentNode.rowIndex;
  12005. var row = this.table.rows[rowIndex];
  12006. row.deleteCell(cell.cellIndex);
  12007. },
  12008. /**
  12009. * 根据始末两个单元格获取被框选的所有单元格范围
  12010. */
  12011. getCellsRange: function (cellA, cellB) {
  12012. function checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex) {
  12013. var tmpBeginRowIndex = beginRowIndex,
  12014. tmpBeginColIndex = beginColIndex,
  12015. tmpEndRowIndex = endRowIndex,
  12016. tmpEndColIndex = endColIndex,
  12017. cellInfo, colIndex, rowIndex;
  12018. // 通过indexTable检查是否存在超出TableRange上边界的情况
  12019. if (beginRowIndex > 0) {
  12020. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  12021. cellInfo = me.indexTable[beginRowIndex][colIndex];
  12022. rowIndex = cellInfo.rowIndex;
  12023. if (rowIndex < beginRowIndex) {
  12024. tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex);
  12025. }
  12026. }
  12027. }
  12028. // 通过indexTable检查是否存在超出TableRange右边界的情况
  12029. if (endColIndex < me.colsNum) {
  12030. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  12031. cellInfo = me.indexTable[rowIndex][endColIndex];
  12032. colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
  12033. if (colIndex > endColIndex) {
  12034. tmpEndColIndex = Math.max(colIndex, tmpEndColIndex);
  12035. }
  12036. }
  12037. }
  12038. // 检查是否有超出TableRange下边界的情况
  12039. if (endRowIndex < me.rowsNum) {
  12040. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  12041. cellInfo = me.indexTable[endRowIndex][colIndex];
  12042. rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
  12043. if (rowIndex > endRowIndex) {
  12044. tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex);
  12045. }
  12046. }
  12047. }
  12048. // 检查是否有超出TableRange左边界的情况
  12049. if (beginColIndex > 0) {
  12050. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  12051. cellInfo = me.indexTable[rowIndex][beginColIndex];
  12052. colIndex = cellInfo.colIndex;
  12053. if (colIndex < beginColIndex) {
  12054. tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex);
  12055. }
  12056. }
  12057. }
  12058. //递归调用直至所有完成所有框选单元格的扩展
  12059. if (tmpBeginRowIndex != beginRowIndex || tmpBeginColIndex != beginColIndex || tmpEndRowIndex != endRowIndex || tmpEndColIndex != endColIndex) {
  12060. return checkRange(tmpBeginRowIndex, tmpBeginColIndex, tmpEndRowIndex, tmpEndColIndex);
  12061. } else {
  12062. // 不需要扩展TableRange的情况
  12063. return {
  12064. beginRowIndex: beginRowIndex,
  12065. beginColIndex: beginColIndex,
  12066. endRowIndex: endRowIndex,
  12067. endColIndex: endColIndex
  12068. };
  12069. }
  12070. }
  12071. try {
  12072. var me = this,
  12073. cellAInfo = me.getCellInfo(cellA);
  12074. if (cellA === cellB) {
  12075. return {
  12076. beginRowIndex: cellAInfo.rowIndex,
  12077. beginColIndex: cellAInfo.colIndex,
  12078. endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  12079. endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
  12080. };
  12081. }
  12082. var cellBInfo = me.getCellInfo(cellB);
  12083. // 计算TableRange的四个边
  12084. var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
  12085. beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
  12086. endRowIndex = Math.max(cellAInfo.rowIndex + cellAInfo.rowSpan - 1, cellBInfo.rowIndex + cellBInfo.rowSpan - 1),
  12087. endColIndex = Math.max(cellAInfo.colIndex + cellAInfo.colSpan - 1, cellBInfo.colIndex + cellBInfo.colSpan - 1);
  12088. return checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex);
  12089. } catch (e) {
  12090. //throw e;
  12091. }
  12092. },
  12093. /**
  12094. * 依据cellsRange获取对应的单元格集合
  12095. */
  12096. getCells: function (range) {
  12097. //每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
  12098. this.clearSelected();
  12099. var beginRowIndex = range.beginRowIndex,
  12100. beginColIndex = range.beginColIndex,
  12101. endRowIndex = range.endRowIndex,
  12102. endColIndex = range.endColIndex,
  12103. cellInfo, rowIndex, colIndex, tdHash = {}, returnTds = [];
  12104. for (var i = beginRowIndex; i <= endRowIndex; i++) {
  12105. for (var j = beginColIndex; j <= endColIndex; j++) {
  12106. cellInfo = this.indexTable[i][j];
  12107. rowIndex = cellInfo.rowIndex;
  12108. colIndex = cellInfo.colIndex;
  12109. // 如果Cells里已经包含了此Cell则跳过
  12110. var key = rowIndex + '|' + colIndex;
  12111. if (tdHash[key]) continue;
  12112. tdHash[key] = 1;
  12113. if (rowIndex < i || colIndex < j || rowIndex + cellInfo.rowSpan - 1 > endRowIndex || colIndex + cellInfo.colSpan - 1 > endColIndex) {
  12114. return null;
  12115. }
  12116. returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex));
  12117. }
  12118. }
  12119. return returnTds;
  12120. },
  12121. /**
  12122. * 清理已经选中的单元格
  12123. */
  12124. clearSelected: function () {
  12125. UETable.removeSelectedClass(this.selectedTds);
  12126. this.selectedTds = [];
  12127. this.cellsRange = {};
  12128. },
  12129. /**
  12130. * 根据range设置已经选中的单元格
  12131. */
  12132. setSelected: function (range) {
  12133. var cells = this.getCells(range);
  12134. UETable.addSelectedClass(cells);
  12135. this.selectedTds = cells;
  12136. this.cellsRange = range;
  12137. },
  12138. isFullRow: function () {
  12139. var range = this.cellsRange;
  12140. return (range.endColIndex - range.beginColIndex + 1) == this.colsNum;
  12141. },
  12142. isFullCol: function () {
  12143. var range = this.cellsRange,
  12144. table = this.table,
  12145. ths = table.getElementsByTagName("th"),
  12146. rows = range.endRowIndex - range.beginRowIndex + 1;
  12147. return !ths.length ? rows == this.rowsNum : rows == this.rowsNum || (rows == this.rowsNum - 1);
  12148. },
  12149. /**
  12150. * 获取视觉上的前置单元格,默认是左边,top传入时
  12151. * @param cell
  12152. * @param top
  12153. */
  12154. getNextCell: function (cell, bottom, ignoreRange) {
  12155. try {
  12156. var cellInfo = this.getCellInfo(cell),
  12157. nextRowIndex, nextColIndex;
  12158. var len = this.selectedTds.length && !ignoreRange,
  12159. range = this.cellsRange;
  12160. //末行或者末列没有后置单元格
  12161. if ((!bottom && (cellInfo.rowIndex == 0)) || (bottom && (!len ? (cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1) : (range.endRowIndex == this.rowsNum - 1)))) return null;
  12162. nextRowIndex = !bottom ? ( !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1)
  12163. : ( !len ? (cellInfo.rowIndex + cellInfo.rowSpan) : range.endRowIndex + 1);
  12164. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  12165. return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this.indexTable[nextRowIndex][nextColIndex].cellIndex);
  12166. } catch (e) {
  12167. showError(e);
  12168. }
  12169. },
  12170. getPreviewCell: function (cell, top) {
  12171. try {
  12172. var cellInfo = this.getCellInfo(cell),
  12173. previewRowIndex, previewColIndex;
  12174. var len = this.selectedTds.length,
  12175. range = this.cellsRange;
  12176. //首行或者首列没有前置单元格
  12177. if ((!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) || (top && (!len ? (cellInfo.rowIndex > (this.colsNum - 1)) : (range.endColIndex == this.colsNum - 1)))) return null;
  12178. previewRowIndex = !top ? ( !len ? cellInfo.rowIndex : range.beginRowIndex )
  12179. : ( !len ? (cellInfo.rowIndex < 1 ? 0 : (cellInfo.rowIndex - 1)) : range.beginRowIndex);
  12180. previewColIndex = !top ? ( !len ? (cellInfo.colIndex < 1 ? 0 : (cellInfo.colIndex - 1)) : range.beginColIndex - 1)
  12181. : ( !len ? cellInfo.colIndex : range.endColIndex + 1);
  12182. return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this.indexTable[previewRowIndex][previewColIndex].cellIndex);
  12183. } catch (e) {
  12184. showError(e);
  12185. }
  12186. },
  12187. /**
  12188. * 移动单元格中的内容
  12189. */
  12190. moveContent: function (cellTo, cellFrom) {
  12191. if (UETable.isEmptyBlock(cellFrom)) return;
  12192. if (UETable.isEmptyBlock(cellTo)) {
  12193. cellTo.innerHTML = cellFrom.innerHTML;
  12194. return;
  12195. }
  12196. var child = cellTo.lastChild;
  12197. if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
  12198. cellTo.appendChild(cellTo.ownerDocument.createElement('br'))
  12199. }
  12200. while (child = cellFrom.firstChild) {
  12201. cellTo.appendChild(child);
  12202. }
  12203. },
  12204. /**
  12205. * 向右合并单元格
  12206. */
  12207. mergeRight: function (cell) {
  12208. var cellInfo = this.getCellInfo(cell),
  12209. rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
  12210. rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
  12211. rightCell = this.getCell(rightCellInfo.rowIndex, rightCellInfo.cellIndex);
  12212. //合并
  12213. cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
  12214. //被合并的单元格不应存在宽度属性
  12215. cell.removeAttribute("width");
  12216. //移动内容
  12217. this.moveContent(cell, rightCell);
  12218. //删掉被合并的Cell
  12219. this.deleteCell(rightCell, rightCellInfo.rowIndex);
  12220. this.update();
  12221. },
  12222. /**
  12223. * 向下合并单元格
  12224. */
  12225. mergeDown: function (cell) {
  12226. var cellInfo = this.getCellInfo(cell),
  12227. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
  12228. downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
  12229. downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
  12230. cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
  12231. cell.removeAttribute("height");
  12232. this.moveContent(cell, downCell);
  12233. this.deleteCell(downCell, downCellInfo.rowIndex);
  12234. this.update();
  12235. },
  12236. /**
  12237. * 合并整个range中的内容
  12238. */
  12239. mergeRange: function () {
  12240. //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
  12241. var range = this.cellsRange,
  12242. leftTopCell = this.getCell(range.beginRowIndex, this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex);
  12243. if (leftTopCell.tagName == "TH" && range.endRowIndex !== range.beginRowIndex) {
  12244. var index = this.indexTable,
  12245. info = this.getCellInfo(leftTopCell);
  12246. leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
  12247. range = this.getCellsRange(leftTopCell, this.getCell(index[this.rowsNum - 1][info.colIndex].rowIndex, index[this.rowsNum - 1][info.colIndex].cellIndex));
  12248. }
  12249. // 删除剩余的Cells
  12250. var cells = this.getCells(range);
  12251. for (var i = 0, ci; ci = cells[i++];) {
  12252. if (ci !== leftTopCell) {
  12253. this.moveContent(leftTopCell, ci);
  12254. this.deleteCell(ci);
  12255. }
  12256. }
  12257. // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
  12258. leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
  12259. leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
  12260. leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
  12261. leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
  12262. if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
  12263. leftTopCell.colSpan = 1;
  12264. }
  12265. if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
  12266. var rowIndex = leftTopCell.parentNode.rowIndex;
  12267. //解决IE下的表格操作问题
  12268. if (this.table.deleteRow) {
  12269. for (var i = rowIndex + 1, curIndex = rowIndex + 1, len = leftTopCell.rowSpan; i < len; i++) {
  12270. this.table.deleteRow(curIndex);
  12271. }
  12272. } else {
  12273. for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
  12274. var row = this.table.rows[rowIndex + 1];
  12275. row.parentNode.removeChild(row);
  12276. }
  12277. }
  12278. leftTopCell.rowSpan = 1;
  12279. }
  12280. this.update();
  12281. },
  12282. /**
  12283. * 插入一行单元格
  12284. */
  12285. insertRow: function (rowIndex, sourceCell) {
  12286. var numCols = this.colsNum,
  12287. table = this.table,
  12288. row = table.insertRow(rowIndex), cell,
  12289. width = parseInt((table.offsetWidth - numCols * 20 - numCols - 1) / numCols, 10);
  12290. //首行直接插入,无需考虑部分单元格被rowspan的情况
  12291. if (rowIndex == 0 || rowIndex == this.rowsNum) {
  12292. for (var colIndex = 0; colIndex < numCols; colIndex++) {
  12293. cell = this.cloneCell(sourceCell, true);
  12294. this.setCellContent(cell);
  12295. cell.getAttribute('vAlign') && cell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  12296. row.appendChild(cell);
  12297. }
  12298. } else {
  12299. var infoRow = this.indexTable[rowIndex],
  12300. cellIndex = 0;
  12301. for (colIndex = 0; colIndex < numCols; colIndex++) {
  12302. var cellInfo = infoRow[colIndex];
  12303. //如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
  12304. if (cellInfo.rowIndex < rowIndex) {
  12305. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  12306. cell.rowSpan = cellInfo.rowSpan + 1;
  12307. } else {
  12308. cell = this.cloneCell(sourceCell, true);
  12309. this.setCellContent(cell);
  12310. row.appendChild(cell);
  12311. }
  12312. }
  12313. }
  12314. //框选时插入不触发contentchange,需要手动更新索引。
  12315. this.update();
  12316. return row;
  12317. },
  12318. /**
  12319. * 删除一行单元格
  12320. * @param rowIndex
  12321. */
  12322. deleteRow: function (rowIndex) {
  12323. var row = this.table.rows[rowIndex],
  12324. infoRow = this.indexTable[rowIndex],
  12325. colsNum = this.colsNum,
  12326. count = 0; //处理计数
  12327. for (var colIndex = 0; colIndex < colsNum;) {
  12328. var cellInfo = infoRow[colIndex],
  12329. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  12330. if (cell.rowSpan > 1) {
  12331. if (cellInfo.rowIndex == rowIndex) {
  12332. var clone = cell.cloneNode(true);
  12333. clone.rowSpan = cell.rowSpan - 1;
  12334. clone.innerHTML = "";
  12335. cell.rowSpan = 1;
  12336. var nextRowIndex = rowIndex + 1,
  12337. nextRow = this.table.rows[nextRowIndex],
  12338. insertCellIndex,
  12339. preMerged = this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count;
  12340. if (preMerged < colIndex) {
  12341. insertCellIndex = colIndex - preMerged - 1;
  12342. //nextRow.insertCell(insertCellIndex);
  12343. domUtils.insertAfter(nextRow.cells[insertCellIndex], clone);
  12344. } else {
  12345. if (nextRow.cells.length) nextRow.insertBefore(clone, nextRow.cells[0])
  12346. }
  12347. count += 1;
  12348. //cell.parentNode.removeChild(cell);
  12349. }
  12350. }
  12351. colIndex += cell.colSpan || 1;
  12352. }
  12353. var deleteTds = [], cacheMap = {};
  12354. for (colIndex = 0; colIndex < colsNum; colIndex++) {
  12355. var tmpRowIndex = infoRow[colIndex].rowIndex,
  12356. tmpCellIndex = infoRow[colIndex].cellIndex,
  12357. key = tmpRowIndex + "_" + tmpCellIndex;
  12358. if (cacheMap[key])continue;
  12359. cacheMap[key] = 1;
  12360. cell = this.getCell(tmpRowIndex, tmpCellIndex);
  12361. deleteTds.push(cell);
  12362. }
  12363. var mergeTds = [];
  12364. utils.each(deleteTds, function (td) {
  12365. if (td.rowSpan == 1) {
  12366. td.parentNode.removeChild(td);
  12367. } else {
  12368. mergeTds.push(td);
  12369. }
  12370. });
  12371. utils.each(mergeTds, function (td) {
  12372. td.rowSpan--;
  12373. });
  12374. row.parentNode.removeChild(row);
  12375. //浏览器方法本身存在bug,采用自定义方法删除
  12376. //this.table.deleteRow(rowIndex);
  12377. this.update();
  12378. },
  12379. insertCol: function (colIndex, sourceCell, defaultValue) {
  12380. var rowsNum = this.rowsNum,
  12381. rowIndex = 0,
  12382. tableRow, cell,
  12383. backWidth = parseInt((this.table.offsetWidth - (this.colsNum + 1) * 20 - (this.colsNum + 1)) / (this.colsNum + 1), 10);
  12384. function replaceTdToTh(rowIndex, cell, tableRow) {
  12385. if (rowIndex == 0) {
  12386. var th = cell.nextSibling || cell.previousSibling;
  12387. if (th.tagName == 'TH') {
  12388. th = cell.ownerDocument.createElement("th");
  12389. th.appendChild(cell.firstChild);
  12390. tableRow.insertBefore(th, cell);
  12391. domUtils.remove(cell)
  12392. }
  12393. } else {
  12394. if (cell.tagName == 'TH') {
  12395. var td = cell.ownerDocument.createElement("td");
  12396. td.appendChild(cell.firstChild);
  12397. tableRow.insertBefore(td, cell);
  12398. domUtils.remove(cell)
  12399. }
  12400. }
  12401. }
  12402. var preCell;
  12403. if (colIndex == 0 || colIndex == this.colsNum) {
  12404. for (; rowIndex < rowsNum; rowIndex++) {
  12405. tableRow = this.table.rows[rowIndex];
  12406. preCell = tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
  12407. cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
  12408. this.setCellContent(cell);
  12409. cell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  12410. preCell && cell.setAttribute('width', preCell.getAttribute('width'));
  12411. if (!colIndex) {
  12412. tableRow.insertBefore(cell, tableRow.cells[0]);
  12413. } else {
  12414. domUtils.insertAfter(tableRow.cells[tableRow.cells.length - 1], cell);
  12415. }
  12416. replaceTdToTh(rowIndex, cell, tableRow)
  12417. }
  12418. } else {
  12419. for (; rowIndex < rowsNum; rowIndex++) {
  12420. var cellInfo = this.indexTable[rowIndex][colIndex];
  12421. if (cellInfo.colIndex < colIndex) {
  12422. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  12423. cell.colSpan = cellInfo.colSpan + 1;
  12424. } else {
  12425. tableRow = this.table.rows[rowIndex];
  12426. preCell = tableRow.cells[cellInfo.cellIndex];
  12427. cell = this.cloneCell(sourceCell, true);//tableRow.insertCell(cellInfo.cellIndex);
  12428. this.setCellContent(cell);
  12429. cell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  12430. preCell && cell.setAttribute('width', preCell.getAttribute('width'));
  12431. //防止IE下报错
  12432. preCell ? tableRow.insertBefore(cell, preCell) : tableRow.appendChild(cell);
  12433. }
  12434. replaceTdToTh(rowIndex, cell, tableRow);
  12435. }
  12436. }
  12437. //框选时插入不触发contentchange,需要手动更新索引
  12438. this.update();
  12439. this.updateWidth(backWidth, defaultValue || {tdPadding: 10, tdBorder: 1});
  12440. },
  12441. updateWidth: function (width, defaultValue) {
  12442. var table = this.table,
  12443. tmpWidth = UETable.getWidth(table) - defaultValue.tdPadding * 2 - defaultValue.tdBorder + width;
  12444. if (tmpWidth < table.ownerDocument.body.offsetWidth) {
  12445. table.setAttribute("width", tmpWidth);
  12446. return;
  12447. }
  12448. var tds = domUtils.getElementsByTagName(this.table, "td");
  12449. utils.each(tds, function (td) {
  12450. td.setAttribute("width", width);
  12451. })
  12452. },
  12453. deleteCol: function (colIndex) {
  12454. var indexTable = this.indexTable,
  12455. tableRows = this.table.rows,
  12456. backTableWidth = this.table.getAttribute("width"),
  12457. backTdWidth = 0,
  12458. rowsNum = this.rowsNum,
  12459. cacheMap = {};
  12460. for (var rowIndex = 0; rowIndex < rowsNum;) {
  12461. var infoRow = indexTable[rowIndex],
  12462. cellInfo = infoRow[colIndex],
  12463. key = cellInfo.rowIndex + '_' + cellInfo.colIndex;
  12464. // 跳过已经处理过的Cell
  12465. if (cacheMap[key])continue;
  12466. cacheMap[key] = 1;
  12467. var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  12468. if (!backTdWidth) backTdWidth = cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0);
  12469. // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
  12470. if (cell.colSpan > 1) {
  12471. cell.colSpan--;
  12472. } else {
  12473. tableRows[rowIndex].deleteCell(cellInfo.cellIndex);
  12474. }
  12475. rowIndex += cellInfo.rowSpan || 1;
  12476. }
  12477. this.table.setAttribute("width", backTableWidth - backTdWidth);
  12478. this.update();
  12479. },
  12480. splitToCells: function (cell) {
  12481. var me = this,
  12482. cells = this.splitToRows(cell);
  12483. utils.each(cells, function (cell) {
  12484. me.splitToCols(cell);
  12485. })
  12486. },
  12487. splitToRows: function (cell) {
  12488. var cellInfo = this.getCellInfo(cell),
  12489. rowIndex = cellInfo.rowIndex,
  12490. colIndex = cellInfo.colIndex,
  12491. results = [];
  12492. // 修改Cell的rowSpan
  12493. cell.rowSpan = 1;
  12494. results.push(cell);
  12495. // 补齐单元格
  12496. for (var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan; i < endRow; i++) {
  12497. if (i == rowIndex)continue;
  12498. var tableRow = this.table.rows[i],
  12499. tmpCell = tableRow.insertCell(colIndex - this.getPreviewMergedCellsNum(i, colIndex));
  12500. tmpCell.colSpan = cellInfo.colSpan;
  12501. this.setCellContent(tmpCell);
  12502. tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  12503. tmpCell.setAttribute('align', cell.getAttribute('align'));
  12504. if (cell.style.cssText) {
  12505. tmpCell.style.cssText = cell.style.cssText;
  12506. }
  12507. results.push(tmpCell);
  12508. }
  12509. this.update();
  12510. return results;
  12511. },
  12512. getPreviewMergedCellsNum: function (rowIndex, colIndex) {
  12513. var indexRow = this.indexTable[rowIndex],
  12514. num = 0;
  12515. for (var i = 0; i < colIndex;) {
  12516. var colSpan = indexRow[i].colSpan,
  12517. tmpRowIndex = indexRow[i].rowIndex;
  12518. num += (colSpan - (tmpRowIndex == rowIndex ? 1 : 0));
  12519. i += colSpan;
  12520. }
  12521. return num;
  12522. },
  12523. splitToCols: function (cell) {
  12524. var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
  12525. cellInfo = this.getCellInfo(cell),
  12526. rowIndex = cellInfo.rowIndex,
  12527. colIndex = cellInfo.colIndex,
  12528. results = [];
  12529. // 修改Cell的rowSpan
  12530. cell.colSpan = 1;
  12531. cell.setAttribute("width", backWidth);
  12532. results.push(cell);
  12533. // 补齐单元格
  12534. for (var j = colIndex, endCol = colIndex + cellInfo.colSpan; j < endCol; j++) {
  12535. if (j == colIndex)continue;
  12536. var tableRow = this.table.rows[rowIndex],
  12537. tmpCell = tableRow.insertCell(this.indexTable[rowIndex][j].cellIndex + 1);
  12538. tmpCell.rowSpan = cellInfo.rowSpan;
  12539. this.setCellContent(tmpCell);
  12540. tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  12541. tmpCell.setAttribute('align', cell.getAttribute('align'));
  12542. tmpCell.setAttribute('width', backWidth);
  12543. if (cell.style.cssText) {
  12544. tmpCell.style.cssText = cell.style.cssText;
  12545. }
  12546. //处理th的情况
  12547. if (cell.tagName == 'TH') {
  12548. var th = cell.ownerDocument.createElement('th');
  12549. th.appendChild(tmpCell.firstChild);
  12550. th.setAttribute('vAlign', cell.getAttribute('vAlign'));
  12551. th.rowSpan = tmpCell.rowSpan;
  12552. tableRow.insertBefore(th, tmpCell);
  12553. domUtils.remove(tmpCell);
  12554. }
  12555. results.push(tmpCell);
  12556. }
  12557. this.update();
  12558. return results;
  12559. },
  12560. isLastCell: function (cell, rowsNum, colsNum) {
  12561. rowsNum = rowsNum || this.rowsNum;
  12562. colsNum = colsNum || this.colsNum;
  12563. var cellInfo = this.getCellInfo(cell);
  12564. return ((cellInfo.rowIndex + cellInfo.rowSpan) == rowsNum) &&
  12565. ((cellInfo.colIndex + cellInfo.colSpan) == colsNum);
  12566. },
  12567. getLastCell: function (cells) {
  12568. cells = cells || this.table.getElementsByTagName("td");
  12569. var firstInfo = this.getCellInfo(cells[0]);
  12570. var me = this, last = cells[0],
  12571. tr = last.parentNode,
  12572. cellsNum = 0, cols = 0, rows;
  12573. utils.each(cells, function (cell) {
  12574. if (cell.parentNode == tr)cols += cell.colSpan || 1;
  12575. cellsNum += cell.rowSpan * cell.colSpan || 1;
  12576. });
  12577. rows = cellsNum / cols;
  12578. utils.each(cells, function (cell) {
  12579. if (me.isLastCell(cell, rows, cols)) {
  12580. last = cell;
  12581. return false;
  12582. }
  12583. });
  12584. return last;
  12585. },
  12586. selectRow: function (rowIndex) {
  12587. var indexRow = this.indexTable[rowIndex],
  12588. start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
  12589. end = this.getCell(indexRow[this.colsNum - 1].rowIndex, indexRow[this.colsNum - 1].cellIndex),
  12590. range = this.getCellsRange(start, end);
  12591. this.setSelected(range);
  12592. },
  12593. selectTable: function () {
  12594. var tds = this.table.getElementsByTagName("td"),
  12595. range = this.getCellsRange(tds[0], tds[tds.length - 1]);
  12596. this.setSelected(range);
  12597. },
  12598. sortTable: function (sortByCellIndex, compareFn) {
  12599. var table = this.table,
  12600. rows = table.rows,
  12601. trArray = [],
  12602. flag = rows[0].cells[0].tagName === "TH",
  12603. lastRowIndex = 0;
  12604. if (this.selectedTds.length) {
  12605. var range = this.cellsRange,
  12606. len = range.endRowIndex + 1;
  12607. for (var i = range.beginRowIndex; i < len; i++) {
  12608. trArray[i] = rows[i];
  12609. }
  12610. trArray.splice(0, range.beginRowIndex);
  12611. lastRowIndex = (range.endRowIndex + 1) === this.rowsNum ? 0 : range.endRowIndex + 1;
  12612. } else {
  12613. for (var i = 0, len = rows.length; i < len; i++) {
  12614. trArray[i] = rows[i];
  12615. }
  12616. }
  12617. //th不参与排序
  12618. flag && trArray.splice(0, 1);
  12619. trArray = utils.sort(trArray, function (tr1, tr2) {
  12620. var txt = function (node) {
  12621. return node.innerText || node.textContent;
  12622. };
  12623. return compareFn ? (typeof compareFn === "number" ? compareFn : compareFn.call(this, tr1.cells[sortByCellIndex], tr2.cells[sortByCellIndex])) : function () {
  12624. var value1 = txt(tr1.cells[sortByCellIndex]),
  12625. value2 = txt(tr2.cells[sortByCellIndex]);
  12626. return value1.localeCompare(value2);
  12627. }();
  12628. });
  12629. var fragment = table.ownerDocument.createDocumentFragment();
  12630. for (var j = 0, len = trArray.length; j < len; j++) {
  12631. fragment.appendChild(trArray[j]);
  12632. }
  12633. var tbody = table.getElementsByTagName("tbody")[0];
  12634. if (!lastRowIndex) {
  12635. tbody.appendChild(fragment);
  12636. } else {
  12637. tbody.insertBefore(fragment, rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1])
  12638. }
  12639. },
  12640. setBackground: function (cells, value) {
  12641. if (typeof value === "string") {
  12642. utils.each(cells, function (cell) {
  12643. cell.style.backgroundColor = value;
  12644. })
  12645. } else if (typeof value === "object") {
  12646. value = utils.extend({
  12647. repeat: true,
  12648. colorList: ["#ddd", "#fff"]
  12649. }, value);
  12650. var rowIndex = this.getCellInfo(cells[0]).rowIndex,
  12651. count = 0,
  12652. colors = value.colorList,
  12653. getColor = function (list, index, repeat) {
  12654. return list[index] ? list[index] : repeat ? list[index % list.length] : "";
  12655. };
  12656. for (var i = 0, cell; cell = cells[i++];) {
  12657. var cellInfo = this.getCellInfo(cell);
  12658. cell.style.backgroundColor = getColor(colors, ((rowIndex + count) == cellInfo.rowIndex) ? count : ++count, value.repeat);
  12659. }
  12660. }
  12661. },
  12662. removeBackground: function (cells) {
  12663. utils.each(cells, function (cell) {
  12664. cell.style.backgroundColor = "";
  12665. })
  12666. }
  12667. };
  12668. function showError(e) {
  12669. }
  12670. })();
  12671. /**
  12672. * Created with JetBrains PhpStorm.
  12673. * User: taoqili
  12674. * Date: 13-2-20
  12675. * Time: 下午6:25
  12676. * To change this template use File | Settings | File Templates.
  12677. */
  12678. ;
  12679. (function () {
  12680. var UT = UE.UETable,
  12681. getTableItemsByRange = function (editor) {
  12682. return UT.getTableItemsByRange(editor);
  12683. },
  12684. getUETableBySelected = function (editor) {
  12685. return UT.getUETableBySelected(editor)
  12686. },
  12687. getDefaultValue = function (editor, table) {
  12688. return UT.getDefaultValue(editor, table);
  12689. },
  12690. getUETable = function (tdOrTable) {
  12691. return UT.getUETable(tdOrTable);
  12692. };
  12693. UE.commands['inserttable'] = {
  12694. queryCommandState: function () {
  12695. return getTableItemsByRange(this).table ? -1 : 0;
  12696. },
  12697. execCommand: function (cmd, opt) {
  12698. function createTable(opt, tdWidth) {
  12699. var html = [],
  12700. rowsNum = opt.numRows,
  12701. colsNum = opt.numCols;
  12702. for (var r = 0; r < rowsNum; r++) {
  12703. html.push('<tr>');
  12704. for (var c = 0; c < colsNum; c++) {
  12705. html.push('<td width="' + tdWidth + '" vAlign="' + opt.tdvalign + '" >' + (browser.ie ? domUtils.fillChar : '<br/>') + '</td>')
  12706. }
  12707. html.push('</tr>')
  12708. }
  12709. //禁止指定table-width
  12710. return '<table><tbody>' + html.join('') + '</tbody></table>'
  12711. }
  12712. if (!opt) {
  12713. opt = utils.extend({}, {
  12714. numCols: this.options.defaultCols,
  12715. numRows: this.options.defaultRows,
  12716. tdvalign: this.options.tdvalign
  12717. })
  12718. }
  12719. var me = this;
  12720. var range = this.selection.getRange(),
  12721. start = range.startContainer,
  12722. firstParentBlock = domUtils.findParent(start, function (node) {
  12723. return domUtils.isBlockElm(node);
  12724. }, true) || me.body;
  12725. var defaultValue = getDefaultValue(me),
  12726. tableWidth = firstParentBlock.offsetWidth,
  12727. tdWidth = Math.floor(tableWidth / opt.numCols - defaultValue.tdPadding * 2 - defaultValue.tdBorder);
  12728. //todo其他属性
  12729. !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
  12730. me.execCommand("inserthtml", createTable(opt, tdWidth));
  12731. }
  12732. };
  12733. UE.commands['insertparagraphbeforetable'] = {
  12734. queryCommandState: function () {
  12735. return getTableItemsByRange(this).cell ? 0 : -1;
  12736. },
  12737. execCommand: function () {
  12738. var table = getTableItemsByRange(this).table;
  12739. if (table) {
  12740. var p = this.document.createElement("p");
  12741. p.innerHTML = browser.ie ? '&nbsp;' : '<br />';
  12742. table.parentNode.insertBefore(p, table);
  12743. this.selection.getRange().setStart(p, 0).setCursor();
  12744. }
  12745. }
  12746. };
  12747. UE.commands['deletetable'] = {
  12748. queryCommandState: function () {
  12749. var rng = this.selection.getRange();
  12750. return domUtils.findParentByTagName(rng.startContainer, 'table', true) ? 0 : -1;
  12751. },
  12752. execCommand: function (cmd, table) {
  12753. var rng = this.selection.getRange();
  12754. table = table || domUtils.findParentByTagName(rng.startContainer, 'table', true);
  12755. if (table) {
  12756. var next = table.nextSibling;
  12757. if (!next) {
  12758. next = domUtils.createElement(this.document, 'p', {
  12759. 'innerHTML': browser.ie ? domUtils.fillChar : '<br/>'
  12760. });
  12761. table.parentNode.insertBefore(next, table);
  12762. }
  12763. domUtils.remove(table);
  12764. rng = this.selection.getRange();
  12765. if (next.nodeType == 3) {
  12766. rng.setStartBefore(next)
  12767. } else {
  12768. rng.setStart(next, 0)
  12769. }
  12770. rng.setCursor(false, true)
  12771. this.fireEvent("tablehasdeleted")
  12772. }
  12773. }
  12774. };
  12775. UE.commands['cellalign'] = {
  12776. queryCommandState: function () {
  12777. return getSelectedArr(this).length ? 0 : -1
  12778. },
  12779. execCommand: function (cmd, align) {
  12780. var selectedTds = getSelectedArr(this);
  12781. if (selectedTds.length) {
  12782. for (var i = 0, ci; ci = selectedTds[i++];) {
  12783. ci.setAttribute('align', align);
  12784. }
  12785. }
  12786. }
  12787. };
  12788. UE.commands['cellvalign'] = {
  12789. queryCommandState: function () {
  12790. return getSelectedArr(this).length ? 0 : -1;
  12791. },
  12792. execCommand: function (cmd, valign) {
  12793. var selectedTds = getSelectedArr(this);
  12794. if (selectedTds.length) {
  12795. for (var i = 0, ci; ci = selectedTds[i++];) {
  12796. ci.setAttribute('vAlign', valign);
  12797. }
  12798. }
  12799. }
  12800. };
  12801. UE.commands['insertcaption'] = {
  12802. queryCommandState: function () {
  12803. var table = getTableItemsByRange(this).table;
  12804. if (table) {
  12805. return table.getElementsByTagName('caption').length == 0 ? 1 : -1;
  12806. }
  12807. return -1;
  12808. },
  12809. execCommand: function () {
  12810. var table = getTableItemsByRange(this).table;
  12811. if (table) {
  12812. var caption = this.document.createElement('caption');
  12813. caption.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
  12814. table.insertBefore(caption, table.firstChild);
  12815. var range = this.selection.getRange();
  12816. range.setStart(caption, 0).setCursor();
  12817. }
  12818. }
  12819. };
  12820. UE.commands['deletecaption'] = {
  12821. queryCommandState: function () {
  12822. var rng = this.selection.getRange(),
  12823. table = domUtils.findParentByTagName(rng.startContainer, 'table');
  12824. if (table) {
  12825. return table.getElementsByTagName('caption').length == 0 ? -1 : 1;
  12826. }
  12827. return -1;
  12828. },
  12829. execCommand: function () {
  12830. var rng = this.selection.getRange(),
  12831. table = domUtils.findParentByTagName(rng.startContainer, 'table');
  12832. if (table) {
  12833. domUtils.remove(table.getElementsByTagName('caption')[0]);
  12834. var range = this.selection.getRange();
  12835. range.setStart(table.rows[0].cells[0], 0).setCursor();
  12836. }
  12837. }
  12838. };
  12839. UE.commands['inserttitle'] = {
  12840. queryCommandState: function () {
  12841. var table = getTableItemsByRange(this).table;
  12842. if (table) {
  12843. var firstRow = table.rows[0];
  12844. return firstRow.getElementsByTagName('th').length == 0 ? 0 : -1
  12845. }
  12846. return -1;
  12847. },
  12848. execCommand: function () {
  12849. var table = getTableItemsByRange(this).table;
  12850. if (table) {
  12851. getUETable(table).insertRow(0, 'th');
  12852. }
  12853. var th = table.getElementsByTagName('th')[0];
  12854. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  12855. }
  12856. };
  12857. UE.commands['deletetitle'] = {
  12858. queryCommandState: function () {
  12859. var table = getTableItemsByRange(this).table;
  12860. if (table) {
  12861. var firstRow = table.rows[0];
  12862. return firstRow.getElementsByTagName('th').length ? 0 : -1
  12863. }
  12864. return -1;
  12865. },
  12866. execCommand: function () {
  12867. var table = getTableItemsByRange(this).table;
  12868. if (table) {
  12869. domUtils.remove(table.rows[0])
  12870. }
  12871. var td = table.getElementsByTagName('td')[0];
  12872. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  12873. }
  12874. };
  12875. UE.commands["mergeright"] = {
  12876. queryCommandState: function (cmd) {
  12877. var tableItems = getTableItemsByRange(this);
  12878. if (!tableItems.cell) return -1;
  12879. var ut = getUETable(tableItems.table);
  12880. if (ut.selectedTds.length) return -1;
  12881. var cellInfo = ut.getCellInfo(tableItems.cell),
  12882. rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
  12883. if (rightColIndex >= ut.colsNum) return -1;
  12884. var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex];
  12885. return (rightCellInfo.rowIndex == cellInfo.rowIndex
  12886. && rightCellInfo.rowSpan == cellInfo.rowSpan) ? 0 : -1;
  12887. },
  12888. execCommand: function (cmd) {
  12889. var rng = this.selection.getRange(),
  12890. bk = rng.createBookmark(true);
  12891. var cell = getTableItemsByRange(this).cell,
  12892. ut = getUETable(cell);
  12893. ut.mergeRight(cell);
  12894. rng.moveToBookmark(bk).select();
  12895. }
  12896. };
  12897. UE.commands["mergedown"] = {
  12898. queryCommandState: function (cmd) {
  12899. var tableItems = getTableItemsByRange(this),
  12900. cell = tableItems.cell;
  12901. if (!cell || cell.tagName == "TH") return -1;
  12902. var ut = getUETable(tableItems.table);
  12903. if (ut.selectedTds.length)return -1;
  12904. var cellInfo = ut.getCellInfo(tableItems.cell),
  12905. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
  12906. // 如果处于最下边则不能f向右合并
  12907. if (downRowIndex >= ut.rowsNum) return -1;
  12908. var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex];
  12909. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  12910. return (downCellInfo.colIndex == cellInfo.colIndex
  12911. && downCellInfo.colSpan == cellInfo.colSpan) && tableItems.cell.tagName !== 'TH' ? 0 : -1;
  12912. },
  12913. execCommand: function () {
  12914. var rng = this.selection.getRange(),
  12915. bk = rng.createBookmark(true);
  12916. var cell = getTableItemsByRange(this).cell,
  12917. ut = getUETable(cell);
  12918. ut.mergeDown(cell);
  12919. rng.moveToBookmark(bk).select();
  12920. }
  12921. };
  12922. UE.commands["mergecells"] = {
  12923. queryCommandState: function () {
  12924. return getUETableBySelected(this) ? 0 : -1;
  12925. },
  12926. execCommand: function () {
  12927. var ut = getUETableBySelected(this);
  12928. if (ut && ut.selectedTds.length) {
  12929. var cell = ut.selectedTds[0];
  12930. ut.mergeRange();
  12931. var rng = this.selection.getRange();
  12932. if (domUtils.isEmptyBlock(cell)) {
  12933. rng.setStart(cell, 0).collapse(true)
  12934. } else {
  12935. rng.selectNodeContents(cell)
  12936. }
  12937. rng.select();
  12938. }
  12939. }
  12940. };
  12941. UE.commands["insertrow"] = {
  12942. queryCommandState: function () {
  12943. var tableItems = getTableItemsByRange(this),
  12944. cell = tableItems.cell;
  12945. return cell && cell.tagName == "TD" && getUETable(tableItems.table).rowsNum < this.options.maxRowNum ? 0 : -1;
  12946. },
  12947. execCommand: function () {
  12948. var rng = this.selection.getRange(),
  12949. bk = rng.createBookmark(true);
  12950. var tableItems = getTableItemsByRange(this),
  12951. cell = tableItems.cell,
  12952. table = tableItems.table,
  12953. ut = getUETable(table),
  12954. cellInfo = ut.getCellInfo(cell);
  12955. //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
  12956. if (!ut.selectedTds.length) {
  12957. ut.insertRow(cellInfo.rowIndex, cell);
  12958. } else {
  12959. var range = ut.cellsRange;
  12960. for (var i = 0, len = range.endRowIndex - range.beginRowIndex + 1; i < len; i++) {
  12961. ut.insertRow(range.beginRowIndex, cell);
  12962. }
  12963. }
  12964. rng.moveToBookmark(bk).select();
  12965. if (table.getAttribute("interlaced") === "enabled")this.fireEvent("interlacetable", table);
  12966. }
  12967. };
  12968. //后插入行
  12969. UE.commands["insertrownext"] = {
  12970. queryCommandState: function () {
  12971. var tableItems = getTableItemsByRange(this),
  12972. cell = tableItems.cell;
  12973. return cell && (cell.tagName == "TD") && getUETable(tableItems.table).rowsNum < this.options.maxRowNum ? 0 : -1;
  12974. },
  12975. execCommand: function () {
  12976. var rng = this.selection.getRange(),
  12977. bk = rng.createBookmark(true);
  12978. var tableItems = getTableItemsByRange(this),
  12979. cell = tableItems.cell,
  12980. table = tableItems.table,
  12981. ut = getUETable(table),
  12982. cellInfo = ut.getCellInfo(cell);
  12983. //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
  12984. if (!ut.selectedTds.length) {
  12985. ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell);
  12986. } else {
  12987. var range = ut.cellsRange;
  12988. for (var i = 0, len = range.endRowIndex - range.beginRowIndex + 1; i < len; i++) {
  12989. ut.insertRow(range.endRowIndex + 1, cell);
  12990. }
  12991. }
  12992. rng.moveToBookmark(bk).select();
  12993. if (table.getAttribute("interlaced") === "enabled")this.fireEvent("interlacetable", table);
  12994. }
  12995. };
  12996. UE.commands["deleterow"] = {
  12997. queryCommandState: function () {
  12998. var tableItems = getTableItemsByRange(this);
  12999. if (!tableItems.cell) {
  13000. return -1;
  13001. }
  13002. },
  13003. execCommand: function () {
  13004. var cell = getTableItemsByRange(this).cell,
  13005. ut = getUETable(cell),
  13006. cellsRange = ut.cellsRange,
  13007. cellInfo = ut.getCellInfo(cell),
  13008. preCell = ut.getVSideCell(cell),
  13009. nextCell = ut.getVSideCell(cell, true),
  13010. rng = this.selection.getRange();
  13011. if (utils.isEmptyObject(cellsRange)) {
  13012. ut.deleteRow(cellInfo.rowIndex);
  13013. } else {
  13014. for (var i = cellsRange.beginRowIndex; i < cellsRange.endRowIndex + 1; i++) {
  13015. ut.deleteRow(cellsRange.beginRowIndex);
  13016. }
  13017. }
  13018. var table = ut.table;
  13019. if (!table.getElementsByTagName('td').length) {
  13020. var nextSibling = table.nextSibling;
  13021. domUtils.remove(table);
  13022. if (nextSibling) {
  13023. rng.setStart(nextSibling, 0).setCursor(false, true);
  13024. }
  13025. } else {
  13026. if (cellInfo.rowSpan == 1 || cellInfo.rowSpan == cellsRange.endRowIndex - cellsRange.beginRowIndex + 1) {
  13027. if (nextCell || preCell) rng.selectNodeContents(nextCell || preCell).setCursor(false, true);
  13028. } else {
  13029. var newCell = ut.getCell(cellInfo.rowIndex, ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex);
  13030. if (newCell) rng.selectNodeContents(newCell).setCursor(false, true);
  13031. }
  13032. }
  13033. if (table.getAttribute("interlaced") === "enabled")this.fireEvent("interlacetable", table);
  13034. }
  13035. };
  13036. UE.commands["insertcol"] = {
  13037. queryCommandState: function (cmd) {
  13038. var tableItems = getTableItemsByRange(this),
  13039. cell = tableItems.cell;
  13040. return cell && (cell.tagName == "TD" || cell.tagName == 'TH') && getUETable(tableItems.table).colsNum < this.options.maxColNum ? 0 : -1;
  13041. },
  13042. execCommand: function (cmd) {
  13043. var rng = this.selection.getRange(),
  13044. bk = rng.createBookmark(true);
  13045. if (this.queryCommandState(cmd) == -1)return;
  13046. var cell = getTableItemsByRange(this).cell,
  13047. ut = getUETable(cell),
  13048. cellInfo = ut.getCellInfo(cell);
  13049. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
  13050. if (!ut.selectedTds.length) {
  13051. ut.insertCol(cellInfo.colIndex, cell);
  13052. } else {
  13053. var range = ut.cellsRange;
  13054. for (var i = 0, len = range.endColIndex - range.beginColIndex + 1; i < len; i++) {
  13055. ut.insertCol(range.beginColIndex, cell);
  13056. }
  13057. }
  13058. rng.moveToBookmark(bk).select(true);
  13059. }
  13060. };
  13061. UE.commands["insertcolnext"] = {
  13062. queryCommandState: function () {
  13063. var tableItems = getTableItemsByRange(this),
  13064. cell = tableItems.cell;
  13065. return cell && getUETable(tableItems.table).colsNum < this.options.maxColNum ? 0 : -1;
  13066. },
  13067. execCommand: function () {
  13068. var rng = this.selection.getRange(),
  13069. bk = rng.createBookmark(true);
  13070. var cell = getTableItemsByRange(this).cell,
  13071. ut = getUETable(cell),
  13072. cellInfo = ut.getCellInfo(cell);
  13073. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
  13074. if (!ut.selectedTds.length) {
  13075. ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell);
  13076. } else {
  13077. var range = ut.cellsRange;
  13078. for (var i = 0, len = range.endColIndex - range.beginColIndex + 1; i < len; i++) {
  13079. ut.insertCol(range.endColIndex + 1, cell);
  13080. }
  13081. }
  13082. rng.moveToBookmark(bk).select();
  13083. }
  13084. };
  13085. UE.commands["deletecol"] = {
  13086. queryCommandState: function () {
  13087. var tableItems = getTableItemsByRange(this);
  13088. if (!tableItems.cell) return -1;
  13089. },
  13090. execCommand: function () {
  13091. var cell = getTableItemsByRange(this).cell,
  13092. ut = getUETable(cell),
  13093. range = ut.cellsRange,
  13094. cellInfo = ut.getCellInfo(cell),
  13095. preCell = ut.getHSideCell(cell),
  13096. nextCell = ut.getHSideCell(cell, true);
  13097. if (utils.isEmptyObject(range)) {
  13098. ut.deleteCol(cellInfo.colIndex);
  13099. } else {
  13100. for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
  13101. ut.deleteCol(range.beginColIndex);
  13102. }
  13103. }
  13104. var table = ut.table,
  13105. rng = this.selection.getRange();
  13106. if (!table.getElementsByTagName('td').length) {
  13107. var nextSibling = table.nextSibling;
  13108. domUtils.remove(table);
  13109. if (nextSibling) {
  13110. rng.setStart(nextSibling, 0).setCursor(false, true);
  13111. }
  13112. } else {
  13113. if (domUtils.inDoc(cell, this.document)) {
  13114. rng.setStart(cell, 0).setCursor(false, true);
  13115. } else {
  13116. if (nextCell && domUtils.inDoc(nextCell, this.document)) {
  13117. rng.selectNodeContents(nextCell).setCursor(false, true);
  13118. } else {
  13119. if (preCell && domUtils.inDoc(preCell, this.document)) {
  13120. rng.selectNodeContents(preCell).setCursor(true, true);
  13121. }
  13122. }
  13123. }
  13124. }
  13125. }
  13126. };
  13127. UE.commands["splittocells"] = {
  13128. queryCommandState: function () {
  13129. var tableItems = getTableItemsByRange(this),
  13130. cell = tableItems.cell;
  13131. if (!cell) return -1;
  13132. var ut = getUETable(tableItems.table);
  13133. if (ut.selectedTds.length > 0) return -1;
  13134. return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1;
  13135. },
  13136. execCommand: function () {
  13137. var rng = this.selection.getRange(),
  13138. bk = rng.createBookmark(true);
  13139. var cell = getTableItemsByRange(this).cell,
  13140. ut = getUETable(cell);
  13141. ut.splitToCells(cell);
  13142. rng.moveToBookmark(bk).select();
  13143. }
  13144. };
  13145. UE.commands["splittorows"] = {
  13146. queryCommandState: function () {
  13147. var tableItems = getTableItemsByRange(this),
  13148. cell = tableItems.cell;
  13149. if (!cell) return -1;
  13150. var ut = getUETable(tableItems.table);
  13151. if (ut.selectedTds.length > 0) return -1;
  13152. return cell && cell.rowSpan > 1 ? 0 : -1;
  13153. },
  13154. execCommand: function () {
  13155. var rng = this.selection.getRange(),
  13156. bk = rng.createBookmark(true);
  13157. var cell = getTableItemsByRange(this).cell,
  13158. ut = getUETable(cell);
  13159. ut.splitToRows(cell);
  13160. rng.moveToBookmark(bk).select();
  13161. }
  13162. };
  13163. UE.commands["splittocols"] = {
  13164. queryCommandState: function () {
  13165. var tableItems = getTableItemsByRange(this),
  13166. cell = tableItems.cell;
  13167. if (!cell) return -1;
  13168. var ut = getUETable(tableItems.table);
  13169. if (ut.selectedTds.length > 0) return -1;
  13170. return cell && cell.colSpan > 1 ? 0 : -1;
  13171. },
  13172. execCommand: function () {
  13173. var rng = this.selection.getRange(),
  13174. bk = rng.createBookmark(true);
  13175. var cell = getTableItemsByRange(this).cell,
  13176. ut = getUETable(cell);
  13177. ut.splitToCols(cell);
  13178. rng.moveToBookmark(bk).select();
  13179. }
  13180. };
  13181. UE.commands["adaptbytext"] =
  13182. UE.commands["adaptbywindow"] = {
  13183. queryCommandState: function () {
  13184. return getTableItemsByRange(this).table ? 0 : -1
  13185. },
  13186. execCommand: function (cmd) {
  13187. var tableItems = getTableItemsByRange(this),
  13188. table = tableItems.table;
  13189. if (table) {
  13190. if (cmd == 'adaptbywindow') {
  13191. resetTdWidth(table, this);
  13192. } else {
  13193. var cells = domUtils.getElementsByTagName(table, "td th");
  13194. utils.each(cells, function (cell) {
  13195. cell.removeAttribute("width");
  13196. });
  13197. table.removeAttribute("width");
  13198. }
  13199. }
  13200. }
  13201. };
  13202. //平均分配各列
  13203. UE.commands['averagedistributecol'] = {
  13204. queryCommandState: function () {
  13205. var ut = getUETableBySelected(this);
  13206. if (!ut) return -1;
  13207. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  13208. },
  13209. execCommand: function (cmd) {
  13210. var me = this,
  13211. ut = getUETableBySelected(me);
  13212. function getAverageWidth() {
  13213. var tb = ut.table,
  13214. averageWidth, sumWidth = 0, colsNum = 0,
  13215. tbAttr = getDefaultValue(me, tb);
  13216. if (ut.isFullRow()) {
  13217. sumWidth = tb.offsetWidth;
  13218. colsNum = ut.colsNum;
  13219. } else {
  13220. var begin = ut.cellsRange.beginColIndex,
  13221. end = ut.cellsRange.endColIndex,
  13222. node;
  13223. for (var i = begin; i <= end;) {
  13224. node = ut.selectedTds[i];
  13225. sumWidth += node.offsetWidth;
  13226. i += node.colSpan;
  13227. colsNum += 1;
  13228. }
  13229. }
  13230. averageWidth = Math.ceil(sumWidth / colsNum) - tbAttr.tdBorder * 2 - tbAttr.tdPadding * 2;
  13231. return averageWidth;
  13232. }
  13233. function setAverageWidth(averageWidth) {
  13234. utils.each(domUtils.getElementsByTagName(ut.table, "th"), function (node) {
  13235. node.setAttribute("width", "");
  13236. });
  13237. var cells = ut.isFullRow() ? domUtils.getElementsByTagName(ut.table, "td") : ut.selectedTds;
  13238. utils.each(cells, function (node) {
  13239. if (node.colSpan == 1) {
  13240. node.setAttribute("width", averageWidth);
  13241. }
  13242. });
  13243. }
  13244. if (ut && ut.selectedTds.length) {
  13245. setAverageWidth(getAverageWidth());
  13246. }
  13247. }
  13248. };
  13249. //平均分配各行
  13250. UE.commands['averagedistributerow'] = {
  13251. queryCommandState: function () {
  13252. var ut = getUETableBySelected(this);
  13253. if (!ut) return -1;
  13254. if (ut.selectedTds && /th/ig.test(ut.selectedTds[0].tagName)) return -1;
  13255. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  13256. },
  13257. execCommand: function (cmd) {
  13258. var me = this,
  13259. ut = getUETableBySelected(me);
  13260. function getAverageHeight() {
  13261. var averageHeight, rowNum, sumHeight = 0,
  13262. tb = ut.table,
  13263. tbAttr = getDefaultValue(me, tb),
  13264. tdpadding = parseInt(domUtils.getComputedStyle(tb.getElementsByTagName('td')[0], "padding-top"));
  13265. if (ut.isFullCol()) {
  13266. var captionArr = domUtils.getElementsByTagName(tb, "caption"),
  13267. thArr = domUtils.getElementsByTagName(tb, "th"),
  13268. captionHeight, thHeight;
  13269. if (captionArr.length > 0) {
  13270. captionHeight = captionArr[0].offsetHeight;
  13271. }
  13272. if (thArr.length > 0) {
  13273. thHeight = thArr[0].offsetHeight;
  13274. }
  13275. sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0);
  13276. rowNum = thArr.length == 0 ? ut.rowsNum : (ut.rowsNum - 1);
  13277. } else {
  13278. var begin = ut.cellsRange.beginRowIndex,
  13279. end = ut.cellsRange.endRowIndex,
  13280. count = 0,
  13281. trs = domUtils.getElementsByTagName(tb, "tr");
  13282. for (var i = begin; i <= end; i++) {
  13283. sumHeight += trs[i].offsetHeight;
  13284. count += 1;
  13285. }
  13286. rowNum = count;
  13287. }
  13288. //ie8下是混杂模式
  13289. if (browser.ie && browser.version < 9) {
  13290. averageHeight = Math.ceil(sumHeight / rowNum);
  13291. } else {
  13292. averageHeight = Math.ceil(sumHeight / rowNum) - tbAttr.tdBorder * 2 - tdpadding * 2;
  13293. }
  13294. return averageHeight;
  13295. }
  13296. function setAverageHeight(averageHeight) {
  13297. var cells = ut.isFullCol() ? domUtils.getElementsByTagName(ut.table, "td") : ut.selectedTds;
  13298. utils.each(cells, function (node) {
  13299. if (node.rowSpan == 1) {
  13300. node.setAttribute("height", averageHeight);
  13301. }
  13302. });
  13303. }
  13304. if (ut && ut.selectedTds.length) {
  13305. setAverageHeight(getAverageHeight());
  13306. }
  13307. }
  13308. };
  13309. //单元格对齐方式
  13310. UE.commands['cellalignment'] = {
  13311. queryCommandState: function () {
  13312. return getTableItemsByRange(this).table ? 0 : -1
  13313. },
  13314. execCommand: function (cmd, data) {
  13315. var me = this,
  13316. ut = getUETableBySelected(me);
  13317. if (!ut) {
  13318. var start = me.selection.getStart(),
  13319. cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  13320. if (!/caption/ig.test(cell.tagName)) {
  13321. domUtils.setAttributes(cell, data);
  13322. } else {
  13323. cell.style.textAlign = data.align;
  13324. cell.style.verticalAlign = data.vAlign;
  13325. }
  13326. me.selection.getRange().setCursor(true);
  13327. } else {
  13328. utils.each(ut.selectedTds, function (cell) {
  13329. domUtils.setAttributes(cell, data);
  13330. });
  13331. }
  13332. },
  13333. /**
  13334. * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
  13335. * @see UE.UETable.getTableCellAlignState
  13336. */
  13337. queryCommandValue: function (cmd) {
  13338. var activeMenuCell = getTableItemsByRange(this).cell;
  13339. if (!activeMenuCell) {
  13340. activeMenuCell = getSelectedArr(this)[0];
  13341. }
  13342. if (!activeMenuCell) {
  13343. return null;
  13344. } else {
  13345. //获取同时选中的其他单元格
  13346. var cells = UE.UETable.getUETable(activeMenuCell).selectedTds;
  13347. !cells.length && ( cells = activeMenuCell );
  13348. return UE.UETable.getTableCellAlignState(cells);
  13349. }
  13350. }
  13351. };
  13352. //表格对齐方式
  13353. UE.commands['tablealignment'] = {
  13354. queryCommandState: function () {
  13355. if (browser.ie && browser.version < 8) {
  13356. return -1;
  13357. }
  13358. return getTableItemsByRange(this).table ? 0 : -1
  13359. },
  13360. execCommand: function (cmd, value) {
  13361. var me = this,
  13362. start = me.selection.getStart(),
  13363. table = start && domUtils.findParentByTagName(start, ["table"], true);
  13364. if (table) {
  13365. table.setAttribute("align", value);
  13366. }
  13367. }
  13368. };
  13369. //表格属性
  13370. UE.commands['edittable'] = {
  13371. queryCommandState: function () {
  13372. return getTableItemsByRange(this).table ? 0 : -1
  13373. },
  13374. execCommand: function (cmd, color) {
  13375. var rng = this.selection.getRange(),
  13376. table = domUtils.findParentByTagName(rng.startContainer, 'table');
  13377. if (table) {
  13378. var arr = domUtils.getElementsByTagName(table, "td").concat(
  13379. domUtils.getElementsByTagName(table, "th"),
  13380. domUtils.getElementsByTagName(table, "caption")
  13381. );
  13382. utils.each(arr, function (node) {
  13383. node.style.borderColor = color;
  13384. });
  13385. }
  13386. }
  13387. };
  13388. //单元格属性
  13389. UE.commands['edittd'] = {
  13390. queryCommandState: function () {
  13391. return getTableItemsByRange(this).table ? 0 : -1
  13392. },
  13393. execCommand: function (cmd, bkColor) {
  13394. var me = this,
  13395. ut = getUETableBySelected(me);
  13396. if (!ut) {
  13397. var start = me.selection.getStart(),
  13398. cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  13399. if (cell) {
  13400. cell.style.backgroundColor = bkColor;
  13401. }
  13402. } else {
  13403. utils.each(ut.selectedTds, function (cell) {
  13404. cell.style.backgroundColor = bkColor;
  13405. });
  13406. }
  13407. }
  13408. };
  13409. UE.commands['sorttable'] = {
  13410. queryCommandState: function () {
  13411. var me = this,
  13412. tableItems = getTableItemsByRange(me);
  13413. if (!tableItems.cell) return -1;
  13414. var table = tableItems.table,
  13415. cells = table.getElementsByTagName("td");
  13416. for (var i = 0, cell; cell = cells[i++];) {
  13417. if (cell.rowSpan != 1 || cell.colSpan != 1) return -1;
  13418. }
  13419. return 0;
  13420. },
  13421. execCommand: function (cmd, fn) {
  13422. var me = this,
  13423. range = me.selection.getRange(),
  13424. bk = range.createBookmark(true),
  13425. tableItems = getTableItemsByRange(me),
  13426. cell = tableItems.cell,
  13427. ut = getUETable(tableItems.table),
  13428. cellInfo = ut.getCellInfo(cell);
  13429. ut.sortTable(cellInfo.cellIndex, fn);
  13430. range.moveToBookmark(bk).select();
  13431. }
  13432. };
  13433. UE.commands["enablesort"] = UE.commands["disablesort"] = {
  13434. queryCommandState: function () {
  13435. return getTableItemsByRange(this).table ? 0 : -1;
  13436. },
  13437. execCommand: function (cmd) {
  13438. var table = getTableItemsByRange(this).table;
  13439. table.setAttribute("data-sort", cmd == "enablesort" ? "sortEnabled" : "sortDisabled");
  13440. }
  13441. };
  13442. UE.commands["settablebackground"] = {
  13443. queryCommandState: function () {
  13444. return getSelectedArr(this).length > 1 ? 0 : -1;
  13445. },
  13446. execCommand: function (cmd, value) {
  13447. var table, cells, ut;
  13448. cells = getSelectedArr(this);
  13449. ut = getUETable(cells[0]);
  13450. ut.setBackground(cells, value);
  13451. }
  13452. };
  13453. UE.commands["cleartablebackground"] = {
  13454. queryCommandState: function () {
  13455. var cells = getSelectedArr(this);
  13456. if (!cells.length)return -1;
  13457. for (var i = 0, cell; cell = cells[i++];) {
  13458. if (cell.style.backgroundColor !== "") return 0;
  13459. }
  13460. return -1;
  13461. },
  13462. execCommand: function () {
  13463. var cells = getSelectedArr(this),
  13464. ut = getUETable(cells[0]);
  13465. ut.removeBackground(cells);
  13466. }
  13467. };
  13468. UE.commands["interlacetable"] = UE.commands["uninterlacetable"] = {
  13469. queryCommandState: function (cmd) {
  13470. var table = getTableItemsByRange(this).table;
  13471. if (!table) return -1;
  13472. var interlaced = table.getAttribute("interlaced");
  13473. if (cmd == "interlacetable") {
  13474. //TODO 待定
  13475. //是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
  13476. return (interlaced === "enabled") ? -1 : 0;
  13477. } else {
  13478. return (!interlaced || interlaced === "disabled") ? -1 : 0;
  13479. }
  13480. },
  13481. execCommand: function (cmd, classList) {
  13482. var table = getTableItemsByRange(this).table;
  13483. if (cmd == "interlacetable") {
  13484. table.setAttribute("interlaced", "enabled");
  13485. this.fireEvent("interlacetable", table, classList);
  13486. } else {
  13487. table.setAttribute("interlaced", "disabled");
  13488. this.fireEvent("uninterlacetable", table);
  13489. }
  13490. }
  13491. };
  13492. function resetTdWidth(table, editor) {
  13493. var tds = table.getElementsByTagName("td");
  13494. utils.each(tds, function (td) {
  13495. td.removeAttribute("width");
  13496. });
  13497. table.setAttribute('width', getTableWidth(editor, true, getDefaultValue(editor, table)));
  13498. setTimeout(function () {
  13499. utils.each(tds, function (td) {
  13500. (td.colSpan == 1) && td.setAttribute("width", td.offsetWidth + "");
  13501. })
  13502. }, 0);
  13503. }
  13504. function getTableWidth(editor, needIEHack, defaultValue) {
  13505. var body = editor.body;
  13506. return body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (editor.options.offsetWidth || 0);
  13507. }
  13508. function getSelectedArr(editor) {
  13509. var cell = getTableItemsByRange(editor).cell;
  13510. if (cell) {
  13511. var ut = getUETable(cell);
  13512. return ut.selectedTds.length ? ut.selectedTds : [cell];
  13513. } else {
  13514. return [];
  13515. }
  13516. }
  13517. })();
  13518. /**
  13519. * Created with JetBrains PhpStorm.
  13520. * User: taoqili
  13521. * Date: 12-10-12
  13522. * Time: 上午10:05
  13523. * To change this template use File | Settings | File Templates.
  13524. */
  13525. UE.plugins['table'] = function () {
  13526. var me = this,
  13527. tabTimer = null,
  13528. //拖动计时器
  13529. tableDragTimer = null,
  13530. //双击计时器
  13531. tableResizeTimer = null,
  13532. //单元格最小宽度
  13533. cellMinWidth = 5,
  13534. isInResizeBuffer = false,
  13535. //单元格边框大小
  13536. cellBorderWidth = 5,
  13537. //鼠标偏移距离
  13538. offsetOfTableCell = 10,
  13539. //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
  13540. singleClickState = 0,
  13541. userActionStatus = null,
  13542. //双击允许的时间范围
  13543. dblclickTime = 360,
  13544. UT = UE.UETable,
  13545. getUETable = function (tdOrTable) {
  13546. return UT.getUETable(tdOrTable);
  13547. },
  13548. getUETableBySelected = function (editor) {
  13549. return UT.getUETableBySelected(editor);
  13550. },
  13551. getDefaultValue = function (editor, table) {
  13552. return UT.getDefaultValue(editor, table);
  13553. },
  13554. removeSelectedClass = function (cells) {
  13555. return UT.removeSelectedClass(cells);
  13556. };
  13557. function showError(e) {
  13558. // throw e;
  13559. }
  13560. me.ready(function () {
  13561. var me = this;
  13562. var orgGetText = me.selection.getText;
  13563. me.selection.getText = function () {
  13564. var table = getUETableBySelected(me);
  13565. if (table) {
  13566. var str = '';
  13567. utils.each(table.selectedTds, function (td) {
  13568. str += td[browser.ie ? 'innerText' : 'textContent'];
  13569. })
  13570. return str;
  13571. } else {
  13572. return orgGetText.call(me.selection)
  13573. }
  13574. }
  13575. })
  13576. //处理拖动及框选相关方法
  13577. var startTd = null, //鼠标按下时的锚点td
  13578. currentTd = null, //当前鼠标经过时的td
  13579. onDrag = "", //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
  13580. onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
  13581. dragButton = null,
  13582. dragOver = false,
  13583. dragLine = null, //模拟的拖动线
  13584. dragTd = null; //发生拖动的目标td
  13585. var mousedown = false,
  13586. //todo 判断混乱模式
  13587. needIEHack = true;
  13588. me.setOpt({
  13589. 'maxColNum': 20,
  13590. 'maxRowNum': 100,
  13591. 'defaultCols': 5,
  13592. 'defaultRows': 5,
  13593. 'tdvalign': 'top',
  13594. 'cursorpath': me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
  13595. 'tableDragable': false,
  13596. 'classList': ["ue-table-interlace-color-single", "ue-table-interlace-color-double"]
  13597. });
  13598. me.getUETable = getUETable;
  13599. var commands = {
  13600. 'deletetable': 1,
  13601. 'inserttable': 1,
  13602. 'cellvalign': 1,
  13603. 'insertcaption': 1,
  13604. 'deletecaption': 1,
  13605. 'inserttitle': 1,
  13606. 'deletetitle': 1,
  13607. "mergeright": 1,
  13608. "mergedown": 1,
  13609. "mergecells": 1,
  13610. "insertrow": 1,
  13611. "insertrownext": 1,
  13612. "deleterow": 1,
  13613. "insertcol": 1,
  13614. "insertcolnext": 1,
  13615. "deletecol": 1,
  13616. "splittocells": 1,
  13617. "splittorows": 1,
  13618. "splittocols": 1,
  13619. "adaptbytext": 1,
  13620. "adaptbywindow": 1,
  13621. "adaptbycustomer": 1,
  13622. "insertparagraph": 1,
  13623. "insertparagraphbeforetable": 1,
  13624. "averagedistributecol": 1,
  13625. "averagedistributerow": 1
  13626. };
  13627. me.ready(function () {
  13628. utils.cssRule('table',
  13629. //选中的td上的样式
  13630. '.selectTdClass{background-color:#edf5fa !important}' +
  13631. 'table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}' +
  13632. //插入的表格的默认样式
  13633. 'table{margin-bottom:10px;border-collapse:collapse;display:table;}' +
  13634. 'td,th{padding: 5px 10px;border: 1px solid #DDD;}' +
  13635. 'caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}' +
  13636. 'th{border-top:2px solid #BBB;background:#F7F7F7;}' +
  13637. '.ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }' +
  13638. 'td p{margin:0;padding:0;}', me.document);
  13639. var tableCopyList, isFullCol, isFullRow;
  13640. //注册del/backspace事件
  13641. me.addListener('keydown', function (cmd, evt) {
  13642. var me = this;
  13643. var keyCode = evt.keyCode || evt.which;
  13644. if (keyCode == 8) {
  13645. var ut = getUETableBySelected(me);
  13646. if (ut && ut.selectedTds.length) {
  13647. if (ut.isFullCol()) {
  13648. me.execCommand('deletecol')
  13649. } else if (ut.isFullRow()) {
  13650. me.execCommand('deleterow')
  13651. } else {
  13652. me.fireEvent('delcells');
  13653. }
  13654. domUtils.preventDefault(evt);
  13655. }
  13656. var caption = domUtils.findParentByTagName(me.selection.getStart(), 'caption', true),
  13657. range = me.selection.getRange();
  13658. if (range.collapsed && caption && isEmptyBlock(caption)) {
  13659. me.fireEvent('saveScene');
  13660. var table = caption.parentNode;
  13661. domUtils.remove(caption);
  13662. if (table) {
  13663. range.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  13664. }
  13665. me.fireEvent('saveScene');
  13666. }
  13667. }
  13668. if (keyCode == 46) {
  13669. ut = getUETableBySelected(me);
  13670. if (ut) {
  13671. me.fireEvent('saveScene');
  13672. for (var i = 0, ci; ci = ut.selectedTds[i++];) {
  13673. domUtils.fillNode(me.document, ci)
  13674. }
  13675. me.fireEvent('saveScene');
  13676. domUtils.preventDefault(evt);
  13677. }
  13678. }
  13679. if (keyCode == 13) {
  13680. var rng = me.selection.getRange(),
  13681. caption = domUtils.findParentByTagName(rng.startContainer, 'caption', true);
  13682. if (caption) {
  13683. var table = domUtils.findParentByTagName(caption, 'table');
  13684. if (!rng.collapsed) {
  13685. rng.deleteContents();
  13686. me.fireEvent('saveScene');
  13687. } else {
  13688. if (caption) {
  13689. rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  13690. }
  13691. }
  13692. domUtils.preventDefault(evt);
  13693. return;
  13694. }
  13695. if (rng.collapsed) {
  13696. var table = domUtils.findParentByTagName(rng.startContainer, 'table');
  13697. if (table) {
  13698. var cell = table.rows[0].cells[0],
  13699. start = domUtils.findParentByTagName(me.selection.getStart(), ['td', 'th'], true),
  13700. preNode = table.previousSibling;
  13701. if (cell === start && (!preNode || preNode.nodeType == 1 && preNode.tagName == 'TABLE' ) && domUtils.isStartInblock(rng)) {
  13702. var first = domUtils.findParent(me.selection.getStart(), function (n) {
  13703. return domUtils.isBlockElm(n)
  13704. }, true);
  13705. if (first && ( /t(h|d)/i.test(first.tagName) || first === start.firstChild )) {
  13706. me.execCommand('insertparagraphbeforetable');
  13707. domUtils.preventDefault(evt);
  13708. }
  13709. }
  13710. }
  13711. }
  13712. }
  13713. if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == '67') {
  13714. tableCopyList = null;
  13715. var ut = getUETableBySelected(me);
  13716. if (ut) {
  13717. var tds = ut.selectedTds;
  13718. isFullCol = ut.isFullCol();
  13719. isFullRow = ut.isFullRow();
  13720. tableCopyList = [
  13721. [ut.cloneCell(tds[0], null, true)]
  13722. ];
  13723. for (var i = 1, ci; ci = tds[i]; i++) {
  13724. if (ci.parentNode !== tds[i - 1].parentNode) {
  13725. tableCopyList.push([ut.cloneCell(ci, null, true)]);
  13726. } else {
  13727. tableCopyList[tableCopyList.length - 1].push(ut.cloneCell(ci, null, true));
  13728. }
  13729. }
  13730. }
  13731. }
  13732. });
  13733. me.addListener("tablehasdeleted", function () {
  13734. toggleDraggableState(this, false, "", null);
  13735. if (dragButton)domUtils.remove(dragButton);
  13736. });
  13737. me.addListener('beforepaste', function (cmd, html) {
  13738. var me = this;
  13739. var rng = me.selection.getRange();
  13740. if (domUtils.findParentByTagName(rng.startContainer, 'caption', true)) {
  13741. var div = me.document.createElement("div");
  13742. div.innerHTML = html.html;
  13743. html.html = div[browser.ie ? 'innerText' : 'textContent'];
  13744. return;
  13745. }
  13746. var table = getUETableBySelected(me);
  13747. if (tableCopyList) {
  13748. me.fireEvent('saveScene');
  13749. var rng = me.selection.getRange();
  13750. var td = domUtils.findParentByTagName(rng.startContainer, ['td', 'th'], true), tmpNode, preNode;
  13751. if (td) {
  13752. var ut = getUETable(td);
  13753. if (isFullRow) {
  13754. var rowIndex = ut.getCellInfo(td).rowIndex;
  13755. if (td.tagName == 'TH') {
  13756. rowIndex++;
  13757. }
  13758. for (var i = 0, ci; ci = tableCopyList[i++];) {
  13759. var tr = ut.insertRow(rowIndex++, "td");
  13760. for (var j = 0, cj; cj = ci[j]; j++) {
  13761. var cell = tr.cells[j];
  13762. if (!cell) {
  13763. cell = tr.insertCell(j)
  13764. }
  13765. cell.innerHTML = cj.innerHTML;
  13766. cj.getAttribute('width') && cell.setAttribute('width', cj.getAttribute('width'));
  13767. cj.getAttribute('vAlign') && cell.setAttribute('vAlign', cj.getAttribute('vAlign'));
  13768. cj.getAttribute('align') && cell.setAttribute('align', cj.getAttribute('align'));
  13769. cj.style.cssText && (cell.style.cssText = cj.style.cssText)
  13770. }
  13771. for (var j = 0, cj; cj = tr.cells[j]; j++) {
  13772. if (!ci[j])
  13773. break;
  13774. cj.innerHTML = ci[j].innerHTML;
  13775. ci[j].getAttribute('width') && cj.setAttribute('width', ci[j].getAttribute('width'));
  13776. ci[j].getAttribute('vAlign') && cj.setAttribute('vAlign', ci[j].getAttribute('vAlign'));
  13777. ci[j].getAttribute('align') && cj.setAttribute('align', ci[j].getAttribute('align'));
  13778. ci[j].style.cssText && (cj.style.cssText = ci[j].style.cssText)
  13779. }
  13780. }
  13781. } else {
  13782. if (isFullCol) {
  13783. cellInfo = ut.getCellInfo(td);
  13784. var maxColNum = 0;
  13785. for (var j = 0, ci = tableCopyList[0], cj; cj = ci[j++];) {
  13786. maxColNum += cj.colSpan || 1;
  13787. }
  13788. me.__hasEnterExecCommand = true;
  13789. for (i = 0; i < maxColNum; i++) {
  13790. me.execCommand('insertcol');
  13791. }
  13792. me.__hasEnterExecCommand = false;
  13793. td = ut.table.rows[0].cells[cellInfo.cellIndex];
  13794. if (td.tagName == 'TH') {
  13795. td = ut.table.rows[1].cells[cellInfo.cellIndex];
  13796. }
  13797. }
  13798. for (var i = 0, ci; ci = tableCopyList[i++];) {
  13799. tmpNode = td;
  13800. for (var j = 0, cj; cj = ci[j++];) {
  13801. if (td) {
  13802. td.innerHTML = cj.innerHTML;
  13803. //todo 定制处理
  13804. cj.getAttribute('width') && td.setAttribute('width', cj.getAttribute('width'));
  13805. cj.getAttribute('vAlign') && td.setAttribute('vAlign', cj.getAttribute('vAlign'));
  13806. cj.getAttribute('align') && td.setAttribute('align', cj.getAttribute('align'));
  13807. cj.style.cssText && (td.style.cssText = cj.style.cssText);
  13808. preNode = td;
  13809. td = td.nextSibling;
  13810. } else {
  13811. var cloneTd = cj.cloneNode(true);
  13812. domUtils.removeAttributes(cloneTd, ['class', 'rowSpan', 'colSpan']);
  13813. preNode.parentNode.appendChild(cloneTd)
  13814. }
  13815. }
  13816. td = ut.getNextCell(tmpNode, true, true);
  13817. if (!tableCopyList[i])
  13818. break;
  13819. if (!td) {
  13820. var cellInfo = ut.getCellInfo(tmpNode);
  13821. ut.table.insertRow(ut.table.rows.length);
  13822. ut.update();
  13823. td = ut.getVSideCell(tmpNode, true);
  13824. }
  13825. }
  13826. }
  13827. ut.update();
  13828. } else {
  13829. table = me.document.createElement('table');
  13830. for (var i = 0, ci; ci = tableCopyList[i++];) {
  13831. var tr = table.insertRow(table.rows.length);
  13832. for (var j = 0, cj; cj = ci[j++];) {
  13833. cloneTd = UT.cloneCell(cj, null, true);
  13834. domUtils.removeAttributes(cloneTd, ['class']);
  13835. tr.appendChild(cloneTd)
  13836. }
  13837. if (j == 2 && cloneTd.rowSpan > 1) {
  13838. cloneTd.rowSpan = 1;
  13839. }
  13840. }
  13841. var defaultValue = getDefaultValue(me),
  13842. width = me.body.offsetWidth -
  13843. (needIEHack ? parseInt(domUtils.getComputedStyle(me.body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (me.options.offsetWidth || 0);
  13844. me.execCommand('insertHTML', '<table ' +
  13845. ( isFullCol && isFullRow ? 'width="' + width + '"' : '') +
  13846. '>' + table.innerHTML.replace(/>\s*</g, '><').replace(/\bth\b/gi, "td") + '</table>')
  13847. }
  13848. me.fireEvent('contentchange');
  13849. me.fireEvent('saveScene');
  13850. html.html = '';
  13851. return true;
  13852. } else {
  13853. var div = me.document.createElement("div"), tables;
  13854. div.innerHTML = html.html;
  13855. tables = div.getElementsByTagName("table");
  13856. if (domUtils.findParentByTagName(me.selection.getStart(), 'table')) {
  13857. utils.each(tables, function (t) {
  13858. domUtils.remove(t)
  13859. });
  13860. if (domUtils.findParentByTagName(me.selection.getStart(), 'caption', true)) {
  13861. div.innerHTML = div[browser.ie ? 'innerText' : 'textContent'];
  13862. }
  13863. } else {
  13864. utils.each(tables, function (table) {
  13865. removeStyleSize(table, true);
  13866. domUtils.removeAttributes(table, ['style', 'border']);
  13867. utils.each(domUtils.getElementsByTagName(table, "td"), function (td) {
  13868. if (isEmptyBlock(td)) {
  13869. domUtils.fillNode(me.document, td);
  13870. }
  13871. removeStyleSize(td, true);
  13872. // domUtils.removeAttributes(td, ['style'])
  13873. });
  13874. });
  13875. }
  13876. html.html = div.innerHTML;
  13877. }
  13878. });
  13879. me.addListener('afterpaste', function () {
  13880. utils.each(domUtils.getElementsByTagName(me.body, "table"), function (table) {
  13881. if (table.offsetWidth > me.body.offsetWidth) {
  13882. var defaultValue = getDefaultValue(me, table);
  13883. table.style.width = me.body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(me.body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (me.options.offsetWidth || 0) + 'px'
  13884. }
  13885. })
  13886. });
  13887. me.addListener('blur', function () {
  13888. tableCopyList = null;
  13889. });
  13890. var timer;
  13891. me.addListener('keydown', function () {
  13892. clearTimeout(timer);
  13893. timer = setTimeout(function () {
  13894. var rng = me.selection.getRange(),
  13895. cell = domUtils.findParentByTagName(rng.startContainer, ['th', 'td'], true);
  13896. if (cell) {
  13897. var table = cell.parentNode.parentNode.parentNode;
  13898. if (table.offsetWidth > table.getAttribute("width")) {
  13899. cell.style.wordBreak = "break-all";
  13900. }
  13901. }
  13902. }, 100);
  13903. });
  13904. me.addListener("selectionchange", function () {
  13905. toggleDraggableState(me, false, "", null);
  13906. });
  13907. //内容变化时触发索引更新
  13908. //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
  13909. me.addListener("contentchange", function () {
  13910. var me = this;
  13911. //尽可能排除一些不需要更新的状况
  13912. hideDragLine(me);
  13913. if (getUETableBySelected(me))return;
  13914. var rng = me.selection.getRange();
  13915. var start = rng.startContainer;
  13916. start = domUtils.findParentByTagName(start, ['td', 'th'], true);
  13917. utils.each(domUtils.getElementsByTagName(me.document, 'table'), function (table) {
  13918. if (me.fireEvent("excludetable", table) === true) return;
  13919. table.ueTable = new UT(table);
  13920. utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
  13921. if (domUtils.isEmptyBlock(td) && td !== start) {
  13922. domUtils.fillNode(me.document, td);
  13923. if (browser.ie && browser.version == 6) {
  13924. td.innerHTML = '&nbsp;'
  13925. }
  13926. }
  13927. });
  13928. utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
  13929. if (domUtils.isEmptyBlock(th) && th !== start) {
  13930. domUtils.fillNode(me.document, th);
  13931. if (browser.ie && browser.version == 6) {
  13932. th.innerHTML = '&nbsp;'
  13933. }
  13934. }
  13935. });
  13936. table.onmouseover = function () {
  13937. me.fireEvent('tablemouseover', table);
  13938. };
  13939. table.onmousemove = function () {
  13940. me.fireEvent('tablemousemove', table);
  13941. me.options.tableDragable && toggleDragButton(true, this, me);
  13942. };
  13943. table.onmouseout = function () {
  13944. me.fireEvent('tablemouseout', table);
  13945. toggleDraggableState(me, false, "", null);
  13946. hideDragLine(me);
  13947. };
  13948. table.onclick = function (evt) {
  13949. evt = me.window.event || evt;
  13950. var target = getParentTdOrTh(evt.target || evt.srcElement);
  13951. if (!target)return;
  13952. var ut = getUETable(target),
  13953. table = ut.table,
  13954. cellInfo = ut.getCellInfo(target),
  13955. cellsRange,
  13956. rng = me.selection.getRange();
  13957. // if ("topLeft" == inPosition(table, mouseCoords(evt))) {
  13958. // cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
  13959. // ut.setSelected(cellsRange);
  13960. // return;
  13961. // }
  13962. // if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
  13963. //
  13964. // return;
  13965. // }
  13966. if (inTableSide(table, target, evt, true)) {
  13967. var endTdCol = ut.getCell(ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex, ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex);
  13968. if (evt.shiftKey && ut.selectedTds.length) {
  13969. if (ut.selectedTds[0] !== endTdCol) {
  13970. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol);
  13971. ut.setSelected(cellsRange);
  13972. } else {
  13973. rng && rng.selectNodeContents(endTdCol).select();
  13974. }
  13975. } else {
  13976. if (target !== endTdCol) {
  13977. cellsRange = ut.getCellsRange(target, endTdCol);
  13978. ut.setSelected(cellsRange);
  13979. } else {
  13980. rng && rng.selectNodeContents(endTdCol).select();
  13981. }
  13982. }
  13983. return;
  13984. }
  13985. if (inTableSide(table, target, evt)) {
  13986. var endTdRow = ut.getCell(ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex, ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex);
  13987. if (evt.shiftKey && ut.selectedTds.length) {
  13988. if (ut.selectedTds[0] !== endTdRow) {
  13989. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow);
  13990. ut.setSelected(cellsRange);
  13991. } else {
  13992. rng && rng.selectNodeContents(endTdRow).select();
  13993. }
  13994. } else {
  13995. if (target !== endTdRow) {
  13996. cellsRange = ut.getCellsRange(target, endTdRow);
  13997. ut.setSelected(cellsRange);
  13998. } else {
  13999. rng && rng.selectNodeContents(endTdRow).select();
  14000. }
  14001. }
  14002. }
  14003. };
  14004. });
  14005. switchBorderColor(me, true);
  14006. });
  14007. domUtils.on(me.document, "mousemove", mouseMoveEvent);
  14008. domUtils.on(me.document, "mouseout", function (evt) {
  14009. var target = evt.target || evt.srcElement;
  14010. if (target.tagName == "TABLE") {
  14011. toggleDraggableState(me, false, "", null);
  14012. }
  14013. });
  14014. /**
  14015. * 表格隔行变色
  14016. */
  14017. me.addListener("interlacetable", function (type, table, classList) {
  14018. if (!table) return;
  14019. var me = this,
  14020. rows = table.rows,
  14021. len = rows.length,
  14022. getClass = function (list, index, repeat) {
  14023. return list[index] ? list[index] : repeat ? list[index % list.length] : "";
  14024. };
  14025. for (var i = 0; i < len; i++) {
  14026. rows[i].className = getClass(classList || me.options.classList, i, true);
  14027. }
  14028. });
  14029. me.addListener("uninterlacetable", function (type, table) {
  14030. if (!table) return;
  14031. var me = this,
  14032. rows = table.rows,
  14033. classList = me.options.classList,
  14034. len = rows.length;
  14035. for (var i = 0; i < len; i++) {
  14036. domUtils.removeClasses(rows[i], classList);
  14037. }
  14038. });
  14039. me.addListener("mousedown", mouseDownEvent);
  14040. me.addListener("mouseup", mouseUpEvent);
  14041. //拖动的时候不出发mouseup
  14042. domUtils.on(me.body, 'dragstart', function (evt) {
  14043. mouseUpEvent.call(me, 'dragstart', evt);
  14044. });
  14045. var currentRowIndex = 0;
  14046. me.addListener("mousedown", function () {
  14047. currentRowIndex = 0;
  14048. });
  14049. me.addListener('tabkeydown', function () {
  14050. var range = this.selection.getRange(),
  14051. common = range.getCommonAncestor(true, true),
  14052. table = domUtils.findParentByTagName(common, 'table');
  14053. if (table) {
  14054. if (domUtils.findParentByTagName(common, 'caption', true)) {
  14055. var cell = domUtils.getElementsByTagName(table, 'th td');
  14056. if (cell && cell.length) {
  14057. range.setStart(cell[0], 0).setCursor(false, true)
  14058. }
  14059. } else {
  14060. var cell = domUtils.findParentByTagName(common, ['td', 'th'], true),
  14061. ua = getUETable(cell);
  14062. currentRowIndex = cell.rowSpan > 1 ? currentRowIndex : ua.getCellInfo(cell).rowIndex;
  14063. var nextCell = ua.getTabNextCell(cell, currentRowIndex);
  14064. if (nextCell) {
  14065. if (isEmptyBlock(nextCell)) {
  14066. range.setStart(nextCell, 0).setCursor(false, true)
  14067. } else {
  14068. range.selectNodeContents(nextCell).select()
  14069. }
  14070. } else {
  14071. me.fireEvent('saveScene');
  14072. me.__hasEnterExecCommand = true;
  14073. this.execCommand('insertrownext');
  14074. me.__hasEnterExecCommand = false;
  14075. range = this.selection.getRange();
  14076. range.setStart(table.rows[table.rows.length - 1].cells[0], 0).setCursor();
  14077. me.fireEvent('saveScene');
  14078. }
  14079. }
  14080. return true;
  14081. }
  14082. });
  14083. browser.ie && me.addListener('selectionchange', function () {
  14084. toggleDraggableState(this, false, "", null);
  14085. });
  14086. me.addListener("keydown", function (type, evt) {
  14087. var me = this;
  14088. //处理在表格的最后一个输入tab产生新的表格
  14089. var keyCode = evt.keyCode || evt.which;
  14090. if (keyCode == 8 || keyCode == 46) {
  14091. return;
  14092. }
  14093. var notCtrlKey = !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey;
  14094. notCtrlKey && removeSelectedClass(domUtils.getElementsByTagName(me.body, "td"));
  14095. var ut = getUETableBySelected(me);
  14096. if (!ut) return;
  14097. notCtrlKey && ut.clearSelected();
  14098. });
  14099. me.addListener("beforegetcontent", function () {
  14100. switchBorderColor(this, false);
  14101. browser.ie && utils.each(this.document.getElementsByTagName('caption'), function (ci) {
  14102. if (domUtils.isEmptyNode(ci)) {
  14103. ci.innerHTML = '&nbsp;'
  14104. }
  14105. });
  14106. });
  14107. me.addListener("aftergetcontent", function () {
  14108. switchBorderColor(this, true);
  14109. });
  14110. me.addListener("getAllHtml", function () {
  14111. removeSelectedClass(me.document.getElementsByTagName("td"));
  14112. });
  14113. //修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
  14114. me.addListener("fullscreenchanged", function (type, fullscreen) {
  14115. if (!fullscreen) {
  14116. var ratio = this.body.offsetWidth / document.body.offsetWidth,
  14117. tables = domUtils.getElementsByTagName(this.body, "table");
  14118. utils.each(tables, function (table) {
  14119. if (table.offsetWidth < me.body.offsetWidth) return false;
  14120. var tds = domUtils.getElementsByTagName(table, "td"),
  14121. backWidths = [];
  14122. utils.each(tds, function (td) {
  14123. backWidths.push(td.offsetWidth);
  14124. });
  14125. for (var i = 0, td; td = tds[i]; i++) {
  14126. td.setAttribute("width", Math.floor(backWidths[i] * ratio));
  14127. }
  14128. table.setAttribute("width", Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me))))
  14129. });
  14130. }
  14131. });
  14132. //重写execCommand命令,用于处理框选时的处理
  14133. var oldExecCommand = me.execCommand;
  14134. me.execCommand = function (cmd, datatat) {
  14135. var me = this,
  14136. args = arguments;
  14137. cmd = cmd.toLowerCase();
  14138. var ut = getUETableBySelected(me), tds,
  14139. range = new dom.Range(me.document),
  14140. cmdFun = me.commands[cmd] || UE.commands[cmd],
  14141. result;
  14142. if (!cmdFun) return;
  14143. if (ut && !commands[cmd] && !cmdFun.notNeedUndo && !me.__hasEnterExecCommand) {
  14144. me.__hasEnterExecCommand = true;
  14145. me.fireEvent("beforeexeccommand", cmd);
  14146. tds = ut.selectedTds;
  14147. var lastState = -2, lastValue = -2, value, state;
  14148. for (var i = 0, td; td = tds[i]; i++) {
  14149. if (isEmptyBlock(td)) {
  14150. range.setStart(td, 0).setCursor(false, true)
  14151. } else {
  14152. range.selectNode(td).select(true);
  14153. }
  14154. state = me.queryCommandState(cmd);
  14155. value = me.queryCommandValue(cmd);
  14156. if (state != -1) {
  14157. if (lastState !== state || lastValue !== value) {
  14158. me._ignoreContentChange = true;
  14159. result = oldExecCommand.apply(me, arguments);
  14160. me._ignoreContentChange = false;
  14161. }
  14162. lastState = me.queryCommandState(cmd);
  14163. lastValue = me.queryCommandValue(cmd);
  14164. if (domUtils.isEmptyBlock(td)) {
  14165. domUtils.fillNode(me.document, td)
  14166. }
  14167. }
  14168. }
  14169. range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true);
  14170. me.fireEvent('contentchange');
  14171. me.fireEvent("afterexeccommand", cmd);
  14172. me.__hasEnterExecCommand = false;
  14173. me._selectionChange();
  14174. } else {
  14175. result = oldExecCommand.apply(me, arguments);
  14176. }
  14177. return result;
  14178. };
  14179. });
  14180. /**
  14181. * 删除obj的宽高style,改成属性宽高
  14182. * @param obj
  14183. * @param replaceToProperty
  14184. */
  14185. function removeStyleSize(obj, replaceToProperty) {
  14186. removeStyle(obj, "width", true);
  14187. removeStyle(obj, "height", true);
  14188. }
  14189. function removeStyle(obj, styleName, replaceToProperty) {
  14190. if (obj.style[styleName]) {
  14191. replaceToProperty && obj.setAttribute(styleName, parseInt(obj.style[styleName], 10));
  14192. obj.style[styleName] = "";
  14193. }
  14194. }
  14195. function getParentTdOrTh(ele) {
  14196. if (ele.tagName == "TD" || ele.tagName == "TH") return ele;
  14197. var td;
  14198. if (td = domUtils.findParentByTagName(ele, "td", true) || domUtils.findParentByTagName(ele, "th", true)) return td;
  14199. return null;
  14200. }
  14201. function isEmptyBlock(node) {
  14202. var reg = new RegExp(domUtils.fillChar, 'g');
  14203. if (node[browser.ie ? 'innerText' : 'textContent'].replace(/^\s*$/, '').replace(reg, '').length > 0) {
  14204. return 0;
  14205. }
  14206. for (var n in dtd.$isNotEmpty) {
  14207. if (node.getElementsByTagName(n).length) {
  14208. return 0;
  14209. }
  14210. }
  14211. return 1;
  14212. }
  14213. function mouseCoords(evt) {
  14214. if (evt.pageX || evt.pageY) {
  14215. return { x: evt.pageX, y: evt.pageY };
  14216. }
  14217. return {
  14218. x: evt.clientX + me.document.body.scrollLeft - me.document.body.clientLeft,
  14219. y: evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
  14220. };
  14221. }
  14222. function mouseMoveEvent(evt) {
  14223. if (isEditorDisabled()) {
  14224. return;
  14225. }
  14226. try {
  14227. //普通状态下鼠标移动
  14228. var target = getParentTdOrTh(evt.target || evt.srcElement),
  14229. pos;
  14230. //区分用户的行为是拖动还是双击
  14231. if (isInResizeBuffer) {
  14232. me.body.style.webkitUserSelect = 'none';
  14233. if (Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell || Math.abs(userActionStatus.y - evt.clientY) > offsetOfTableCell) {
  14234. clearTableDragTimer();
  14235. isInResizeBuffer = false;
  14236. singleClickState = 0;
  14237. //drag action
  14238. tableBorderDrag(evt);
  14239. }
  14240. }
  14241. //修改单元格大小时的鼠标移动
  14242. if (onDrag && dragTd) {
  14243. singleClickState = 0;
  14244. me.body.style.webkitUserSelect = 'none';
  14245. me.selection.getNative()[browser.ie ? 'empty' : 'removeAllRanges']();
  14246. pos = mouseCoords(evt);
  14247. toggleDraggableState(me, true, onDrag, pos, target);
  14248. if (onDrag == "h") {
  14249. dragLine.style.left = getPermissionX(dragTd, evt) + "px";
  14250. } else if (onDrag == "v") {
  14251. dragLine.style.top = getPermissionY(dragTd, evt) + "px";
  14252. }
  14253. return;
  14254. }
  14255. //当鼠标处于table上时,修改移动过程中的光标状态
  14256. if (target) {
  14257. //针对使用table作为容器的组件不触发拖拽效果
  14258. if (me.fireEvent('excludetable', target) === true)
  14259. return;
  14260. pos = mouseCoords(evt);
  14261. var state = getRelation(target, pos),
  14262. table = domUtils.findParentByTagName(target, "table", true);
  14263. if (inTableSide(table, target, evt, true)) {
  14264. if (me.fireEvent("excludetable", table) === true) return;
  14265. me.body.style.cursor = "url(" + me.options.cursorpath + "h.png),pointer";
  14266. } else if (inTableSide(table, target, evt)) {
  14267. if (me.fireEvent("excludetable", table) === true) return;
  14268. me.body.style.cursor = "url(" + me.options.cursorpath + "v.png),pointer";
  14269. } else {
  14270. me.body.style.cursor = "text";
  14271. var curCell = target;
  14272. if (/\d/.test(state)) {
  14273. state = state.replace(/\d/, '');
  14274. target = getUETable(target).getPreviewCell(target, state == "v");
  14275. }
  14276. //位于第一行的顶部或者第一列的左边时不可拖动
  14277. toggleDraggableState(me, target ? !!state : false, target ? state : '', pos, target);
  14278. }
  14279. } else {
  14280. toggleDragButton(false, table, me);
  14281. }
  14282. } catch (e) {
  14283. showError(e);
  14284. }
  14285. }
  14286. var dragButtonTimer;
  14287. function toggleDragButton(show, table, editor) {
  14288. if (!show) {
  14289. if (dragOver)return;
  14290. dragButtonTimer = setTimeout(function () {
  14291. !dragOver && dragButton && dragButton.parentNode && dragButton.parentNode.removeChild(dragButton);
  14292. }, 2000);
  14293. } else {
  14294. createDragButton(table, editor);
  14295. }
  14296. }
  14297. function createDragButton(table, editor) {
  14298. var pos = domUtils.getXY(table),
  14299. doc = table.ownerDocument;
  14300. if (dragButton && dragButton.parentNode)return dragButton;
  14301. dragButton = doc.createElement("div");
  14302. dragButton.contentEditable = false;
  14303. dragButton.innerHTML = "";
  14304. dragButton.style.cssText = "width:15px;height:15px;background-image:url(" + editor.options.UEDITOR_HOME_URL + "dialogs/table/dragicon.png);position: absolute;cursor:move;top:" + (pos.y - 15) + "px;left:" + (pos.x) + "px;";
  14305. domUtils.unSelectable(dragButton);
  14306. dragButton.onmouseover = function (evt) {
  14307. dragOver = true;
  14308. };
  14309. dragButton.onmouseout = function (evt) {
  14310. dragOver = false;
  14311. };
  14312. domUtils.on(dragButton, 'click', function (type, evt) {
  14313. doClick(evt, this);
  14314. });
  14315. domUtils.on(dragButton, 'dblclick', function (type, evt) {
  14316. doDblClick(evt);
  14317. });
  14318. domUtils.on(dragButton, 'dragstart', function (type, evt) {
  14319. domUtils.preventDefault(evt);
  14320. });
  14321. var timer;
  14322. function doClick(evt, button) {
  14323. // 部分浏览器下需要清理
  14324. clearTimeout(timer);
  14325. timer = setTimeout(function () {
  14326. editor.fireEvent("tableClicked", table, button);
  14327. }, 300);
  14328. }
  14329. function doDblClick(evt) {
  14330. clearTimeout(timer);
  14331. var ut = getUETable(table),
  14332. start = table.rows[0].cells[0],
  14333. end = ut.getLastCell(),
  14334. range = ut.getCellsRange(start, end);
  14335. editor.selection.getRange().setStart(start, 0).setCursor(false, true);
  14336. ut.setSelected(range);
  14337. }
  14338. doc.body.appendChild(dragButton);
  14339. }
  14340. // function inPosition(table, pos) {
  14341. // var tablePos = domUtils.getXY(table),
  14342. // width = table.offsetWidth,
  14343. // height = table.offsetHeight;
  14344. // if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
  14345. // return "topLeft";
  14346. // } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
  14347. // return "bottomRight";
  14348. // }
  14349. // }
  14350. function inTableSide(table, cell, evt, top) {
  14351. var pos = mouseCoords(evt),
  14352. state = getRelation(cell, pos);
  14353. if (top) {
  14354. var caption = table.getElementsByTagName("caption")[0],
  14355. capHeight = caption ? caption.offsetHeight : 0;
  14356. return (state == "v1") && ((pos.y - domUtils.getXY(table).y - capHeight) < 8);
  14357. } else {
  14358. return (state == "h1") && ((pos.x - domUtils.getXY(table).x) < 8);
  14359. }
  14360. }
  14361. /**
  14362. * 获取拖动时允许的X轴坐标
  14363. * @param dragTd
  14364. * @param evt
  14365. */
  14366. function getPermissionX(dragTd, evt) {
  14367. var ut = getUETable(dragTd);
  14368. if (ut) {
  14369. var preTd = ut.getSameEndPosCells(dragTd, "x")[0],
  14370. nextTd = ut.getSameStartPosXCells(dragTd)[0],
  14371. mouseX = mouseCoords(evt).x,
  14372. left = (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20 ,
  14373. right = nextTd ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20 : (me.body.offsetWidth + 5 || parseInt(domUtils.getComputedStyle(me.body, "width"), 10));
  14374. left += cellMinWidth;
  14375. right -= cellMinWidth;
  14376. return mouseX < left ? left : mouseX > right ? right : mouseX;
  14377. }
  14378. }
  14379. /**
  14380. * 获取拖动时允许的Y轴坐标
  14381. */
  14382. function getPermissionY(dragTd, evt) {
  14383. try {
  14384. var top = domUtils.getXY(dragTd).y,
  14385. mousePosY = mouseCoords(evt).y;
  14386. return mousePosY < top ? top : mousePosY;
  14387. } catch (e) {
  14388. showError(e);
  14389. }
  14390. }
  14391. /**
  14392. * 移动状态切换
  14393. */
  14394. function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
  14395. try {
  14396. editor.body.style.cursor = dir == "h" ? "col-resize" : dir == "v" ? "row-resize" : "text";
  14397. if (browser.ie) {
  14398. if (dir && !mousedown && !getUETableBySelected(editor)) {
  14399. getDragLine(editor, editor.document);
  14400. showDragLineAt(dir, cell);
  14401. } else {
  14402. hideDragLine(editor)
  14403. }
  14404. }
  14405. onBorder = draggable;
  14406. } catch (e) {
  14407. showError(e);
  14408. }
  14409. }
  14410. /**
  14411. * 获取与UETable相关的resize line
  14412. * @param uetable UETable对象
  14413. */
  14414. function getResizeLineByUETable() {
  14415. var lineId = '_UETableResizeLine',
  14416. line = this.document.getElementById(lineId);
  14417. if (!line) {
  14418. line = this.document.createElement("div");
  14419. line.id = lineId;
  14420. line.contnetEditable = false;
  14421. line.setAttribute("unselectable", "on");
  14422. var styles = {
  14423. width: 2 * cellBorderWidth + 1 + 'px',
  14424. position: 'absolute',
  14425. 'z-index': 100000,
  14426. cursor: 'col-resize',
  14427. background: 'red',
  14428. display: 'none'
  14429. };
  14430. //切换状态
  14431. line.onmouseout = function () {
  14432. this.style.display = 'none';
  14433. };
  14434. utils.extend(line.style, styles);
  14435. this.document.body.appendChild(line);
  14436. }
  14437. return line;
  14438. }
  14439. /**
  14440. * 更新resize-line
  14441. */
  14442. function updateResizeLine(cell, uetable) {
  14443. var line = getResizeLineByUETable.call(this),
  14444. table = uetable.table,
  14445. styles = {
  14446. top: domUtils.getXY(table).y + 'px',
  14447. left: domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + 'px',
  14448. display: 'block',
  14449. height: table.offsetHeight + 'px'
  14450. };
  14451. utils.extend(line.style, styles);
  14452. }
  14453. /**
  14454. * 显示resize-line
  14455. */
  14456. function showResizeLine(cell) {
  14457. var uetable = getUETable(cell);
  14458. updateResizeLine.call(this, cell, uetable);
  14459. }
  14460. /**
  14461. * 获取鼠标与当前单元格的相对位置
  14462. * @param ele
  14463. * @param mousePos
  14464. */
  14465. function getRelation(ele, mousePos) {
  14466. var elePos = domUtils.getXY(ele);
  14467. if (!elePos) {
  14468. return '';
  14469. }
  14470. if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
  14471. return "h";
  14472. }
  14473. if (mousePos.x - elePos.x < cellBorderWidth) {
  14474. return 'h1'
  14475. }
  14476. if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
  14477. return "v";
  14478. }
  14479. if (mousePos.y - elePos.y < cellBorderWidth) {
  14480. return 'v1'
  14481. }
  14482. return '';
  14483. }
  14484. function mouseDownEvent(type, evt) {
  14485. if (isEditorDisabled()) {
  14486. return;
  14487. }
  14488. userActionStatus = {
  14489. x: evt.clientX,
  14490. y: evt.clientY
  14491. };
  14492. //右键菜单单独处理
  14493. if (evt.button == 2) {
  14494. var ut = getUETableBySelected(me),
  14495. flag = false;
  14496. if (ut) {
  14497. var td = getTargetTd(me, evt);
  14498. utils.each(ut.selectedTds, function (ti) {
  14499. if (ti === td) {
  14500. flag = true;
  14501. }
  14502. });
  14503. if (!flag) {
  14504. removeSelectedClass(domUtils.getElementsByTagName(me.body, "th td"));
  14505. ut.clearSelected()
  14506. } else {
  14507. td = ut.selectedTds[0];
  14508. setTimeout(function () {
  14509. me.selection.getRange().setStart(td, 0).setCursor(false, true);
  14510. }, 0);
  14511. }
  14512. }
  14513. } else {
  14514. tableClickHander(evt);
  14515. }
  14516. }
  14517. //清除表格的计时器
  14518. function clearTableTimer() {
  14519. tabTimer && clearTimeout(tabTimer);
  14520. tabTimer = null;
  14521. }
  14522. //双击收缩
  14523. function tableDbclickHandler(evt) {
  14524. singleClickState = 0;
  14525. evt = evt || me.window.event;
  14526. var target = getParentTdOrTh(evt.target || evt.srcElement);
  14527. if (target) {
  14528. var h;
  14529. if (h = getRelation(target, mouseCoords(evt))) {
  14530. hideDragLine(me);
  14531. if (h == 'h1') {
  14532. h = 'h';
  14533. if (inTableSide(domUtils.findParentByTagName(target, "table"), target, evt)) {
  14534. me.execCommand('adaptbywindow');
  14535. } else {
  14536. target = getUETable(target).getPreviewCell(target);
  14537. if (target) {
  14538. var rng = me.selection.getRange();
  14539. rng.selectNodeContents(target).setCursor(true, true)
  14540. }
  14541. }
  14542. }
  14543. if (h == 'h') {
  14544. var ut = getUETable(target),
  14545. table = ut.table,
  14546. cells = getCellsByMoveBorder(target, table, true);
  14547. cells = extractArray(cells, 'left');
  14548. ut.width = ut.offsetWidth;
  14549. var oldWidth = [],
  14550. newWidth = [];
  14551. utils.each(cells, function (cell) {
  14552. oldWidth.push(cell.offsetWidth);
  14553. });
  14554. utils.each(cells, function (cell) {
  14555. cell.removeAttribute("width");
  14556. });
  14557. window.setTimeout(function () {
  14558. //是否允许改变
  14559. var changeable = true;
  14560. utils.each(cells, function (cell, index) {
  14561. var width = cell.offsetWidth;
  14562. if (width > oldWidth[index]) {
  14563. changeable = false;
  14564. return false;
  14565. }
  14566. newWidth.push(width);
  14567. });
  14568. var change = changeable ? newWidth : oldWidth;
  14569. utils.each(cells, function (cell, index) {
  14570. cell.width = change[index] - getTabcellSpace();
  14571. });
  14572. }, 0);
  14573. // minWidth -= cellMinWidth;
  14574. //
  14575. // table.removeAttribute("width");
  14576. // utils.each(cells, function (cell) {
  14577. // cell.style.width = "";
  14578. // cell.width -= minWidth;
  14579. // });
  14580. }
  14581. }
  14582. }
  14583. }
  14584. function tableClickHander(evt) {
  14585. removeSelectedClass(domUtils.getElementsByTagName(me.body, "td th"));
  14586. //trace:3113
  14587. //选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
  14588. utils.each(me.document.getElementsByTagName('table'), function (t) {
  14589. t.ueTable = null;
  14590. });
  14591. startTd = getTargetTd(me, evt);
  14592. if (!startTd) return;
  14593. var table = domUtils.findParentByTagName(startTd, "table", true);
  14594. ut = getUETable(table);
  14595. ut && ut.clearSelected();
  14596. //判断当前鼠标状态
  14597. if (!onBorder) {
  14598. me.document.body.style.webkitUserSelect = '';
  14599. mousedown = true;
  14600. me.addListener('mouseover', mouseOverEvent);
  14601. } else {
  14602. //边框上的动作处理
  14603. borderActionHandler(evt);
  14604. }
  14605. }
  14606. //处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
  14607. function borderActionHandler(evt) {
  14608. if (browser.ie) {
  14609. evt = reconstruct(evt);
  14610. }
  14611. clearTableDragTimer();
  14612. //是否正在等待resize的缓冲中
  14613. isInResizeBuffer = true;
  14614. tableDragTimer = setTimeout(function () {
  14615. tableBorderDrag(evt);
  14616. }, dblclickTime);
  14617. }
  14618. function extractArray(originArr, key) {
  14619. var result = [],
  14620. tmp = null;
  14621. for (var i = 0, len = originArr.length; i < len; i++) {
  14622. tmp = originArr[ i ][ key ];
  14623. if (tmp) {
  14624. result.push(tmp);
  14625. }
  14626. }
  14627. return result;
  14628. }
  14629. function clearTableDragTimer() {
  14630. tableDragTimer && clearTimeout(tableDragTimer);
  14631. tableDragTimer = null;
  14632. }
  14633. function reconstruct(obj) {
  14634. var attrs = ['pageX', 'pageY', 'clientX', 'clientY', 'srcElement', 'target'],
  14635. newObj = {};
  14636. if (obj) {
  14637. for (var i = 0, key, val; key = attrs[i]; i++) {
  14638. val = obj[ key ];
  14639. val && (newObj[ key ] = val);
  14640. }
  14641. }
  14642. return newObj;
  14643. }
  14644. //边框拖动
  14645. function tableBorderDrag(evt) {
  14646. isInResizeBuffer = false;
  14647. if (!startTd) return;
  14648. var state = Math.abs(userActionStatus.x - evt.clientX) >= Math.abs(userActionStatus.y - evt.clientY) ? 'h' : 'v';
  14649. // var state = getRelation(startTd, mouseCoords(evt));
  14650. if (/\d/.test(state)) {
  14651. state = state.replace(/\d/, '');
  14652. startTd = getUETable(startTd).getPreviewCell(startTd, state == 'v');
  14653. }
  14654. hideDragLine(me);
  14655. getDragLine(me, me.document);
  14656. me.fireEvent('saveScene');
  14657. showDragLineAt(state, startTd);
  14658. mousedown = true;
  14659. //拖动开始
  14660. onDrag = state;
  14661. dragTd = startTd;
  14662. }
  14663. function mouseUpEvent(type, evt) {
  14664. if (isEditorDisabled()) {
  14665. return;
  14666. }
  14667. clearTableDragTimer();
  14668. isInResizeBuffer = false;
  14669. if (onBorder) {
  14670. singleClickState = ++singleClickState % 3;
  14671. userActionStatus = {
  14672. x: evt.clientX,
  14673. y: evt.clientY
  14674. };
  14675. tableResizeTimer = setTimeout(function () {
  14676. singleClickState > 0 && singleClickState--;
  14677. }, dblclickTime);
  14678. if (singleClickState === 2) {
  14679. singleClickState = 0;
  14680. tableDbclickHandler(evt);
  14681. return;
  14682. }
  14683. }
  14684. if (evt.button == 2)return;
  14685. var me = this;
  14686. //清除表格上原生跨选问题
  14687. var range = me.selection.getRange(),
  14688. start = domUtils.findParentByTagName(range.startContainer, 'table', true),
  14689. end = domUtils.findParentByTagName(range.endContainer, 'table', true);
  14690. if (start || end) {
  14691. if (start === end) {
  14692. start = domUtils.findParentByTagName(range.startContainer, ['td', 'th', 'caption'], true);
  14693. end = domUtils.findParentByTagName(range.endContainer, ['td', 'th', 'caption'], true);
  14694. if (start !== end) {
  14695. me.selection.clearRange()
  14696. }
  14697. } else {
  14698. me.selection.clearRange()
  14699. }
  14700. }
  14701. mousedown = false;
  14702. me.document.body.style.webkitUserSelect = '';
  14703. //拖拽状态下的mouseUP
  14704. if (onDrag && dragTd) {
  14705. me.selection.getNative()[browser.ie ? 'empty' : 'removeAllRanges']();
  14706. singleClickState = 0;
  14707. dragLine = me.document.getElementById('ue_tableDragLine');
  14708. var dragTdPos = domUtils.getXY(dragTd),
  14709. dragLinePos = domUtils.getXY(dragLine);
  14710. switch (onDrag) {
  14711. case "h":
  14712. changeColWidth(dragTd, dragLinePos.x - dragTdPos.x);
  14713. break;
  14714. case "v":
  14715. changeRowHeight(dragTd, dragLinePos.y - dragTdPos.y - dragTd.offsetHeight);
  14716. break;
  14717. default:
  14718. }
  14719. onDrag = "";
  14720. dragTd = null;
  14721. hideDragLine(me);
  14722. me.fireEvent('saveScene');
  14723. return;
  14724. }
  14725. //正常状态下的mouseup
  14726. if (!startTd) {
  14727. var target = domUtils.findParentByTagName(evt.target || evt.srcElement, "td", true);
  14728. if (!target) target = domUtils.findParentByTagName(evt.target || evt.srcElement, "th", true);
  14729. if (target && (target.tagName == "TD" || target.tagName == "TH")) {
  14730. if (me.fireEvent("excludetable", target) === true) return;
  14731. range = new dom.Range(me.document);
  14732. range.setStart(target, 0).setCursor(false, true);
  14733. }
  14734. } else {
  14735. var ut = getUETable(startTd),
  14736. cell = ut ? ut.selectedTds[0] : null;
  14737. if (cell) {
  14738. range = new dom.Range(me.document);
  14739. if (domUtils.isEmptyBlock(cell)) {
  14740. range.setStart(cell, 0).setCursor(false, true);
  14741. } else {
  14742. range.selectNodeContents(cell).shrinkBoundary().setCursor(false, true);
  14743. }
  14744. } else {
  14745. range = me.selection.getRange().shrinkBoundary();
  14746. if (!range.collapsed) {
  14747. var start = domUtils.findParentByTagName(range.startContainer, ['td', 'th'], true),
  14748. end = domUtils.findParentByTagName(range.endContainer, ['td', 'th'], true);
  14749. //在table里边的不能清除
  14750. if (start && !end || !start && end || start && end && start !== end) {
  14751. range.setCursor(false, true);
  14752. }
  14753. }
  14754. }
  14755. startTd = null;
  14756. me.removeListener('mouseover', mouseOverEvent);
  14757. }
  14758. me._selectionChange(250, evt);
  14759. }
  14760. function mouseOverEvent(type, evt) {
  14761. if (isEditorDisabled()) {
  14762. return;
  14763. }
  14764. var me = this,
  14765. tar = evt.target || evt.srcElement;
  14766. currentTd = domUtils.findParentByTagName(tar, "td", true) || domUtils.findParentByTagName(tar, "th", true);
  14767. //需要判断两个TD是否位于同一个表格内
  14768. if (startTd && currentTd &&
  14769. ((startTd.tagName == "TD" && currentTd.tagName == "TD") || (startTd.tagName == "TH" && currentTd.tagName == "TH")) &&
  14770. domUtils.findParentByTagName(startTd, 'table') == domUtils.findParentByTagName(currentTd, 'table')) {
  14771. var ut = getUETable(currentTd);
  14772. if (startTd != currentTd) {
  14773. me.document.body.style.webkitUserSelect = 'none';
  14774. me.selection.getNative()[browser.ie ? 'empty' : 'removeAllRanges']();
  14775. var range = ut.getCellsRange(startTd, currentTd);
  14776. ut.setSelected(range);
  14777. } else {
  14778. me.document.body.style.webkitUserSelect = '';
  14779. ut.clearSelected();
  14780. }
  14781. }
  14782. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  14783. }
  14784. function setCellHeight(cell, height, backHeight) {
  14785. var lineHight = parseInt(domUtils.getComputedStyle(cell, "line-height"), 10),
  14786. tmpHeight = backHeight + height;
  14787. height = tmpHeight < lineHight ? lineHight : tmpHeight;
  14788. if (cell.style.height) cell.style.height = "";
  14789. cell.rowSpan == 1 ? cell.setAttribute("height", height) : (cell.removeAttribute && cell.removeAttribute("height"));
  14790. }
  14791. function getWidth(cell) {
  14792. if (!cell)return 0;
  14793. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  14794. }
  14795. function changeColWidth(cell, changeValue) {
  14796. var ut = getUETable(cell);
  14797. if (ut) {
  14798. //根据当前移动的边框获取相关的单元格
  14799. var table = ut.table,
  14800. cells = getCellsByMoveBorder(cell, table);
  14801. table.style.width = "";
  14802. table.removeAttribute("width");
  14803. //修正改变量
  14804. changeValue = correctChangeValue(changeValue, cell, cells);
  14805. if (cell.nextSibling) {
  14806. var i = 0;
  14807. utils.each(cells, function (cellGroup) {
  14808. cellGroup.left.width = (+cellGroup.left.width) + changeValue;
  14809. cellGroup.right && ( cellGroup.right.width = (+cellGroup.right.width) - changeValue );
  14810. });
  14811. } else {
  14812. utils.each(cells, function (cellGroup) {
  14813. cellGroup.left.width -= -changeValue;
  14814. });
  14815. }
  14816. }
  14817. }
  14818. function isEditorDisabled() {
  14819. return me.body.contentEditable === "false";
  14820. }
  14821. function changeRowHeight(td, changeValue) {
  14822. if (Math.abs(changeValue) < 10) return;
  14823. var ut = getUETable(td);
  14824. if (ut) {
  14825. var cells = ut.getSameEndPosCells(td, "y"),
  14826. //备份需要连带变化的td的原始高度,否则后期无法获取正确的值
  14827. backHeight = cells[0] ? cells[0].offsetHeight : 0;
  14828. for (var i = 0, cell; cell = cells[i++];) {
  14829. setCellHeight(cell, changeValue, backHeight);
  14830. }
  14831. }
  14832. }
  14833. /**
  14834. * 获取调整单元格大小的相关单元格
  14835. * @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
  14836. */
  14837. function getCellsByMoveBorder(cell, table, isContainMergeCell) {
  14838. if (!table) {
  14839. table = domUtils.findParentByTagName(cell, 'table');
  14840. }
  14841. if (!table) {
  14842. return null;
  14843. }
  14844. //获取到该单元格所在行的序列号
  14845. var index = domUtils.getNodeIndex(cell),
  14846. temp = cell,
  14847. rows = table.rows,
  14848. colIndex = 0;
  14849. while (temp) {
  14850. //获取到当前单元格在未发生单元格合并时的序列
  14851. if (temp.nodeType === 1) {
  14852. colIndex += (temp.colSpan || 1);
  14853. }
  14854. temp = temp.previousSibling;
  14855. }
  14856. temp = null;
  14857. //记录想关的单元格
  14858. var borderCells = [];
  14859. utils.each(rows, function (tabRow) {
  14860. var cells = tabRow.cells,
  14861. currIndex = 0;
  14862. utils.each(cells, function (tabCell) {
  14863. currIndex += (tabCell.colSpan || 1);
  14864. if (currIndex === colIndex) {
  14865. borderCells.push({
  14866. left: tabCell,
  14867. right: tabCell.nextSibling || null
  14868. });
  14869. return false;
  14870. } else if (currIndex > colIndex) {
  14871. if (isContainMergeCell) {
  14872. borderCells.push({
  14873. left: tabCell
  14874. });
  14875. }
  14876. return false;
  14877. }
  14878. });
  14879. });
  14880. return borderCells;
  14881. }
  14882. /**
  14883. * 通过给定的单元格集合获取最小的单元格width
  14884. */
  14885. function getMinWidthByTableCells(cells) {
  14886. var minWidth = Number.MAX_VALUE;
  14887. for (var i = 0, curCell; curCell = cells[ i ]; i++) {
  14888. minWidth = Math.min(minWidth, curCell.width || getTableCellWidth(curCell));
  14889. }
  14890. return minWidth;
  14891. }
  14892. function correctChangeValue(changeValue, relatedCell, cells) {
  14893. //为单元格的paading预留空间
  14894. changeValue -= getTabcellSpace();
  14895. if (changeValue < 0) {
  14896. return 0;
  14897. }
  14898. changeValue -= getTableCellWidth(relatedCell);
  14899. //确定方向
  14900. var direction = changeValue < 0 ? 'left' : 'right';
  14901. changeValue = Math.abs(changeValue);
  14902. //只关心非最后一个单元格就可以
  14903. utils.each(cells, function (cellGroup) {
  14904. var curCell = cellGroup[direction];
  14905. //为单元格保留最小空间
  14906. if (curCell) {
  14907. changeValue = Math.min(changeValue, getTableCellWidth(curCell) - cellMinWidth);
  14908. }
  14909. });
  14910. //修正越界
  14911. changeValue = changeValue < 0 ? 0 : changeValue;
  14912. return direction === 'left' ? -changeValue : changeValue;
  14913. }
  14914. function getTableCellWidth(cell) {
  14915. var width = 0,
  14916. //偏移纠正量
  14917. offset = 0,
  14918. width = cell.offsetWidth - getTabcellSpace();
  14919. //最后一个节点纠正一下
  14920. if (!cell.nextSibling) {
  14921. width -= getTableCellOffset(cell);
  14922. }
  14923. width = width < 0 ? 0 : width;
  14924. try {
  14925. cell.width = width;
  14926. } catch (e) {
  14927. }
  14928. return width;
  14929. }
  14930. /**
  14931. * 获取单元格所在表格的最末单元格的偏移量
  14932. */
  14933. function getTableCellOffset(cell) {
  14934. tab = domUtils.findParentByTagName(cell, "table", false);
  14935. if (tab.offsetVal === undefined) {
  14936. var prev = cell.previousSibling;
  14937. if (prev) {
  14938. //最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
  14939. tab.offsetVal = cell.offsetWidth - prev.offsetWidth === UT.borderWidth ? UT.borderWidth : 0;
  14940. } else {
  14941. tab.offsetVal = 0;
  14942. }
  14943. }
  14944. return tab.offsetVal;
  14945. }
  14946. function getTabcellSpace() {
  14947. if (UT.tabcellSpace === undefined) {
  14948. var cell = null,
  14949. tab = me.document.createElement("table"),
  14950. tbody = me.document.createElement("tbody"),
  14951. trow = me.document.createElement("tr"),
  14952. tabcell = me.document.createElement("td"),
  14953. mirror = null;
  14954. tabcell.style.cssText = 'border: 0;';
  14955. tabcell.width = 1;
  14956. trow.appendChild(tabcell);
  14957. trow.appendChild(mirror = tabcell.cloneNode(false));
  14958. tbody.appendChild(trow);
  14959. tab.appendChild(tbody);
  14960. tab.style.cssText = "visibility: hidden;";
  14961. me.body.appendChild(tab);
  14962. UT.paddingSpace = tabcell.offsetWidth - 1;
  14963. var tmpTabWidth = tab.offsetWidth;
  14964. tabcell.style.cssText = '';
  14965. mirror.style.cssText = '';
  14966. UT.borderWidth = ( tab.offsetWidth - tmpTabWidth ) / 3;
  14967. UT.tabcellSpace = UT.paddingSpace + UT.borderWidth;
  14968. me.body.removeChild(tab);
  14969. }
  14970. getTabcellSpace = function () {
  14971. return UT.tabcellSpace;
  14972. };
  14973. return UT.tabcellSpace;
  14974. }
  14975. function getDragLine(editor, doc) {
  14976. if (mousedown)return;
  14977. dragLine = editor.document.createElement("div");
  14978. domUtils.setAttributes(dragLine, {
  14979. id: "ue_tableDragLine",
  14980. unselectable: 'on',
  14981. contenteditable: false,
  14982. 'onresizestart': 'return false',
  14983. 'ondragstart': 'return false',
  14984. 'onselectstart': 'return false',
  14985. style: "background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)"
  14986. });
  14987. editor.body.appendChild(dragLine);
  14988. }
  14989. function hideDragLine(editor) {
  14990. if (mousedown)return;
  14991. var line;
  14992. while (line = editor.document.getElementById('ue_tableDragLine')) {
  14993. domUtils.remove(line)
  14994. }
  14995. }
  14996. /**
  14997. * 依据state(v|h)在cell位置显示横线
  14998. * @param state
  14999. * @param cell
  15000. */
  15001. function showDragLineAt(state, cell) {
  15002. if (!cell) return;
  15003. var table = domUtils.findParentByTagName(cell, "table"),
  15004. caption = table.getElementsByTagName('caption'),
  15005. width = table.offsetWidth,
  15006. height = table.offsetHeight - (caption.length > 0 ? caption[0].offsetHeight : 0),
  15007. tablePos = domUtils.getXY(table),
  15008. cellPos = domUtils.getXY(cell), css;
  15009. switch (state) {
  15010. case "h":
  15011. css = 'height:' + height + 'px;top:' + (tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) + 'px;left:' + (cellPos.x + cell.offsetWidth);
  15012. dragLine.style.cssText = css + 'px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)';
  15013. break;
  15014. case "v":
  15015. css = 'width:' + width + 'px;left:' + tablePos.x + 'px;top:' + (cellPos.y + cell.offsetHeight );
  15016. //必须加上border:0和color:blue,否则低版ie不支持背景色显示
  15017. dragLine.style.cssText = css + 'px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)';
  15018. break;
  15019. default:
  15020. }
  15021. }
  15022. /**
  15023. * 当表格边框颜色为白色时设置为虚线,true为添加虚线
  15024. * @param editor
  15025. * @param flag
  15026. */
  15027. function switchBorderColor(editor, flag) {
  15028. var tableArr = domUtils.getElementsByTagName(editor.body, "table"), color;
  15029. for (var i = 0, node; node = tableArr[i++];) {
  15030. var td = domUtils.getElementsByTagName(node, "td");
  15031. if (td[0]) {
  15032. if (flag) {
  15033. color = (td[0].style.borderColor).replace(/\s/g, "");
  15034. if (/(#ffffff)|(rgb\(255,f55,255\))/ig.test(color))
  15035. domUtils.addClass(node, "noBorderTable")
  15036. } else {
  15037. domUtils.removeClasses(node, "noBorderTable")
  15038. }
  15039. }
  15040. }
  15041. }
  15042. function getTableWidth(editor, needIEHack, defaultValue) {
  15043. var body = editor.body;
  15044. return body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (editor.options.offsetWidth || 0);
  15045. }
  15046. /**
  15047. * 获取当前拖动的单元格
  15048. */
  15049. function getTargetTd(editor, evt) {
  15050. var target = domUtils.findParentByTagName(evt.target || evt.srcElement, ["td", "th"], true),
  15051. dir = null;
  15052. if (!target) {
  15053. return null;
  15054. }
  15055. dir = getRelation(target, mouseCoords(evt));
  15056. //如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td
  15057. if (!target) {
  15058. return null;
  15059. }
  15060. if (dir === 'h1' && target.previousSibling) {
  15061. var position = domUtils.getXY(target),
  15062. cellWidth = target.offsetWidth;
  15063. if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
  15064. target = target.previousSibling;
  15065. }
  15066. } else if (dir === 'v1' && target.parentNode.previousSibling) {
  15067. var position = domUtils.getXY(target),
  15068. cellHeight = target.offsetHeight;
  15069. if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
  15070. target = target.parentNode.previousSibling.firstChild;
  15071. }
  15072. }
  15073. //排除了非td内部以及用于代码高亮部分的td
  15074. return target && !(editor.fireEvent("excludetable", target) === true) ? target : null;
  15075. }
  15076. };
  15077. ///import core
  15078. ///commands 右键菜单
  15079. ///commandsName ContextMenu
  15080. ///commandsTitle 右键菜单
  15081. /**
  15082. * 右键菜单
  15083. * @function
  15084. * @name baidu.editor.plugins.contextmenu
  15085. * @author zhanyi
  15086. */
  15087. UE.plugins['contextmenu'] = function () {
  15088. var me = this,
  15089. lang = me.getLang("contextMenu"),
  15090. menu,
  15091. items = me.options.contextMenu || [
  15092. {label: lang['selectall'], cmdName: 'selectall'},
  15093. {
  15094. label: lang.deletecode,
  15095. cmdName: 'highlightcode',
  15096. icon: 'deletehighlightcode'
  15097. },
  15098. {
  15099. label: lang.cleardoc,
  15100. cmdName: 'cleardoc',
  15101. exec: function () {
  15102. if (confirm(lang.confirmclear)) {
  15103. this.execCommand('cleardoc');
  15104. }
  15105. }
  15106. },
  15107. '-',
  15108. {
  15109. label: lang.unlink,
  15110. cmdName: 'unlink'
  15111. },
  15112. '-',
  15113. {
  15114. group: lang.paragraph,
  15115. icon: 'justifyjustify',
  15116. subMenu: [
  15117. {
  15118. label: lang.justifyleft,
  15119. cmdName: 'justify',
  15120. value: 'left'
  15121. },
  15122. {
  15123. label: lang.justifyright,
  15124. cmdName: 'justify',
  15125. value: 'right'
  15126. },
  15127. {
  15128. label: lang.justifycenter,
  15129. cmdName: 'justify',
  15130. value: 'center'
  15131. },
  15132. {
  15133. label: lang.justifyjustify,
  15134. cmdName: 'justify',
  15135. value: 'justify'
  15136. }
  15137. ]
  15138. },
  15139. '-',
  15140. {
  15141. group: lang.table,
  15142. icon: 'table',
  15143. subMenu: [
  15144. {
  15145. label: lang.inserttable,
  15146. cmdName: 'inserttable'
  15147. },
  15148. {
  15149. label: lang.deletetable,
  15150. cmdName: 'deletetable'
  15151. },
  15152. '-',
  15153. {
  15154. label: lang.deleterow,
  15155. cmdName: 'deleterow'
  15156. },
  15157. {
  15158. label: lang.deletecol,
  15159. cmdName: 'deletecol'
  15160. },
  15161. {
  15162. label: lang.insertcol,
  15163. cmdName: 'insertcol'
  15164. },
  15165. {
  15166. label: lang.insertcolnext,
  15167. cmdName: 'insertcolnext'
  15168. },
  15169. {
  15170. label: lang.insertrow,
  15171. cmdName: 'insertrow'
  15172. },
  15173. {
  15174. label: lang.insertrownext,
  15175. cmdName: 'insertrownext'
  15176. },
  15177. '-',
  15178. {
  15179. label: lang.insertcaption,
  15180. cmdName: 'insertcaption'
  15181. },
  15182. {
  15183. label: lang.deletecaption,
  15184. cmdName: 'deletecaption'
  15185. },
  15186. {
  15187. label: lang.inserttitle,
  15188. cmdName: 'inserttitle'
  15189. },
  15190. {
  15191. label: lang.deletetitle,
  15192. cmdName: 'deletetitle'
  15193. },
  15194. '-',
  15195. {
  15196. label: lang.mergecells,
  15197. cmdName: 'mergecells'
  15198. },
  15199. {
  15200. label: lang.mergeright,
  15201. cmdName: 'mergeright'
  15202. },
  15203. {
  15204. label: lang.mergedown,
  15205. cmdName: 'mergedown'
  15206. },
  15207. '-',
  15208. {
  15209. label: lang.splittorows,
  15210. cmdName: 'splittorows'
  15211. },
  15212. {
  15213. label: lang.splittocols,
  15214. cmdName: 'splittocols'
  15215. },
  15216. {
  15217. label: lang.splittocells,
  15218. cmdName: 'splittocells'
  15219. },
  15220. '-',
  15221. {
  15222. label: lang.averageDiseRow,
  15223. cmdName: 'averagedistributerow'
  15224. },
  15225. {
  15226. label: lang.averageDisCol,
  15227. cmdName: 'averagedistributecol'
  15228. },
  15229. '-',
  15230. {
  15231. label: lang.edittd,
  15232. cmdName: 'edittd',
  15233. exec: function () {
  15234. if (UE.ui['edittd']) {
  15235. new UE.ui['edittd'](this);
  15236. }
  15237. this.getDialog('edittd').open();
  15238. }
  15239. },
  15240. {
  15241. label: lang.edittable,
  15242. cmdName: 'edittable',
  15243. exec: function () {
  15244. if (UE.ui['edittable']) {
  15245. new UE.ui['edittable'](this);
  15246. }
  15247. this.getDialog('edittable').open();
  15248. }
  15249. }
  15250. ]
  15251. },
  15252. {
  15253. group: lang.tablesort,
  15254. icon: 'tablesort',
  15255. subMenu: [
  15256. {
  15257. label: lang.reversecurrent,
  15258. cmdName: 'sorttable',
  15259. value: 1
  15260. },
  15261. {
  15262. label: lang.orderbyasc,
  15263. cmdName: 'sorttable'
  15264. },
  15265. {
  15266. label: lang.reversebyasc,
  15267. cmdName: 'sorttable',
  15268. exec: function () {
  15269. this.execCommand("sorttable", function (td1, td2) {
  15270. var value1 = td1.innerHTML,
  15271. value2 = td2.innerHTML;
  15272. return value2.localeCompare(value1);
  15273. });
  15274. }
  15275. },
  15276. {
  15277. label: lang.orderbynum,
  15278. cmdName: 'sorttable',
  15279. exec: function () {
  15280. this.execCommand("sorttable", function (td1, td2) {
  15281. var value1 = td1[browser.ie ? 'innerText' : 'textContent'].match(/\d+/),
  15282. value2 = td2[browser.ie ? 'innerText' : 'textContent'].match(/\d+/);
  15283. if (value1) value1 = +value1[0];
  15284. if (value2) value2 = +value2[0];
  15285. return (value1 || 0) - (value2 || 0);
  15286. });
  15287. }
  15288. },
  15289. {
  15290. label: lang.reversebynum,
  15291. cmdName: 'sorttable',
  15292. exec: function () {
  15293. this.execCommand("sorttable", function (td1, td2) {
  15294. var value1 = td1[browser.ie ? 'innerText' : 'textContent'].match(/\d+/),
  15295. value2 = td2[browser.ie ? 'innerText' : 'textContent'].match(/\d+/);
  15296. if (value1) value1 = +value1[0];
  15297. if (value2) value2 = +value2[0];
  15298. return (value2 || 0) - (value1 || 0);
  15299. });
  15300. }
  15301. }
  15302. ]
  15303. },
  15304. {
  15305. group: lang.borderbk,
  15306. icon: 'borderBack',
  15307. subMenu: [
  15308. {
  15309. label: lang.setcolor,
  15310. cmdName: "interlacetable",
  15311. exec: function () {
  15312. this.execCommand("interlacetable");
  15313. }
  15314. },
  15315. {
  15316. label: lang.unsetcolor,
  15317. cmdName: "uninterlacetable",
  15318. exec: function () {
  15319. this.execCommand("uninterlacetable");
  15320. }
  15321. },
  15322. {
  15323. label: lang.setbackground,
  15324. cmdName: "settablebackground",
  15325. exec: function () {
  15326. this.execCommand("settablebackground", {repeat: true, colorList: ["#bbb", "#ccc"]});
  15327. }
  15328. },
  15329. {
  15330. label: lang.unsetbackground,
  15331. cmdName: "cleartablebackground",
  15332. exec: function () {
  15333. this.execCommand("cleartablebackground");
  15334. }
  15335. },
  15336. {
  15337. label: lang.redandblue,
  15338. cmdName: "settablebackground",
  15339. exec: function () {
  15340. this.execCommand("settablebackground", {repeat: true, colorList: ["red", "blue"]});
  15341. }
  15342. },
  15343. {
  15344. label: lang.threecolorgradient,
  15345. cmdName: "settablebackground",
  15346. exec: function () {
  15347. this.execCommand("settablebackground", {repeat: true, colorList: ["#aaa", "#bbb", "#ccc"]});
  15348. }
  15349. }
  15350. ]
  15351. },
  15352. {
  15353. group: lang.aligntd,
  15354. icon: 'aligntd',
  15355. subMenu: [
  15356. {
  15357. cmdName: 'cellalignment',
  15358. value: {align: 'left', vAlign: 'top'}
  15359. },
  15360. {
  15361. cmdName: 'cellalignment',
  15362. value: {align: 'center', vAlign: 'top'}
  15363. },
  15364. {
  15365. cmdName: 'cellalignment',
  15366. value: {align: 'right', vAlign: 'top'}
  15367. },
  15368. {
  15369. cmdName: 'cellalignment',
  15370. value: {align: 'left', vAlign: 'middle'}
  15371. },
  15372. {
  15373. cmdName: 'cellalignment',
  15374. value: {align: 'center', vAlign: 'middle'}
  15375. },
  15376. {
  15377. cmdName: 'cellalignment',
  15378. value: {align: 'right', vAlign: 'middle'}
  15379. },
  15380. {
  15381. cmdName: 'cellalignment',
  15382. value: {align: 'left', vAlign: 'bottom'}
  15383. },
  15384. {
  15385. cmdName: 'cellalignment',
  15386. value: {align: 'center', vAlign: 'bottom'}
  15387. },
  15388. {
  15389. cmdName: 'cellalignment',
  15390. value: {align: 'right', vAlign: 'bottom'}
  15391. }
  15392. ]
  15393. },
  15394. {
  15395. group: lang.aligntable,
  15396. icon: 'aligntable',
  15397. subMenu: [
  15398. {
  15399. cmdName: 'tablealignment',
  15400. className: 'left',
  15401. label: lang.tableleft,
  15402. value: "left"
  15403. },
  15404. {
  15405. cmdName: 'tablealignment',
  15406. className: 'center',
  15407. label: lang.tablecenter,
  15408. value: "center"
  15409. },
  15410. {
  15411. cmdName: 'tablealignment',
  15412. className: 'right',
  15413. label: lang.tableright,
  15414. value: "right"
  15415. }
  15416. ]
  15417. },
  15418. '-',
  15419. {
  15420. label: lang.insertparagraphbefore,
  15421. cmdName: 'insertparagraph',
  15422. value: true
  15423. },
  15424. {
  15425. label: lang.insertparagraphafter,
  15426. cmdName: 'insertparagraph'
  15427. },
  15428. {
  15429. label: lang['copy'],
  15430. cmdName: 'copy',
  15431. exec: function () {
  15432. alert(lang.copymsg);
  15433. },
  15434. query: function () {
  15435. return 0;
  15436. }
  15437. },
  15438. {
  15439. label: lang['paste'],
  15440. cmdName: 'paste',
  15441. exec: function () {
  15442. alert(lang.pastemsg);
  15443. },
  15444. query: function () {
  15445. return 0;
  15446. }
  15447. },
  15448. {
  15449. label: lang['highlightcode'],
  15450. cmdName: 'highlightcode',
  15451. exec: function () {
  15452. if (UE.ui['highlightcode']) {
  15453. new UE.ui['highlightcode'](this);
  15454. }
  15455. this.ui._dialogs['highlightcodeDialog'].open();
  15456. }
  15457. }
  15458. ];
  15459. if (!items.length) {
  15460. return;
  15461. }
  15462. var uiUtils = UE.ui.uiUtils;
  15463. me.addListener('contextmenu', function (type, evt) {
  15464. var offset = uiUtils.getViewportOffsetByEvent(evt);
  15465. me.fireEvent('beforeselectionchange');
  15466. if (menu) {
  15467. menu.destroy();
  15468. }
  15469. for (var i = 0, ti, contextItems = []; ti = items[i]; i++) {
  15470. var last;
  15471. (function (item) {
  15472. if (item == '-') {
  15473. if ((last = contextItems[contextItems.length - 1 ] ) && last !== '-') {
  15474. contextItems.push('-');
  15475. }
  15476. } else if (item.hasOwnProperty("group")) {
  15477. for (var j = 0, cj, subMenu = []; cj = item.subMenu[j]; j++) {
  15478. (function (subItem) {
  15479. if (subItem == '-') {
  15480. if ((last = subMenu[subMenu.length - 1 ] ) && last !== '-') {
  15481. subMenu.push('-');
  15482. } else {
  15483. subMenu.splice(subMenu.length - 1);
  15484. }
  15485. } else {
  15486. if ((me.commands[subItem.cmdName] || UE.commands[subItem.cmdName] || subItem.query) &&
  15487. (subItem.query ? subItem.query() : me.queryCommandState(subItem.cmdName)) > -1) {
  15488. subMenu.push({
  15489. 'label': subItem.label || me.getLang("contextMenu." + subItem.cmdName + (subItem.value || '')) || "",
  15490. 'className': 'edui-for-' + subItem.cmdName + ( subItem.className ? ( ' edui-for-' + subItem.cmdName + '-' + subItem.className ) : '' ),
  15491. onclick: subItem.exec ? function () {
  15492. subItem.exec.call(me);
  15493. } : function () {
  15494. me.execCommand(subItem.cmdName, subItem.value);
  15495. }
  15496. });
  15497. }
  15498. }
  15499. })(cj);
  15500. }
  15501. if (subMenu.length) {
  15502. function getLabel() {
  15503. switch (item.icon) {
  15504. case "table":
  15505. return me.getLang("contextMenu.table");
  15506. case "justifyjustify":
  15507. return me.getLang("contextMenu.paragraph");
  15508. case "aligntd":
  15509. return me.getLang("contextMenu.aligntd");
  15510. case "aligntable":
  15511. return me.getLang("contextMenu.aligntable");
  15512. case "tablesort":
  15513. return lang.tablesort;
  15514. case "borderBack":
  15515. return lang.borderbk;
  15516. default :
  15517. return '';
  15518. }
  15519. }
  15520. contextItems.push({
  15521. //todo 修正成自动获取方式
  15522. 'label': getLabel(),
  15523. className: 'edui-for-' + item.icon,
  15524. 'subMenu': {
  15525. items: subMenu,
  15526. editor: me
  15527. }
  15528. });
  15529. }
  15530. } else {
  15531. //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
  15532. if ((me.commands[item.cmdName] || UE.commands[item.cmdName] || item.query) &&
  15533. (item.query ? item.query.call(me) : me.queryCommandState(item.cmdName)) > -1) {
  15534. //highlight todo
  15535. if (item.cmdName == 'highlightcode') {
  15536. if (me.queryCommandState(item.cmdName) == 1 && item.icon != 'deletehighlightcode') {
  15537. return;
  15538. }
  15539. if (me.queryCommandState(item.cmdName) != 1 && item.icon == 'deletehighlightcode') {
  15540. return;
  15541. }
  15542. }
  15543. contextItems.push({
  15544. 'label': item.label || me.getLang("contextMenu." + item.cmdName),
  15545. className: 'edui-for-' + (item.icon ? item.icon : item.cmdName + (item.value || '')),
  15546. onclick: item.exec ? function () {
  15547. item.exec.call(me);
  15548. } : function () {
  15549. me.execCommand(item.cmdName, item.value);
  15550. }
  15551. });
  15552. }
  15553. }
  15554. })(ti);
  15555. }
  15556. if (contextItems[contextItems.length - 1] == '-') {
  15557. contextItems.pop();
  15558. }
  15559. menu = new UE.ui.Menu({
  15560. items: contextItems,
  15561. className: "edui-contextmenu",
  15562. editor: me
  15563. });
  15564. menu.render();
  15565. menu.showAt(offset);
  15566. me.fireEvent("aftershowcontextmenu", menu);
  15567. domUtils.preventDefault(evt);
  15568. if (browser.ie) {
  15569. var ieRange;
  15570. try {
  15571. ieRange = me.selection.getNative().createRange();
  15572. } catch (e) {
  15573. return;
  15574. }
  15575. if (ieRange.item) {
  15576. var range = new dom.Range(me.document);
  15577. range.selectNode(ieRange.item(0)).select(true, true);
  15578. }
  15579. }
  15580. });
  15581. };
  15582. ///import core
  15583. ///commands 弹出菜单
  15584. // commandsName popupmenu
  15585. ///commandsTitle 弹出菜单
  15586. /**
  15587. * 弹出菜单
  15588. * @function
  15589. * @name baidu.editor.plugins.popupmenu
  15590. * @author xuheng
  15591. */
  15592. UE.plugins['shortcutmenu'] = function () {
  15593. var me = this,
  15594. menu,
  15595. items = me.options.shortcutMenu || [];
  15596. if (!items.length) {
  15597. return;
  15598. }
  15599. me.addListener('contextmenu mouseup', function (type, e) {
  15600. var me = this,
  15601. customEvt = {
  15602. type: type,
  15603. target: e.target || e.srcElement,
  15604. screenX: e.screenX,
  15605. screenY: e.screenY,
  15606. clientX: e.clientX,
  15607. clientY: e.clientY
  15608. };
  15609. setTimeout(function () {
  15610. var rng = me.selection.getRange();
  15611. if (rng.collapsed === false || type == "contextmenu") {
  15612. if (!menu) {
  15613. menu = new baidu.editor.ui.ShortCutMenu({
  15614. editor: me,
  15615. items: items,
  15616. theme: me.options.theme,
  15617. className: 'edui-shortcutmenu'
  15618. });
  15619. menu.render();
  15620. me.fireEvent("afterrendershortcutmenu", menu);
  15621. }
  15622. menu.show(customEvt, !!UE.plugins['contextmenu']);
  15623. }
  15624. });
  15625. if (type == 'contextmenu') {
  15626. domUtils.preventDefault(e);
  15627. if (browser.ie) {
  15628. var ieRange;
  15629. try {
  15630. ieRange = me.selection.getNative().createRange();
  15631. } catch (e) {
  15632. return;
  15633. }
  15634. if (ieRange.item) {
  15635. var range = new dom.Range(me.document);
  15636. range.selectNode(ieRange.item(0)).select(true, true);
  15637. }
  15638. }
  15639. }
  15640. if (type == "keydown") {
  15641. menu && !menu.isHidden && menu.hide();
  15642. }
  15643. });
  15644. me.addListener('keydown', function (type) {
  15645. if (type == "keydown") {
  15646. menu && !menu.isHidden && menu.hide();
  15647. }
  15648. });
  15649. };
  15650. ///import core
  15651. ///commands 加粗,斜体,上标,下标
  15652. ///commandsName Bold,Italic,Subscript,Superscript
  15653. ///commandsTitle 加粗,加斜,下标,上标
  15654. /**
  15655. * b u i等基础功能实现
  15656. * @function
  15657. * @name baidu.editor.execCommands
  15658. * @param {String} cmdName bold加粗。italic斜体。subscript上标。superscript下标。
  15659. */
  15660. UE.plugins['basestyle'] = function () {
  15661. var basestyles = {
  15662. 'bold': ['strong', 'b'],
  15663. 'italic': ['em', 'i'],
  15664. 'subscript': ['sub'],
  15665. 'superscript': ['sup']
  15666. },
  15667. getObj = function (editor, tagNames) {
  15668. return domUtils.filterNodeList(editor.selection.getStartElementPath(), tagNames);
  15669. },
  15670. me = this;
  15671. //添加快捷键
  15672. me.addshortcutkey({
  15673. "Bold": "ctrl+66",//^B
  15674. "Italic": "ctrl+73", //^I
  15675. "Underline": "ctrl+85"//^U
  15676. });
  15677. me.addInputRule(function (root) {
  15678. utils.each(root.getNodesByTagName('b i'), function (node) {
  15679. switch (node.tagName) {
  15680. case 'b':
  15681. node.tagName = 'strong';
  15682. break;
  15683. case 'i':
  15684. node.tagName = 'em';
  15685. }
  15686. });
  15687. });
  15688. for (var style in basestyles) {
  15689. (function (cmd, tagNames) {
  15690. me.commands[cmd] = {
  15691. execCommand: function (cmdName) {
  15692. var range = me.selection.getRange(), obj = getObj(this, tagNames);
  15693. if (range.collapsed) {
  15694. if (obj) {
  15695. var tmpText = me.document.createTextNode('');
  15696. range.insertNode(tmpText).removeInlineStyle(tagNames);
  15697. range.setStartBefore(tmpText);
  15698. domUtils.remove(tmpText);
  15699. } else {
  15700. var tmpNode = range.document.createElement(tagNames[0]);
  15701. if (cmdName == 'superscript' || cmdName == 'subscript') {
  15702. tmpText = me.document.createTextNode('');
  15703. range.insertNode(tmpText)
  15704. .removeInlineStyle(['sub', 'sup'])
  15705. .setStartBefore(tmpText)
  15706. .collapse(true);
  15707. }
  15708. range.insertNode(tmpNode).setStart(tmpNode, 0);
  15709. }
  15710. range.collapse(true);
  15711. } else {
  15712. if (cmdName == 'superscript' || cmdName == 'subscript') {
  15713. if (!obj || obj.tagName.toLowerCase() != cmdName) {
  15714. range.removeInlineStyle(['sub', 'sup']);
  15715. }
  15716. }
  15717. obj ? range.removeInlineStyle(tagNames) : range.applyInlineStyle(tagNames[0]);
  15718. }
  15719. range.select();
  15720. },
  15721. queryCommandState: function () {
  15722. return getObj(this, tagNames) ? 1 : 0;
  15723. }
  15724. };
  15725. })(style, basestyles[style]);
  15726. }
  15727. };
  15728. ///import core
  15729. ///commands 选区路径
  15730. ///commandsName ElementPath,elementPathEnabled
  15731. ///commandsTitle 选区路径
  15732. /**
  15733. * 选区路径
  15734. * @function
  15735. * @name baidu.editor.execCommand
  15736. * @param {String} cmdName elementpath选区路径
  15737. */
  15738. UE.plugins['elementpath'] = function () {
  15739. var currentLevel,
  15740. tagNames,
  15741. me = this;
  15742. me.setOpt('elementPathEnabled', true);
  15743. if (!me.options.elementPathEnabled) {
  15744. return;
  15745. }
  15746. me.commands['elementpath'] = {
  15747. execCommand: function (cmdName, level) {
  15748. var start = tagNames[level],
  15749. range = me.selection.getRange();
  15750. currentLevel = level * 1;
  15751. range.selectNode(start).select();
  15752. },
  15753. queryCommandValue: function () {
  15754. //产生一个副本,不能修改原来的startElementPath;
  15755. var parents = [].concat(this.selection.getStartElementPath()).reverse(),
  15756. names = [];
  15757. tagNames = parents;
  15758. for (var i = 0, ci; ci = parents[i]; i++) {
  15759. if (ci.nodeType == 3) {
  15760. continue;
  15761. }
  15762. var name = ci.tagName.toLowerCase();
  15763. if (name == 'img' && ci.getAttribute('anchorname')) {
  15764. name = 'anchor';
  15765. }
  15766. names[i] = name;
  15767. if (currentLevel == i) {
  15768. currentLevel = -1;
  15769. break;
  15770. }
  15771. }
  15772. return names;
  15773. }
  15774. };
  15775. };
  15776. ///import core
  15777. ///import plugins\removeformat.js
  15778. ///commands 格式刷
  15779. ///commandsName FormatMatch
  15780. ///commandsTitle 格式刷
  15781. /**
  15782. * 格式刷,只格式inline的
  15783. * @function
  15784. * @name baidu.editor.execCommand
  15785. * @param {String} cmdName formatmatch执行格式刷
  15786. */
  15787. UE.plugins['formatmatch'] = function () {
  15788. var me = this,
  15789. list = [], img,
  15790. flag = 0;
  15791. me.addListener('reset', function () {
  15792. list = [];
  15793. flag = 0;
  15794. });
  15795. function addList(type, evt) {
  15796. if (browser.webkit) {
  15797. var target = evt.target.tagName == 'IMG' ? evt.target : null;
  15798. }
  15799. function addFormat(range) {
  15800. if (text) {
  15801. range.selectNode(text);
  15802. }
  15803. return range.applyInlineStyle(list[list.length - 1].tagName, null, list);
  15804. }
  15805. me.undoManger && me.undoManger.save();
  15806. var range = me.selection.getRange(),
  15807. imgT = target || range.getClosedNode();
  15808. if (img && imgT && imgT.tagName == 'IMG') {
  15809. //trace:964
  15810. imgT.style.cssText += ';float:' + (img.style.cssFloat || img.style.styleFloat || 'none') + ';display:' + (img.style.display || 'inline');
  15811. img = null;
  15812. } else {
  15813. if (!img) {
  15814. var collapsed = range.collapsed;
  15815. if (collapsed) {
  15816. var text = me.document.createTextNode('match');
  15817. range.insertNode(text).select();
  15818. }
  15819. me.__hasEnterExecCommand = true;
  15820. //不能把block上的属性干掉
  15821. //trace:1553
  15822. var removeFormatAttributes = me.options.removeFormatAttributes;
  15823. me.options.removeFormatAttributes = '';
  15824. me.execCommand('removeformat');
  15825. me.options.removeFormatAttributes = removeFormatAttributes;
  15826. me.__hasEnterExecCommand = false;
  15827. //trace:969
  15828. range = me.selection.getRange();
  15829. if (list.length) {
  15830. addFormat(range);
  15831. }
  15832. if (text) {
  15833. range.setStartBefore(text).collapse(true);
  15834. }
  15835. range.select();
  15836. text && domUtils.remove(text);
  15837. }
  15838. }
  15839. me.undoManger && me.undoManger.save();
  15840. me.removeListener('mouseup', addList);
  15841. flag = 0;
  15842. }
  15843. me.commands['formatmatch'] = {
  15844. execCommand: function (cmdName) {
  15845. if (flag) {
  15846. flag = 0;
  15847. list = [];
  15848. me.removeListener('mouseup', addList);
  15849. return;
  15850. }
  15851. var range = me.selection.getRange();
  15852. img = range.getClosedNode();
  15853. if (!img || img.tagName != 'IMG') {
  15854. range.collapse(true).shrinkBoundary();
  15855. var start = range.startContainer;
  15856. list = domUtils.findParents(start, true, function (node) {
  15857. return !domUtils.isBlockElm(node) && node.nodeType == 1;
  15858. });
  15859. //a不能加入格式刷, 并且克隆节点
  15860. for (var i = 0, ci; ci = list[i]; i++) {
  15861. if (ci.tagName == 'A') {
  15862. list.splice(i, 1);
  15863. break;
  15864. }
  15865. }
  15866. }
  15867. me.addListener('mouseup', addList);
  15868. flag = 1;
  15869. },
  15870. queryCommandState: function () {
  15871. return flag;
  15872. },
  15873. notNeedUndo: 1
  15874. };
  15875. };
  15876. ///import core
  15877. ///commands 查找替换
  15878. ///commandsName SearchReplace
  15879. ///commandsTitle 查询替换
  15880. ///commandsDialog dialogs\searchreplace
  15881. /**
  15882. * @description 查找替换
  15883. * @author zhanyi
  15884. */
  15885. UE.plugins['searchreplace'] = function () {
  15886. var currentRange,
  15887. first,
  15888. me = this;
  15889. me.addListener('reset', function () {
  15890. currentRange = null;
  15891. first = null;
  15892. });
  15893. me.commands['searchreplace'] = {
  15894. execCommand: function (cmdName, opt) {
  15895. var me = this,
  15896. sel = me.selection,
  15897. range,
  15898. nativeRange,
  15899. num = 0,
  15900. opt = utils.extend(opt, {
  15901. all: false,
  15902. casesensitive: false,
  15903. dir: 1
  15904. }, true);
  15905. var searchStr = opt.searchStr;
  15906. if (browser.ie) {
  15907. me.focus();
  15908. while (1) {
  15909. var tmpRange;
  15910. nativeRange = me.document.selection.createRange();
  15911. tmpRange = nativeRange.duplicate();
  15912. tmpRange.moveToElementText(me.document.body);
  15913. if (opt.all) {
  15914. first = 0;
  15915. opt.dir = 1;
  15916. if (currentRange) {
  15917. tmpRange.setEndPoint(opt.dir == -1 ? 'EndToStart' : 'StartToEnd', currentRange);
  15918. } else {
  15919. tmpRange.moveToElementText(me.document.body);
  15920. }
  15921. } else {
  15922. tmpRange.setEndPoint(opt.dir == -1 ? 'EndToStart' : 'StartToEnd', nativeRange);
  15923. if (opt.hasOwnProperty("replaceStr")) {
  15924. tmpRange.setEndPoint(opt.dir == -1 ? 'StartToEnd' : 'EndToStart', nativeRange);
  15925. }
  15926. }
  15927. nativeRange = tmpRange.duplicate();
  15928. if (/^\/[^/]+\/\w*$/.test(opt.searchStr)) {
  15929. var str = tmpRange.text,
  15930. reg = new RegExp(opt.searchStr.replace(/^\/|\/\w*$/g, ''), 'g' + (opt.casesensitive ? '' : 'i'));
  15931. var match = str.match(reg);
  15932. if (match && match.length) {
  15933. searchStr = opt.dir < 0 ? match[match.length - 1] : match[0];
  15934. } else {
  15935. currentRange = null;
  15936. return num;
  15937. }
  15938. }
  15939. if (!tmpRange.findText(searchStr, opt.dir, opt.casesensitive ? 4 : 0)) {
  15940. currentRange = null;
  15941. tmpRange = me.document.selection.createRange();
  15942. tmpRange.scrollIntoView();
  15943. currentRange = null;
  15944. return num;
  15945. }
  15946. tmpRange.select();
  15947. //替换
  15948. if (opt.hasOwnProperty("replaceStr")) {
  15949. range = sel.getRange();
  15950. range.deleteContents().insertNode(range.document.createTextNode(opt.replaceStr)).select();
  15951. currentRange = sel.getNative().createRange();
  15952. }
  15953. num++;
  15954. if (!opt.all) {
  15955. break;
  15956. }
  15957. }
  15958. } else {
  15959. var w = me.window, nativeSel = sel.getNative();
  15960. while (1) {
  15961. if (opt.all) {
  15962. if (currentRange) {
  15963. currentRange.collapse(false);
  15964. nativeRange = currentRange;
  15965. } else {
  15966. nativeRange = me.document.createRange();
  15967. nativeRange.setStart(me.document.body, 0);
  15968. nativeRange.collapse(true);
  15969. }
  15970. nativeSel.removeAllRanges();
  15971. nativeSel.addRange(nativeRange);
  15972. first = 0;
  15973. opt.dir = 1;
  15974. } else {
  15975. //safari弹出层,原生已经找不到range了,所以需要先选回来,再取原生
  15976. if (browser.safari) {
  15977. me.selection.getRange().select();
  15978. }
  15979. var nativeSel = w.getSelection();
  15980. if (!nativeSel.rangeCount) {
  15981. nativeRange = currentRange || me._bakNativeRange;
  15982. } else {
  15983. nativeRange = nativeSel.getRangeAt(0);
  15984. }
  15985. if (opt.hasOwnProperty("replaceStr")) {
  15986. nativeRange.collapse(opt.dir == 1 ? true : false);
  15987. }
  15988. }
  15989. //如果是第一次并且海选中了内容那就要清除,为find做准备
  15990. if (!first) {
  15991. nativeRange.collapse(opt.dir < 0 ? true : false);
  15992. nativeSel.removeAllRanges();
  15993. nativeSel.addRange(nativeRange);
  15994. } else {
  15995. nativeSel.removeAllRanges();
  15996. }
  15997. //是正则查找
  15998. if (/^\/[^/]+\/\w*$/.test(opt.searchStr)) {
  15999. var tmpRange = nativeRange.cloneRange();
  16000. //向前查找
  16001. if (opt.dir < 0) {
  16002. nativeRange.collapse(true);
  16003. nativeRange.setStart(me.body, 0);
  16004. } else {
  16005. nativeRange.setEnd(me.body, me.body.childNodes.length);
  16006. }
  16007. var str = nativeRange + '',
  16008. reg = new RegExp(opt.searchStr.replace(/^\/|\/\w*$/g, ''), 'g' + (opt.casesensitive ? '' : 'i'));
  16009. var match = str.match(reg);
  16010. if (match && match.length) {
  16011. searchStr = opt.dir < 0 ? match[match.length - 1] : match[0];
  16012. } else {
  16013. currentRange = null;
  16014. return num;
  16015. }
  16016. nativeSel.removeAllRanges();
  16017. nativeRange = tmpRange;
  16018. nativeSel.addRange(nativeRange);
  16019. }
  16020. if (!w.find(searchStr, opt.casesensitive, opt.dir < 0 ? true : false)) {
  16021. currentRange = null;
  16022. nativeSel.removeAllRanges();
  16023. return num;
  16024. }
  16025. first = 0;
  16026. range = w.getSelection().getRangeAt(0);
  16027. if (!range.collapsed) {
  16028. if (opt.hasOwnProperty("replaceStr")) {
  16029. range.deleteContents();
  16030. var text = w.document.createTextNode(opt.replaceStr);
  16031. range.insertNode(text);
  16032. range.selectNode(text);
  16033. nativeSel.addRange(range);
  16034. }
  16035. currentRange = range.cloneRange();
  16036. }
  16037. num++;
  16038. if (!opt.all) {
  16039. break;
  16040. }
  16041. }
  16042. }
  16043. return true;
  16044. }
  16045. };
  16046. };
  16047. ///import core
  16048. ///commands 自定义样式
  16049. ///commandsName CustomStyle
  16050. ///commandsTitle 自定义样式
  16051. UE.plugins['customstyle'] = function () {
  16052. var me = this;
  16053. me.setOpt({ 'customstyle': [
  16054. {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;'},
  16055. {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;'},
  16056. {tag: 'span', name: 'im', style: 'font-size:16px;font-style:italic;font-weight:bold;line-height:18px;'},
  16057. {tag: 'span', name: 'hi', style: 'font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;'}
  16058. ]});
  16059. me.commands['customstyle'] = {
  16060. execCommand: function (cmdName, obj) {
  16061. var me = this,
  16062. tagName = obj.tag,
  16063. node = domUtils.findParent(me.selection.getStart(), function (node) {
  16064. return node.getAttribute('label');
  16065. }, true),
  16066. range, bk, tmpObj = {};
  16067. for (var p in obj) {
  16068. if (obj[p] !== undefined)
  16069. tmpObj[p] = obj[p];
  16070. }
  16071. delete tmpObj.tag;
  16072. if (node && node.getAttribute('label') == obj.label) {
  16073. range = this.selection.getRange();
  16074. bk = range.createBookmark();
  16075. if (range.collapsed) {
  16076. //trace:1732 删掉自定义标签,要有p来回填站位
  16077. if (dtd.$block[node.tagName]) {
  16078. var fillNode = me.document.createElement('p');
  16079. domUtils.moveChild(node, fillNode);
  16080. node.parentNode.insertBefore(fillNode, node);
  16081. domUtils.remove(node);
  16082. } else {
  16083. domUtils.remove(node, true);
  16084. }
  16085. } else {
  16086. var common = domUtils.getCommonAncestor(bk.start, bk.end),
  16087. nodes = domUtils.getElementsByTagName(common, tagName);
  16088. if (new RegExp(tagName, 'i').test(common.tagName)) {
  16089. nodes.push(common);
  16090. }
  16091. for (var i = 0, ni; ni = nodes[i++];) {
  16092. if (ni.getAttribute('label') == obj.label) {
  16093. var ps = domUtils.getPosition(ni, bk.start), pe = domUtils.getPosition(ni, bk.end);
  16094. if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS)
  16095. &&
  16096. (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
  16097. )
  16098. if (dtd.$block[tagName]) {
  16099. var fillNode = me.document.createElement('p');
  16100. domUtils.moveChild(ni, fillNode);
  16101. ni.parentNode.insertBefore(fillNode, ni);
  16102. }
  16103. domUtils.remove(ni, true);
  16104. }
  16105. }
  16106. node = domUtils.findParent(common, function (node) {
  16107. return node.getAttribute('label') == obj.label;
  16108. }, true);
  16109. if (node) {
  16110. domUtils.remove(node, true);
  16111. }
  16112. }
  16113. range.moveToBookmark(bk).select();
  16114. } else {
  16115. if (dtd.$block[tagName]) {
  16116. this.execCommand('paragraph', tagName, tmpObj, 'customstyle');
  16117. range = me.selection.getRange();
  16118. if (!range.collapsed) {
  16119. range.collapse();
  16120. node = domUtils.findParent(me.selection.getStart(), function (node) {
  16121. return node.getAttribute('label') == obj.label;
  16122. }, true);
  16123. var pNode = me.document.createElement('p');
  16124. domUtils.insertAfter(node, pNode);
  16125. domUtils.fillNode(me.document, pNode);
  16126. range.setStart(pNode, 0).setCursor();
  16127. }
  16128. } else {
  16129. range = me.selection.getRange();
  16130. if (range.collapsed) {
  16131. node = me.document.createElement(tagName);
  16132. domUtils.setAttributes(node, tmpObj);
  16133. range.insertNode(node).setStart(node, 0).setCursor();
  16134. return;
  16135. }
  16136. bk = range.createBookmark();
  16137. range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select();
  16138. }
  16139. }
  16140. },
  16141. queryCommandValue: function () {
  16142. var parent = domUtils.filterNodeList(
  16143. this.selection.getStartElementPath(),
  16144. function (node) {
  16145. return node.getAttribute('label')
  16146. }
  16147. );
  16148. return parent ? parent.getAttribute('label') : '';
  16149. }
  16150. };
  16151. //当去掉customstyle是,如果是块元素,用p代替
  16152. me.addListener('keyup', function (type, evt) {
  16153. var keyCode = evt.keyCode || evt.which;
  16154. if (keyCode == 32 || keyCode == 13) {
  16155. var range = me.selection.getRange();
  16156. if (range.collapsed) {
  16157. var node = domUtils.findParent(me.selection.getStart(), function (node) {
  16158. return node.getAttribute('label');
  16159. }, true);
  16160. if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
  16161. var p = me.document.createElement('p');
  16162. domUtils.insertAfter(node, p);
  16163. domUtils.fillNode(me.document, p);
  16164. domUtils.remove(node);
  16165. range.setStart(p, 0).setCursor();
  16166. }
  16167. }
  16168. }
  16169. });
  16170. };
  16171. ///import core
  16172. ///commands 远程图片抓取
  16173. ///commandsName catchRemoteImage,catchremoteimageenable
  16174. ///commandsTitle 远程图片抓取
  16175. /**
  16176. * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
  16177. *
  16178. */
  16179. UE.plugins['catchremoteimage'] = function () {
  16180. if (this.options.catchRemoteImageEnable === false) {
  16181. return;
  16182. }
  16183. var me = this;
  16184. this.setOpt({
  16185. localDomain: ["127.0.0.1", "localhost", "img.baidu.com"],
  16186. separater: 'ue_separate_ue',
  16187. catchFieldName: "upfile",
  16188. catchRemoteImageEnable: true
  16189. });
  16190. var ajax = UE.ajax,
  16191. localDomain = me.options.localDomain ,
  16192. catcherUrl = me.options.catcherUrl,
  16193. separater = me.options.separater;
  16194. function catchremoteimage(imgs, callbacks) {
  16195. var submitStr = imgs.join(separater);
  16196. var tmpOption = {
  16197. timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
  16198. onsuccess: callbacks["success"],
  16199. onerror: callbacks["error"]
  16200. };
  16201. tmpOption[me.options.catchFieldName] = submitStr;
  16202. ajax.request(catcherUrl, tmpOption);
  16203. }
  16204. me.addListener("afterpaste", function () {
  16205. me.fireEvent("catchRemoteImage");
  16206. });
  16207. me.addListener("catchRemoteImage", function () {
  16208. var remoteImages = [];
  16209. var imgs = domUtils.getElementsByTagName(me.document, "img");
  16210. var test = function (src, urls) {
  16211. for (var j = 0, url; url = urls[j++];) {
  16212. if (src.indexOf(url) !== -1) {
  16213. return true;
  16214. }
  16215. }
  16216. return false;
  16217. };
  16218. for (var i = 0, ci; ci = imgs[i++];) {
  16219. if (ci.getAttribute("word_img")) {
  16220. continue;
  16221. }
  16222. var src = ci.getAttribute("_src") || ci.src || "";
  16223. if (/^(https?|ftp):/i.test(src) && !test(src, localDomain)) {
  16224. remoteImages.push(src);
  16225. }
  16226. }
  16227. if (remoteImages.length) {
  16228. catchremoteimage(remoteImages, {
  16229. //成功抓取
  16230. success: function (xhr) {
  16231. try {
  16232. var info = eval("(" + xhr.responseText + ")");
  16233. } catch (e) {
  16234. return;
  16235. }
  16236. var srcUrls = info.srcUrl.split(separater),
  16237. urls = info.url.split(separater);
  16238. for (var i = 0, ci; ci = imgs[i++];) {
  16239. var src = ci.getAttribute("_src") || ci.src || "";
  16240. for (var j = 0, cj; cj = srcUrls[j++];) {
  16241. var url = urls[j - 1];
  16242. if (src == cj && url != "error") { //抓取失败时不做替换处理
  16243. //地址修正
  16244. var newSrc = me.options.catcherPath + url;
  16245. domUtils.setAttributes(ci, {
  16246. "src": newSrc,
  16247. "_src": newSrc
  16248. });
  16249. break;
  16250. }
  16251. }
  16252. }
  16253. me.fireEvent('catchremotesuccess')
  16254. },
  16255. //回调失败,本次请求超时
  16256. error: function () {
  16257. me.fireEvent("catchremoteerror");
  16258. }
  16259. });
  16260. }
  16261. });
  16262. };
  16263. ///import core
  16264. ///import plugins\inserthtml.js
  16265. ///import plugins\image.js
  16266. ///commandsName snapscreen
  16267. ///commandsTitle 截屏
  16268. /**
  16269. * 截屏插件
  16270. */
  16271. UE.plugins['snapscreen'] = function () {
  16272. var me = this,
  16273. doc,
  16274. snapplugin;
  16275. me.setOpt({
  16276. snapscreenServerPort: location.port //屏幕截图的server端端口
  16277. , snapscreenImgAlign: '' //截图的图片默认的排版方式
  16278. , snapscreenHost: location.hostname //屏幕截图的server端文件所在的网站地址或者ip,请不要加http://
  16279. });
  16280. me.commands['snapscreen'] = {
  16281. execCommand: function () {
  16282. var me = this, lang = me.getLang("snapScreen_plugin");
  16283. if (!snapplugin) {
  16284. var container = me.container;
  16285. doc = container.ownerDocument || container.document;
  16286. snapplugin = doc.createElement("object");
  16287. try {
  16288. snapplugin.type = "application/x-pluginbaidusnap";
  16289. } catch (e) {
  16290. return;
  16291. }
  16292. snapplugin.style.cssText = "position:absolute;left:-9999px;";
  16293. snapplugin.setAttribute("width", "0");
  16294. snapplugin.setAttribute("height", "0");
  16295. container.appendChild(snapplugin);
  16296. }
  16297. var editorOptions = me.options;
  16298. var onSuccess = function (rs) {
  16299. try {
  16300. rs = eval("(" + rs + ")");
  16301. } catch (e) {
  16302. alert(lang.callBackErrorMsg);
  16303. return;
  16304. }
  16305. if (rs.state != 'SUCCESS') {
  16306. alert(rs.state);
  16307. return;
  16308. }
  16309. me.execCommand('insertimage', {
  16310. src: editorOptions.snapscreenPath + rs.url,
  16311. floatStyle: editorOptions.snapscreenImgAlign,
  16312. _src: editorOptions.snapscreenPath + rs.url
  16313. });
  16314. };
  16315. var onStartUpload = function () {
  16316. //开始截图上传
  16317. };
  16318. var onError = function () {
  16319. alert(lang.uploadErrorMsg);
  16320. };
  16321. try {
  16322. var port = editorOptions.snapscreenServerPort + '';
  16323. editorOptions.snapscreenServerUrl = editorOptions.snapscreenServerUrl.split(editorOptions.snapscreenHost);
  16324. editorOptions.snapscreenServerUrl = editorOptions.snapscreenServerUrl[1] || editorOptions.snapscreenServerUrl[0];
  16325. if (editorOptions.snapscreenServerUrl.indexOf(":" + port) === 0) {
  16326. editorOptions.snapscreenServerUrl = editorOptions.snapscreenServerUrl.substring(port.length + 1);
  16327. }
  16328. var ret = snapplugin.saveSnapshot(editorOptions.snapscreenHost, editorOptions.snapscreenServerUrl, port);
  16329. onSuccess(ret);
  16330. } catch (e) {
  16331. me.ui._dialogs['snapscreenDialog'].open();
  16332. }
  16333. }
  16334. };
  16335. }
  16336. ///import core
  16337. ///commands 插入空行
  16338. ///commandsName insertparagraph
  16339. ///commandsTitle 插入空行
  16340. /**
  16341. * 插入空行
  16342. * @function
  16343. * @name baidu.editor.execCommand
  16344. * @param {String} cmdName insertparagraph
  16345. */
  16346. UE.commands['insertparagraph'] = {
  16347. execCommand: function (cmdName, front) {
  16348. var me = this,
  16349. range = me.selection.getRange(),
  16350. start = range.startContainer, tmpNode;
  16351. while (start) {
  16352. if (domUtils.isBody(start)) {
  16353. break;
  16354. }
  16355. tmpNode = start;
  16356. start = start.parentNode;
  16357. }
  16358. if (tmpNode) {
  16359. var p = me.document.createElement('p');
  16360. if (front) {
  16361. tmpNode.parentNode.insertBefore(p, tmpNode)
  16362. } else {
  16363. tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling)
  16364. }
  16365. domUtils.fillNode(me.document, p);
  16366. range.setStart(p, 0).setCursor(false, true);
  16367. }
  16368. }
  16369. };
  16370. ///import core
  16371. ///import plugins/inserthtml.js
  16372. ///commands 百度应用
  16373. ///commandsName webapp
  16374. ///commandsTitle 百度应用
  16375. ///commandsDialog dialogs\webapp
  16376. UE.plugins['webapp'] = function () {
  16377. var me = this;
  16378. function createInsertStr(obj, toIframe, addParagraph) {
  16379. return !toIframe ?
  16380. (addParagraph ? '<p>' : '') + '<img title="' + obj.title + '" width="' + obj.width + '" height="' + obj.height + '"' +
  16381. ' 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 + '" />' +
  16382. (addParagraph ? '</p>' : '')
  16383. :
  16384. '<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>';
  16385. }
  16386. function switchImgAndIframe(img2frame) {
  16387. var tmpdiv,
  16388. nodes = domUtils.getElementsByTagName(me.document, !img2frame ? "iframe" : "img");
  16389. for (var i = 0, node; node = nodes[i++];) {
  16390. if (node.className != "edui-faked-webapp") {
  16391. continue;
  16392. }
  16393. tmpdiv = me.document.createElement("div");
  16394. 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);
  16395. node.parentNode.replaceChild(tmpdiv.firstChild, node);
  16396. }
  16397. }
  16398. me.addListener("beforegetcontent", function () {
  16399. switchImgAndIframe(true);
  16400. });
  16401. me.addListener('aftersetcontent', function () {
  16402. switchImgAndIframe(false);
  16403. });
  16404. me.addListener('aftergetcontent', function (cmdName) {
  16405. if (cmdName == 'aftergetcontent' && me.queryCommandState('source')) {
  16406. return;
  16407. }
  16408. switchImgAndIframe(false);
  16409. });
  16410. me.commands['webapp'] = {
  16411. execCommand: function (cmd, obj) {
  16412. me.execCommand("inserthtml", createInsertStr(obj, false, true));
  16413. }
  16414. };
  16415. };
  16416. ///import core
  16417. ///import plugins\inserthtml.js
  16418. ///import plugins\cleardoc.js
  16419. ///commands 模板
  16420. ///commandsName template
  16421. ///commandsTitle 模板
  16422. ///commandsDialog dialogs\template
  16423. UE.plugins['template'] = function () {
  16424. UE.commands['template'] = {
  16425. execCommand: function (cmd, obj) {
  16426. obj.html && this.execCommand("inserthtml", obj.html);
  16427. }
  16428. };
  16429. this.addListener("click", function (type, evt) {
  16430. var el = evt.target || evt.srcElement,
  16431. range = this.selection.getRange();
  16432. var tnode = domUtils.findParent(el, function (node) {
  16433. if (node.className && domUtils.hasClass(node, "ue_t")) {
  16434. return node;
  16435. }
  16436. }, true);
  16437. tnode && range.selectNode(tnode).shrinkBoundary().select();
  16438. });
  16439. this.addListener("keydown", function (type, evt) {
  16440. var range = this.selection.getRange();
  16441. if (!range.collapsed) {
  16442. if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  16443. var tnode = domUtils.findParent(range.startContainer, function (node) {
  16444. if (node.className && domUtils.hasClass(node, "ue_t")) {
  16445. return node;
  16446. }
  16447. }, true);
  16448. if (tnode) {
  16449. domUtils.removeClasses(tnode, ["ue_t"]);
  16450. }
  16451. }
  16452. }
  16453. });
  16454. };
  16455. ///import core
  16456. ///import plugins/inserthtml.js
  16457. ///commands 音乐
  16458. ///commandsName Music
  16459. ///commandsTitle 插入音乐
  16460. ///commandsDialog dialogs\music
  16461. UE.plugins['music'] = function () {
  16462. var me = this,
  16463. div;
  16464. /**
  16465. * 创建插入音乐字符窜
  16466. * @param url 音乐地址
  16467. * @param width 音乐宽度
  16468. * @param height 音乐高度
  16469. * @param align 阴雨对齐
  16470. * @param toEmbed 是否以flash代替显示
  16471. * @param addParagraph 是否需要添加P标签
  16472. */
  16473. function creatInsertStr(url, width, height, align, toEmbed, addParagraph) {
  16474. return !toEmbed ?
  16475. (addParagraph ? ('<p ' + (align != "none" ? ( align == "center" ? ' style="text-align:center;" ' : ' style="float:"' + align ) : '') + '>') : '') +
  16476. '<img align="' + align + '" width="' + width + '" height="' + height + '" _url="' + url + '" class="edui-faked-music"' +
  16477. ' src="' + me.options.langPath + me.options.lang + '/images/music.png" />' +
  16478. (addParagraph ? '</p>' : '')
  16479. :
  16480. '<embed type="application/x-shockwave-flash" class="edui-faked-music" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  16481. ' src="' + url + '" width="' + width + '" height="' + height + '" align="' + align + '"' +
  16482. ( align != "none" ? ' style= "' + ( align == "center" ? "display:block;" : " float: " + align ) + '"' : '' ) +
  16483. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  16484. }
  16485. function switchImgAndEmbed(img2embed) {
  16486. var tmpdiv,
  16487. nodes = domUtils.getElementsByTagName(me.document, !img2embed ? "embed" : "img");
  16488. for (var i = 0, node; node = nodes[i++];) {
  16489. if (node.className != "edui-faked-music") {
  16490. continue;
  16491. }
  16492. tmpdiv = me.document.createElement("div");
  16493. //先看float在看align,浮动有的是时候是在float上定义的
  16494. var align = domUtils.getComputedStyle(node, 'float');
  16495. align = align == 'none' ? (node.getAttribute('align') || '') : align;
  16496. tmpdiv.innerHTML = creatInsertStr(img2embed ? node.getAttribute("_url") : node.getAttribute("src"), node.width, node.height, align, img2embed);
  16497. node.parentNode.replaceChild(tmpdiv.firstChild, node);
  16498. }
  16499. }
  16500. me.addListener("beforegetcontent", function () {
  16501. switchImgAndEmbed(true);
  16502. });
  16503. me.addListener('aftersetcontent', function () {
  16504. switchImgAndEmbed(false);
  16505. });
  16506. me.addListener('aftergetcontent', function (cmdName) {
  16507. if (cmdName == 'aftergetcontent' && me.queryCommandState('source')) {
  16508. return;
  16509. }
  16510. switchImgAndEmbed(false);
  16511. });
  16512. me.commands["music"] = {
  16513. execCommand: function (cmd, musicObj) {
  16514. var me = this,
  16515. str = creatInsertStr(musicObj.url, musicObj.width || 400, musicObj.height || 95, "none", false, true);
  16516. me.execCommand("inserthtml", str);
  16517. },
  16518. queryCommandState: function () {
  16519. var me = this,
  16520. img = me.selection.getRange().getClosedNode(),
  16521. flag = img && (img.className == "edui-faked-music");
  16522. return flag ? 1 : 0;
  16523. }
  16524. };
  16525. };
  16526. var baidu = baidu || {};
  16527. baidu.editor = baidu.editor || {};
  16528. baidu.editor.ui = {};
  16529. (function () {
  16530. var browser = baidu.editor.browser,
  16531. domUtils = baidu.editor.dom.domUtils;
  16532. var magic = '$EDITORUI';
  16533. var root = window[magic] = {};
  16534. var uidMagic = 'ID' + magic;
  16535. var uidCount = 0;
  16536. var uiUtils = baidu.editor.ui.uiUtils = {
  16537. uid: function (obj) {
  16538. return (obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount);
  16539. },
  16540. hook: function (fn, callback) {
  16541. var dg;
  16542. if (fn && fn._callbacks) {
  16543. dg = fn;
  16544. } else {
  16545. dg = function () {
  16546. var q;
  16547. if (fn) {
  16548. q = fn.apply(this, arguments);
  16549. }
  16550. var callbacks = dg._callbacks;
  16551. var k = callbacks.length;
  16552. while (k--) {
  16553. var r = callbacks[k].apply(this, arguments);
  16554. if (q === undefined) {
  16555. q = r;
  16556. }
  16557. }
  16558. return q;
  16559. };
  16560. dg._callbacks = [];
  16561. }
  16562. dg._callbacks.push(callback);
  16563. return dg;
  16564. },
  16565. createElementByHtml: function (html) {
  16566. var el = document.createElement('div');
  16567. el.innerHTML = html;
  16568. el = el.firstChild;
  16569. el.parentNode.removeChild(el);
  16570. return el;
  16571. },
  16572. getViewportElement: function () {
  16573. return (browser.ie && browser.quirks) ?
  16574. document.body : document.documentElement;
  16575. },
  16576. getClientRect: function (element) {
  16577. var bcr;
  16578. //trace IE6下在控制编辑器显隐时可能会报错,catch一下
  16579. try {
  16580. bcr = element.getBoundingClientRect();
  16581. } catch (e) {
  16582. bcr = {left: 0, top: 0, height: 0, width: 0}
  16583. }
  16584. var rect = {
  16585. left: Math.round(bcr.left),
  16586. top: Math.round(bcr.top),
  16587. height: Math.round(bcr.bottom - bcr.top),
  16588. width: Math.round(bcr.right - bcr.left)
  16589. };
  16590. var doc;
  16591. while ((doc = element.ownerDocument) !== document &&
  16592. (element = domUtils.getWindow(doc).frameElement)) {
  16593. bcr = element.getBoundingClientRect();
  16594. rect.left += bcr.left;
  16595. rect.top += bcr.top;
  16596. }
  16597. rect.bottom = rect.top + rect.height;
  16598. rect.right = rect.left + rect.width;
  16599. return rect;
  16600. },
  16601. getViewportRect: function () {
  16602. var viewportEl = uiUtils.getViewportElement();
  16603. var width = (window.innerWidth || viewportEl.clientWidth) | 0;
  16604. var height = (window.innerHeight || viewportEl.clientHeight) | 0;
  16605. return {
  16606. left: 0,
  16607. top: 0,
  16608. height: height,
  16609. width: width,
  16610. bottom: height,
  16611. right: width
  16612. };
  16613. },
  16614. setViewportOffset: function (element, offset) {
  16615. var rect;
  16616. var fixedLayer = uiUtils.getFixedLayer();
  16617. if (element.parentNode === fixedLayer) {
  16618. element.style.left = offset.left + 'px';
  16619. element.style.top = offset.top + 'px';
  16620. } else {
  16621. domUtils.setViewportOffset(element, offset);
  16622. }
  16623. },
  16624. getEventOffset: function (evt) {
  16625. var el = evt.target || evt.srcElement;
  16626. var rect = uiUtils.getClientRect(el);
  16627. var offset = uiUtils.getViewportOffsetByEvent(evt);
  16628. return {
  16629. left: offset.left - rect.left,
  16630. top: offset.top - rect.top
  16631. };
  16632. },
  16633. getViewportOffsetByEvent: function (evt) {
  16634. var el = evt.target || evt.srcElement;
  16635. var frameEl = domUtils.getWindow(el).frameElement;
  16636. var offset = {
  16637. left: evt.clientX,
  16638. top: evt.clientY
  16639. };
  16640. if (frameEl && el.ownerDocument !== document) {
  16641. var rect = uiUtils.getClientRect(frameEl);
  16642. offset.left += rect.left;
  16643. offset.top += rect.top;
  16644. }
  16645. return offset;
  16646. },
  16647. setGlobal: function (id, obj) {
  16648. root[id] = obj;
  16649. return magic + '["' + id + '"]';
  16650. },
  16651. unsetGlobal: function (id) {
  16652. delete root[id];
  16653. },
  16654. copyAttributes: function (tgt, src) {
  16655. var attributes = src.attributes;
  16656. var k = attributes.length;
  16657. while (k--) {
  16658. var attrNode = attributes[k];
  16659. if (attrNode.nodeName != 'style' && attrNode.nodeName != 'class' && (!browser.ie || attrNode.specified)) {
  16660. tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue);
  16661. }
  16662. }
  16663. if (src.className) {
  16664. domUtils.addClass(tgt, src.className);
  16665. }
  16666. if (src.style.cssText) {
  16667. tgt.style.cssText += ';' + src.style.cssText;
  16668. }
  16669. },
  16670. removeStyle: function (el, styleName) {
  16671. if (el.style.removeProperty) {
  16672. el.style.removeProperty(styleName);
  16673. } else if (el.style.removeAttribute) {
  16674. el.style.removeAttribute(styleName);
  16675. } else throw '';
  16676. },
  16677. contains: function (elA, elB) {
  16678. return elA && elB && (elA === elB ? false : (
  16679. elA.contains ? elA.contains(elB) :
  16680. elA.compareDocumentPosition(elB) & 16
  16681. ));
  16682. },
  16683. startDrag: function (evt, callbacks, doc) {
  16684. var doc = doc || document;
  16685. var startX = evt.clientX;
  16686. var startY = evt.clientY;
  16687. function handleMouseMove(evt) {
  16688. var x = evt.clientX - startX;
  16689. var y = evt.clientY - startY;
  16690. callbacks.ondragmove(x, y, evt);
  16691. if (evt.stopPropagation) {
  16692. evt.stopPropagation();
  16693. } else {
  16694. evt.cancelBubble = true;
  16695. }
  16696. }
  16697. if (doc.addEventListener) {
  16698. function handleMouseUp(evt) {
  16699. doc.removeEventListener('mousemove', handleMouseMove, true);
  16700. doc.removeEventListener('mouseup', handleMouseUp, true);
  16701. window.removeEventListener('mouseup', handleMouseUp, true);
  16702. callbacks.ondragstop();
  16703. }
  16704. doc.addEventListener('mousemove', handleMouseMove, true);
  16705. doc.addEventListener('mouseup', handleMouseUp, true);
  16706. window.addEventListener('mouseup', handleMouseUp, true);
  16707. evt.preventDefault();
  16708. } else {
  16709. var elm = evt.srcElement;
  16710. elm.setCapture();
  16711. function releaseCaptrue() {
  16712. elm.releaseCapture();
  16713. elm.detachEvent('onmousemove', handleMouseMove);
  16714. elm.detachEvent('onmouseup', releaseCaptrue);
  16715. elm.detachEvent('onlosecaptrue', releaseCaptrue);
  16716. callbacks.ondragstop();
  16717. }
  16718. elm.attachEvent('onmousemove', handleMouseMove);
  16719. elm.attachEvent('onmouseup', releaseCaptrue);
  16720. elm.attachEvent('onlosecaptrue', releaseCaptrue);
  16721. evt.returnValue = false;
  16722. }
  16723. callbacks.ondragstart();
  16724. },
  16725. getFixedLayer: function () {
  16726. var layer = document.getElementById('edui_fixedlayer');
  16727. if (layer == null) {
  16728. layer = document.createElement('div');
  16729. layer.id = 'edui_fixedlayer';
  16730. document.body.appendChild(layer);
  16731. if (browser.ie && browser.version <= 8) {
  16732. layer.style.position = 'absolute';
  16733. bindFixedLayer();
  16734. setTimeout(updateFixedOffset);
  16735. } else {
  16736. layer.style.position = 'fixed';
  16737. }
  16738. layer.style.left = '0';
  16739. layer.style.top = '0';
  16740. layer.style.width = '0';
  16741. layer.style.height = '0';
  16742. }
  16743. return layer;
  16744. },
  16745. makeUnselectable: function (element) {
  16746. if (browser.opera || (browser.ie && browser.version < 9)) {
  16747. element.unselectable = 'on';
  16748. if (element.hasChildNodes()) {
  16749. for (var i = 0; i < element.childNodes.length; i++) {
  16750. if (element.childNodes[i].nodeType == 1) {
  16751. uiUtils.makeUnselectable(element.childNodes[i]);
  16752. }
  16753. }
  16754. }
  16755. } else {
  16756. if (element.style.MozUserSelect !== undefined) {
  16757. element.style.MozUserSelect = 'none';
  16758. } else if (element.style.WebkitUserSelect !== undefined) {
  16759. element.style.WebkitUserSelect = 'none';
  16760. } else if (element.style.KhtmlUserSelect !== undefined) {
  16761. element.style.KhtmlUserSelect = 'none';
  16762. }
  16763. }
  16764. }
  16765. };
  16766. function updateFixedOffset() {
  16767. var layer = document.getElementById('edui_fixedlayer');
  16768. uiUtils.setViewportOffset(layer, {
  16769. left: 0,
  16770. top: 0
  16771. });
  16772. // layer.style.display = 'none';
  16773. // layer.style.display = 'block';
  16774. //#trace: 1354
  16775. // setTimeout(updateFixedOffset);
  16776. }
  16777. function bindFixedLayer(adjOffset) {
  16778. domUtils.on(window, 'scroll', updateFixedOffset);
  16779. domUtils.on(window, 'resize', baidu.editor.utils.defer(updateFixedOffset, 0, true));
  16780. }
  16781. })();
  16782. (function () {
  16783. var utils = baidu.editor.utils,
  16784. uiUtils = baidu.editor.ui.uiUtils,
  16785. EventBase = baidu.editor.EventBase,
  16786. UIBase = baidu.editor.ui.UIBase = function () {
  16787. };
  16788. UIBase.prototype = {
  16789. className: '',
  16790. uiName: '',
  16791. initOptions: function (options) {
  16792. var me = this;
  16793. for (var k in options) {
  16794. me[k] = options[k];
  16795. }
  16796. this.id = this.id || 'edui' + uiUtils.uid();
  16797. },
  16798. initUIBase: function () {
  16799. this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this));
  16800. },
  16801. render: function (holder) {
  16802. var html = this.renderHtml();
  16803. var el = uiUtils.createElementByHtml(html);
  16804. //by xuheng 给每个node添加class
  16805. var list = domUtils.getElementsByTagName(el, "*");
  16806. var theme = "edui-" + (this.theme || this.editor.options.theme);
  16807. var layer = document.getElementById('edui_fixedlayer');
  16808. for (var i = 0, node; node = list[i++];) {
  16809. domUtils.addClass(node, theme);
  16810. }
  16811. domUtils.addClass(el, theme);
  16812. if (layer) {
  16813. layer.className = "";
  16814. domUtils.addClass(layer, theme);
  16815. }
  16816. var seatEl = this.getDom();
  16817. if (seatEl != null) {
  16818. seatEl.parentNode.replaceChild(el, seatEl);
  16819. uiUtils.copyAttributes(el, seatEl);
  16820. } else {
  16821. if (typeof holder == 'string') {
  16822. holder = document.getElementById(holder);
  16823. }
  16824. holder = holder || uiUtils.getFixedLayer();
  16825. domUtils.addClass(holder, theme);
  16826. holder.appendChild(el);
  16827. }
  16828. this.postRender();
  16829. },
  16830. getDom: function (name) {
  16831. if (!name) {
  16832. return document.getElementById(this.id);
  16833. } else {
  16834. return document.getElementById(this.id + '_' + name);
  16835. }
  16836. },
  16837. postRender: function () {
  16838. this.fireEvent('postrender');
  16839. },
  16840. getHtmlTpl: function () {
  16841. return '';
  16842. },
  16843. formatHtml: function (tpl) {
  16844. var prefix = 'edui-' + this.uiName;
  16845. return (tpl
  16846. .replace(/##/g, this.id)
  16847. .replace(/%%-/g, this.uiName ? prefix + '-' : '')
  16848. .replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className)
  16849. .replace(/\$\$/g, this._globalKey));
  16850. },
  16851. renderHtml: function () {
  16852. return this.formatHtml(this.getHtmlTpl());
  16853. },
  16854. dispose: function () {
  16855. var box = this.getDom();
  16856. if (box) baidu.editor.dom.domUtils.remove(box);
  16857. uiUtils.unsetGlobal(this.id);
  16858. }
  16859. };
  16860. utils.inherits(UIBase, EventBase);
  16861. })();
  16862. (function () {
  16863. var utils = baidu.editor.utils,
  16864. UIBase = baidu.editor.ui.UIBase,
  16865. Separator = baidu.editor.ui.Separator = function (options) {
  16866. this.initOptions(options);
  16867. this.initSeparator();
  16868. };
  16869. Separator.prototype = {
  16870. uiName: 'separator',
  16871. initSeparator: function () {
  16872. this.initUIBase();
  16873. },
  16874. getHtmlTpl: function () {
  16875. return '<div id="##" class="edui-box %%"></div>';
  16876. }
  16877. };
  16878. utils.inherits(Separator, UIBase);
  16879. })();
  16880. ///import core
  16881. ///import uicore
  16882. (function () {
  16883. var utils = baidu.editor.utils,
  16884. domUtils = baidu.editor.dom.domUtils,
  16885. UIBase = baidu.editor.ui.UIBase,
  16886. uiUtils = baidu.editor.ui.uiUtils;
  16887. var Mask = baidu.editor.ui.Mask = function (options) {
  16888. this.initOptions(options);
  16889. this.initUIBase();
  16890. };
  16891. Mask.prototype = {
  16892. getHtmlTpl: function () {
  16893. return '<div id="##" class="edui-mask %%" onmousedown="return $$._onMouseDown(event, this);"></div>';
  16894. },
  16895. postRender: function () {
  16896. var me = this;
  16897. domUtils.on(window, 'resize', function () {
  16898. setTimeout(function () {
  16899. if (!me.isHidden()) {
  16900. me._fill();
  16901. }
  16902. });
  16903. });
  16904. },
  16905. show: function (zIndex) {
  16906. this._fill();
  16907. this.getDom().style.display = '';
  16908. this.getDom().style.zIndex = zIndex;
  16909. },
  16910. hide: function () {
  16911. this.getDom().style.display = 'none';
  16912. this.getDom().style.zIndex = '';
  16913. },
  16914. isHidden: function () {
  16915. return this.getDom().style.display == 'none';
  16916. },
  16917. _onMouseDown: function () {
  16918. return false;
  16919. },
  16920. _fill: function () {
  16921. var el = this.getDom();
  16922. var vpRect = uiUtils.getViewportRect();
  16923. el.style.width = vpRect.width + 'px';
  16924. el.style.height = vpRect.height + 'px';
  16925. }
  16926. };
  16927. utils.inherits(Mask, UIBase);
  16928. })();
  16929. ///import core
  16930. ///import uicore
  16931. (function () {
  16932. var utils = baidu.editor.utils,
  16933. uiUtils = baidu.editor.ui.uiUtils,
  16934. domUtils = baidu.editor.dom.domUtils,
  16935. UIBase = baidu.editor.ui.UIBase,
  16936. Popup = baidu.editor.ui.Popup = function (options) {
  16937. this.initOptions(options);
  16938. this.initPopup();
  16939. };
  16940. var allPopups = [];
  16941. function closeAllPopup(evt, el) {
  16942. for (var i = 0; i < allPopups.length; i++) {
  16943. var pop = allPopups[i];
  16944. if (!pop.isHidden()) {
  16945. if (pop.queryAutoHide(el) !== false) {
  16946. if (evt && /scroll/ig.test(evt.type) && pop.className == "edui-wordpastepop") return;
  16947. pop.hide();
  16948. }
  16949. }
  16950. }
  16951. if (allPopups.length)
  16952. pop.editor.fireEvent("afterhidepop");
  16953. }
  16954. Popup.postHide = closeAllPopup;
  16955. var ANCHOR_CLASSES = ['edui-anchor-topleft', 'edui-anchor-topright',
  16956. 'edui-anchor-bottomleft', 'edui-anchor-bottomright'];
  16957. Popup.prototype = {
  16958. SHADOW_RADIUS: 5,
  16959. content: null,
  16960. _hidden: false,
  16961. autoRender: true,
  16962. canSideLeft: true,
  16963. canSideUp: true,
  16964. initPopup: function () {
  16965. this.initUIBase();
  16966. allPopups.push(this);
  16967. },
  16968. getHtmlTpl: function () {
  16969. return '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
  16970. ' <div id="##_body" class="edui-popup-body">' +
  16971. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="javascript:"></iframe>' +
  16972. ' <div class="edui-shadow"></div>' +
  16973. ' <div id="##_content" class="edui-popup-content">' +
  16974. this.getContentHtmlTpl() +
  16975. ' </div>' +
  16976. ' </div>' +
  16977. '</div>';
  16978. },
  16979. getContentHtmlTpl: function () {
  16980. if (this.content) {
  16981. if (typeof this.content == 'string') {
  16982. return this.content;
  16983. }
  16984. return this.content.renderHtml();
  16985. } else {
  16986. return ''
  16987. }
  16988. },
  16989. _UIBase_postRender: UIBase.prototype.postRender,
  16990. postRender: function () {
  16991. if (this.content instanceof UIBase) {
  16992. this.content.postRender();
  16993. }
  16994. //捕获鼠标滚轮
  16995. if (this.captureWheel && !this.captured) {
  16996. this.captured = true;
  16997. var winHeight = ( document.documentElement.clientHeight || document.body.clientHeight ) - 80,
  16998. _height = this.getDom().offsetHeight,
  16999. _top = domUtils.getXY(this.combox.getDom()).y,
  17000. content = this.getDom('content'),
  17001. me = this;
  17002. while (_top + _height > winHeight) {
  17003. _height -= 30;
  17004. content.style.height = _height + 'px';
  17005. }
  17006. //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
  17007. if (window.XMLHttpRequest) {
  17008. domUtils.on(content, ( 'onmousewheel' in document.body ) ? 'mousewheel' : 'DOMMouseScroll', function (e) {
  17009. if (e.preventDefault) {
  17010. e.preventDefault();
  17011. } else {
  17012. e.returnValue = false;
  17013. }
  17014. if (e.wheelDelta) {
  17015. content.scrollTop -= ( e.wheelDelta / 120 ) * 60;
  17016. } else {
  17017. content.scrollTop -= ( e.detail / -3 ) * 60;
  17018. }
  17019. });
  17020. } else {
  17021. //ie6
  17022. domUtils.on(this.getDom(), 'mousewheel', function (e) {
  17023. e.returnValue = false;
  17024. me.getDom('content').scrollTop -= ( e.wheelDelta / 120 ) * 60;
  17025. });
  17026. }
  17027. }
  17028. this.fireEvent('postRenderAfter');
  17029. this.hide(true);
  17030. this._UIBase_postRender();
  17031. },
  17032. _doAutoRender: function () {
  17033. if (!this.getDom() && this.autoRender) {
  17034. this.render();
  17035. }
  17036. },
  17037. mesureSize: function () {
  17038. var box = this.getDom('content');
  17039. return uiUtils.getClientRect(box);
  17040. },
  17041. fitSize: function () {
  17042. if (this.captureWheel && this.sized) {
  17043. return this.__size;
  17044. }
  17045. this.sized = true;
  17046. var popBodyEl = this.getDom('body');
  17047. popBodyEl.style.width = '';
  17048. popBodyEl.style.height = '';
  17049. var size = this.mesureSize();
  17050. if (this.captureWheel) {
  17051. popBodyEl.style.width = -(-20 - size.width) + 'px';
  17052. } else {
  17053. popBodyEl.style.width = size.width + 'px';
  17054. }
  17055. popBodyEl.style.height = size.height + 'px';
  17056. this.__size = size;
  17057. this.captureWheel && (this.getDom('content').style.overflow = 'auto');
  17058. return size;
  17059. },
  17060. showAnchor: function (element, hoz) {
  17061. this.showAnchorRect(uiUtils.getClientRect(element), hoz);
  17062. },
  17063. showAnchorRect: function (rect, hoz, adj) {
  17064. this._doAutoRender();
  17065. var vpRect = uiUtils.getViewportRect();
  17066. this._show();
  17067. var popSize = this.fitSize();
  17068. var sideLeft, sideUp, left, top;
  17069. if (hoz) {
  17070. sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width);
  17071. sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height);
  17072. left = (sideLeft ? rect.left - popSize.width : rect.right);
  17073. top = (sideUp ? rect.bottom - popSize.height : rect.top);
  17074. } else {
  17075. sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width);
  17076. sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height);
  17077. left = (sideLeft ? rect.right - popSize.width : rect.left);
  17078. top = (sideUp ? rect.top - popSize.height : rect.bottom);
  17079. }
  17080. var popEl = this.getDom();
  17081. uiUtils.setViewportOffset(popEl, {
  17082. left: left,
  17083. top: top
  17084. });
  17085. domUtils.removeClasses(popEl, ANCHOR_CLASSES);
  17086. popEl.className += ' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
  17087. if (this.editor) {
  17088. popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
  17089. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = popEl.style.zIndex - 1;
  17090. }
  17091. },
  17092. showAt: function (offset) {
  17093. var left = offset.left;
  17094. var top = offset.top;
  17095. var rect = {
  17096. left: left,
  17097. top: top,
  17098. right: left,
  17099. bottom: top,
  17100. height: 0,
  17101. width: 0
  17102. };
  17103. this.showAnchorRect(rect, false, true);
  17104. },
  17105. _show: function () {
  17106. if (this._hidden) {
  17107. var box = this.getDom();
  17108. box.style.display = '';
  17109. this._hidden = false;
  17110. // if (box.setActive) {
  17111. // box.setActive();
  17112. // }
  17113. this.fireEvent('show');
  17114. }
  17115. },
  17116. isHidden: function () {
  17117. return this._hidden;
  17118. },
  17119. show: function () {
  17120. this._doAutoRender();
  17121. this._show();
  17122. },
  17123. hide: function (notNofity) {
  17124. if (!this._hidden && this.getDom()) {
  17125. this.getDom().style.display = 'none';
  17126. this._hidden = true;
  17127. if (!notNofity) {
  17128. this.fireEvent('hide');
  17129. }
  17130. }
  17131. },
  17132. queryAutoHide: function (el) {
  17133. return !el || !uiUtils.contains(this.getDom(), el);
  17134. }
  17135. };
  17136. utils.inherits(Popup, UIBase);
  17137. domUtils.on(document, 'mousedown', function (evt) {
  17138. var el = evt.target || evt.srcElement;
  17139. closeAllPopup(evt, el);
  17140. });
  17141. domUtils.on(window, 'scroll', function (evt, el) {
  17142. closeAllPopup(evt, el);
  17143. });
  17144. })();
  17145. ///import core
  17146. ///import uicore
  17147. (function () {
  17148. var utils = baidu.editor.utils,
  17149. UIBase = baidu.editor.ui.UIBase,
  17150. ColorPicker = baidu.editor.ui.ColorPicker = function (options) {
  17151. this.initOptions(options);
  17152. this.noColorText = this.noColorText || this.editor.getLang("clearColor");
  17153. this.initUIBase();
  17154. };
  17155. ColorPicker.prototype = {
  17156. getHtmlTpl: function () {
  17157. return genColorPicker(this.noColorText, this.editor);
  17158. },
  17159. _onTableClick: function (evt) {
  17160. var tgt = evt.target || evt.srcElement;
  17161. var color = tgt.getAttribute('data-color');
  17162. if (color) {
  17163. this.fireEvent('pickcolor', color);
  17164. }
  17165. },
  17166. _onTableOver: function (evt) {
  17167. var tgt = evt.target || evt.srcElement;
  17168. var color = tgt.getAttribute('data-color');
  17169. if (color) {
  17170. this.getDom('preview').style.backgroundColor = color;
  17171. }
  17172. },
  17173. _onTableOut: function () {
  17174. this.getDom('preview').style.backgroundColor = '';
  17175. },
  17176. _onPickNoColor: function () {
  17177. this.fireEvent('picknocolor');
  17178. }
  17179. };
  17180. utils.inherits(ColorPicker, UIBase);
  17181. var COLORS = (
  17182. 'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' +
  17183. 'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' +
  17184. 'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' +
  17185. 'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' +
  17186. 'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' +
  17187. '7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' +
  17188. 'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,').split(',');
  17189. function genColorPicker(noColorText, editor) {
  17190. var html = '<div id="##" class="edui-colorpicker %%">' +
  17191. '<div class="edui-colorpicker-topbar edui-clearfix">' +
  17192. '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
  17193. '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">' + noColorText + '</div>' +
  17194. '</div>' +
  17195. '<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">' +
  17196. '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;padding-top: 2px"><td colspan="10">' + editor.getLang("themeColor") + '</td> </tr>' +
  17197. '<tr class="edui-colorpicker-tablefirstrow" >';
  17198. for (var i = 0; i < COLORS.length; i++) {
  17199. if (i && i % 10 === 0) {
  17200. html += '</tr>' + (i == 60 ? '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;"><td colspan="10">' + editor.getLang("standardColor") + '</td></tr>' : '') + '<tr' + (i == 60 ? ' class="edui-colorpicker-tablefirstrow"' : '') + '>';
  17201. }
  17202. 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"' +
  17203. ' data-color="#' + COLORS[i] + '"' +
  17204. ' style="background-color:#' + COLORS[i] + ';border:solid #ccc;' +
  17205. (i < 10 || i >= 60 ? 'border-width:1px;' :
  17206. i >= 10 && i < 20 ? 'border-width:1px 1px 0 1px;' :
  17207. 'border-width:0 1px 0 1px;') +
  17208. '"' +
  17209. '></a></td>' : '';
  17210. }
  17211. html += '</tr></table></div>';
  17212. return html;
  17213. }
  17214. })();
  17215. ///import core
  17216. ///import uicore
  17217. (function () {
  17218. var utils = baidu.editor.utils,
  17219. uiUtils = baidu.editor.ui.uiUtils,
  17220. UIBase = baidu.editor.ui.UIBase;
  17221. var TablePicker = baidu.editor.ui.TablePicker = function (options) {
  17222. this.initOptions(options);
  17223. this.initTablePicker();
  17224. };
  17225. TablePicker.prototype = {
  17226. defaultNumRows: 10,
  17227. defaultNumCols: 10,
  17228. maxNumRows: 20,
  17229. maxNumCols: 20,
  17230. numRows: 10,
  17231. numCols: 10,
  17232. lengthOfCellSide: 22,
  17233. initTablePicker: function () {
  17234. this.initUIBase();
  17235. },
  17236. getHtmlTpl: function () {
  17237. var me = this;
  17238. return '<div id="##" class="edui-tablepicker %%">' +
  17239. '<div class="edui-tablepicker-body">' +
  17240. '<div class="edui-infoarea">' +
  17241. '<span id="##_label" class="edui-label"></span>' +
  17242. '</div>' +
  17243. '<div class="edui-pickarea"' +
  17244. ' onmousemove="$$._onMouseMove(event, this);"' +
  17245. ' onmouseover="$$._onMouseOver(event, this);"' +
  17246. ' onmouseout="$$._onMouseOut(event, this);"' +
  17247. ' onclick="$$._onClick(event, this);"' +
  17248. '>' +
  17249. '<div id="##_overlay" class="edui-overlay"></div>' +
  17250. '</div>' +
  17251. '</div>' +
  17252. '</div>';
  17253. },
  17254. _UIBase_render: UIBase.prototype.render,
  17255. render: function (holder) {
  17256. this._UIBase_render(holder);
  17257. this.getDom('label').innerHTML = '0' + this.editor.getLang("t_row") + ' x 0' + this.editor.getLang("t_col");
  17258. },
  17259. _track: function (numCols, numRows) {
  17260. var style = this.getDom('overlay').style;
  17261. var sideLen = this.lengthOfCellSide;
  17262. style.width = numCols * sideLen + 'px';
  17263. style.height = numRows * sideLen + 'px';
  17264. var label = this.getDom('label');
  17265. label.innerHTML = numCols + this.editor.getLang("t_col") + ' x ' + numRows + this.editor.getLang("t_row");
  17266. this.numCols = numCols;
  17267. this.numRows = numRows;
  17268. },
  17269. _onMouseOver: function (evt, el) {
  17270. var rel = evt.relatedTarget || evt.fromElement;
  17271. if (!uiUtils.contains(el, rel) && el !== rel) {
  17272. this.getDom('label').innerHTML = '0' + this.editor.getLang("t_col") + ' x 0' + this.editor.getLang("t_row");
  17273. this.getDom('overlay').style.visibility = '';
  17274. }
  17275. },
  17276. _onMouseOut: function (evt, el) {
  17277. var rel = evt.relatedTarget || evt.toElement;
  17278. if (!uiUtils.contains(el, rel) && el !== rel) {
  17279. this.getDom('label').innerHTML = '0' + this.editor.getLang("t_col") + ' x 0' + this.editor.getLang("t_row");
  17280. this.getDom('overlay').style.visibility = 'hidden';
  17281. }
  17282. },
  17283. _onMouseMove: function (evt, el) {
  17284. var style = this.getDom('overlay').style;
  17285. var offset = uiUtils.getEventOffset(evt);
  17286. var sideLen = this.lengthOfCellSide;
  17287. var numCols = Math.ceil(offset.left / sideLen);
  17288. var numRows = Math.ceil(offset.top / sideLen);
  17289. this._track(numCols, numRows);
  17290. },
  17291. _onClick: function () {
  17292. this.fireEvent('picktable', this.numCols, this.numRows);
  17293. }
  17294. };
  17295. utils.inherits(TablePicker, UIBase);
  17296. })();
  17297. (function () {
  17298. var browser = baidu.editor.browser,
  17299. domUtils = baidu.editor.dom.domUtils,
  17300. uiUtils = baidu.editor.ui.uiUtils;
  17301. var TPL_STATEFUL = 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
  17302. ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
  17303. ( browser.ie ? (
  17304. ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
  17305. ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"' )
  17306. : (
  17307. ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
  17308. ' onmouseout="$$.Stateful_onMouseOut(event, this);"' ));
  17309. baidu.editor.ui.Stateful = {
  17310. alwalysHoverable: false,
  17311. target: null,//目标元素和this指向dom不一样
  17312. Stateful_init: function () {
  17313. this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
  17314. this.getHtmlTpl = this.Stateful_getHtmlTpl;
  17315. },
  17316. Stateful_getHtmlTpl: function () {
  17317. var tpl = this._Stateful_dGetHtmlTpl();
  17318. // 使用function避免$转义
  17319. return tpl.replace(/stateful/g, function () {
  17320. return TPL_STATEFUL;
  17321. });
  17322. },
  17323. Stateful_onMouseEnter: function (evt, el) {
  17324. this.target = el;
  17325. if (!this.isDisabled() || this.alwalysHoverable) {
  17326. this.addState('hover');
  17327. this.fireEvent('over');
  17328. }
  17329. },
  17330. Stateful_onMouseLeave: function (evt, el) {
  17331. if (!this.isDisabled() || this.alwalysHoverable) {
  17332. this.removeState('hover');
  17333. this.removeState('active');
  17334. this.fireEvent('out');
  17335. }
  17336. },
  17337. Stateful_onMouseOver: function (evt, el) {
  17338. var rel = evt.relatedTarget;
  17339. if (!uiUtils.contains(el, rel) && el !== rel) {
  17340. this.Stateful_onMouseEnter(evt, el);
  17341. }
  17342. },
  17343. Stateful_onMouseOut: function (evt, el) {
  17344. var rel = evt.relatedTarget;
  17345. if (!uiUtils.contains(el, rel) && el !== rel) {
  17346. this.Stateful_onMouseLeave(evt, el);
  17347. }
  17348. },
  17349. Stateful_onMouseDown: function (evt, el) {
  17350. if (!this.isDisabled()) {
  17351. this.addState('active');
  17352. }
  17353. },
  17354. Stateful_onMouseUp: function (evt, el) {
  17355. if (!this.isDisabled()) {
  17356. this.removeState('active');
  17357. }
  17358. },
  17359. Stateful_postRender: function () {
  17360. if (this.disabled && !this.hasState('disabled')) {
  17361. this.addState('disabled');
  17362. }
  17363. },
  17364. hasState: function (state) {
  17365. return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state);
  17366. },
  17367. addState: function (state) {
  17368. if (!this.hasState(state)) {
  17369. this.getStateDom().className += ' edui-state-' + state;
  17370. }
  17371. },
  17372. removeState: function (state) {
  17373. if (this.hasState(state)) {
  17374. domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state]);
  17375. }
  17376. },
  17377. getStateDom: function () {
  17378. return this.getDom('state');
  17379. },
  17380. isChecked: function () {
  17381. return this.hasState('checked');
  17382. },
  17383. setChecked: function (checked) {
  17384. if (!this.isDisabled() && checked) {
  17385. this.addState('checked');
  17386. } else {
  17387. this.removeState('checked');
  17388. }
  17389. },
  17390. isDisabled: function () {
  17391. return this.hasState('disabled');
  17392. },
  17393. setDisabled: function (disabled) {
  17394. if (disabled) {
  17395. this.removeState('hover');
  17396. this.removeState('checked');
  17397. this.removeState('active');
  17398. this.addState('disabled');
  17399. } else {
  17400. this.removeState('disabled');
  17401. }
  17402. }
  17403. };
  17404. })();
  17405. ///import core
  17406. ///import uicore
  17407. ///import ui/stateful.js
  17408. (function () {
  17409. var utils = baidu.editor.utils,
  17410. UIBase = baidu.editor.ui.UIBase,
  17411. Stateful = baidu.editor.ui.Stateful,
  17412. Button = baidu.editor.ui.Button = function (options) {
  17413. this.initOptions(options);
  17414. this.initButton();
  17415. };
  17416. Button.prototype = {
  17417. uiName: 'button',
  17418. label: '',
  17419. title: '',
  17420. showIcon: true,
  17421. showText: true,
  17422. initButton: function () {
  17423. this.initUIBase();
  17424. this.Stateful_init();
  17425. },
  17426. getHtmlTpl: function () {
  17427. return '<div id="##" class="edui-box %%">' +
  17428. '<div id="##_state" stateful>' +
  17429. '<div class="%%-wrap"><div id="##_body" unselectable="on" ' + (this.title ? 'title="' + this.title + '"' : '') +
  17430. ' class="%%-body" onmousedown="return false;" onclick="return $$._onClick();">' +
  17431. (this.showIcon ? '<div class="edui-box edui-icon"></div>' : '') +
  17432. (this.showText ? '<div class="edui-box edui-label">' + this.label + '</div>' : '') +
  17433. '</div>' +
  17434. '</div>' +
  17435. '</div></div>';
  17436. },
  17437. postRender: function () {
  17438. this.Stateful_postRender();
  17439. this.setDisabled(this.disabled)
  17440. },
  17441. _onClick: function () {
  17442. if (!this.isDisabled()) {
  17443. this.fireEvent('click');
  17444. }
  17445. }
  17446. };
  17447. utils.inherits(Button, UIBase);
  17448. utils.extend(Button.prototype, Stateful);
  17449. })();
  17450. ///import core
  17451. ///import uicore
  17452. ///import ui/stateful.js
  17453. (function () {
  17454. var utils = baidu.editor.utils,
  17455. uiUtils = baidu.editor.ui.uiUtils,
  17456. domUtils = baidu.editor.dom.domUtils,
  17457. UIBase = baidu.editor.ui.UIBase,
  17458. Stateful = baidu.editor.ui.Stateful,
  17459. SplitButton = baidu.editor.ui.SplitButton = function (options) {
  17460. this.initOptions(options);
  17461. this.initSplitButton();
  17462. };
  17463. SplitButton.prototype = {
  17464. popup: null,
  17465. uiName: 'splitbutton',
  17466. title: '',
  17467. initSplitButton: function () {
  17468. this.initUIBase();
  17469. this.Stateful_init();
  17470. var me = this;
  17471. if (this.popup != null) {
  17472. var popup = this.popup;
  17473. this.popup = null;
  17474. this.setPopup(popup);
  17475. }
  17476. },
  17477. _UIBase_postRender: UIBase.prototype.postRender,
  17478. postRender: function () {
  17479. this.Stateful_postRender();
  17480. this._UIBase_postRender();
  17481. },
  17482. setPopup: function (popup) {
  17483. if (this.popup === popup) return;
  17484. if (this.popup != null) {
  17485. this.popup.dispose();
  17486. }
  17487. popup.addListener('show', utils.bind(this._onPopupShow, this));
  17488. popup.addListener('hide', utils.bind(this._onPopupHide, this));
  17489. popup.addListener('postrender', utils.bind(function () {
  17490. popup.getDom('body').appendChild(
  17491. uiUtils.createElementByHtml('<div id="' +
  17492. this.popup.id + '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
  17493. (uiUtils.getClientRect(this.getDom()).width + 20) + 'px"></div>')
  17494. );
  17495. popup.getDom().className += ' ' + this.className;
  17496. }, this));
  17497. this.popup = popup;
  17498. },
  17499. _onPopupShow: function () {
  17500. this.addState('opened');
  17501. },
  17502. _onPopupHide: function () {
  17503. this.removeState('opened');
  17504. },
  17505. getHtmlTpl: function () {
  17506. return '<div id="##" class="edui-box %%">' +
  17507. '<div ' + (this.title ? 'title="' + this.title + '"' : '') + ' id="##_state" stateful><div class="%%-body">' +
  17508. '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
  17509. '<div class="edui-box edui-icon"></div>' +
  17510. '</div>' +
  17511. '<div class="edui-box edui-splitborder"></div>' +
  17512. '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
  17513. '</div></div></div>';
  17514. },
  17515. showPopup: function () {
  17516. // 当popup往上弹出的时候,做特殊处理
  17517. var rect = uiUtils.getClientRect(this.getDom());
  17518. rect.top -= this.popup.SHADOW_RADIUS;
  17519. rect.height += this.popup.SHADOW_RADIUS;
  17520. this.popup.showAnchorRect(rect);
  17521. },
  17522. _onArrowClick: function (event, el) {
  17523. if (!this.isDisabled()) {
  17524. this.showPopup();
  17525. }
  17526. },
  17527. _onButtonClick: function () {
  17528. if (!this.isDisabled()) {
  17529. this.fireEvent('buttonclick');
  17530. }
  17531. }
  17532. };
  17533. utils.inherits(SplitButton, UIBase);
  17534. utils.extend(SplitButton.prototype, Stateful, true);
  17535. })();
  17536. ///import core
  17537. ///import uicore
  17538. ///import ui/colorpicker.js
  17539. ///import ui/popup.js
  17540. ///import ui/splitbutton.js
  17541. (function () {
  17542. var utils = baidu.editor.utils,
  17543. uiUtils = baidu.editor.ui.uiUtils,
  17544. ColorPicker = baidu.editor.ui.ColorPicker,
  17545. Popup = baidu.editor.ui.Popup,
  17546. SplitButton = baidu.editor.ui.SplitButton,
  17547. ColorButton = baidu.editor.ui.ColorButton = function (options) {
  17548. this.initOptions(options);
  17549. this.initColorButton();
  17550. };
  17551. ColorButton.prototype = {
  17552. initColorButton: function () {
  17553. var me = this;
  17554. this.popup = new Popup({
  17555. content: new ColorPicker({
  17556. noColorText: me.editor.getLang("clearColor"),
  17557. editor: me.editor,
  17558. onpickcolor: function (t, color) {
  17559. me._onPickColor(color);
  17560. },
  17561. onpicknocolor: function (t, color) {
  17562. me._onPickNoColor(color);
  17563. }
  17564. }),
  17565. editor: me.editor
  17566. });
  17567. this.initSplitButton();
  17568. },
  17569. _SplitButton_postRender: SplitButton.prototype.postRender,
  17570. postRender: function () {
  17571. this._SplitButton_postRender();
  17572. this.getDom('button_body').appendChild(
  17573. uiUtils.createElementByHtml('<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>')
  17574. );
  17575. this.getDom().className += ' edui-colorbutton';
  17576. },
  17577. setColor: function (color) {
  17578. this.getDom('colorlump').style.backgroundColor = color;
  17579. this.color = color;
  17580. },
  17581. _onPickColor: function (color) {
  17582. if (this.fireEvent('pickcolor', color) !== false) {
  17583. this.setColor(color);
  17584. this.popup.hide();
  17585. }
  17586. },
  17587. _onPickNoColor: function (color) {
  17588. if (this.fireEvent('picknocolor') !== false) {
  17589. this.popup.hide();
  17590. }
  17591. }
  17592. };
  17593. utils.inherits(ColorButton, SplitButton);
  17594. })();
  17595. ///import core
  17596. ///import uicore
  17597. ///import ui/popup.js
  17598. ///import ui/tablepicker.js
  17599. ///import ui/splitbutton.js
  17600. (function () {
  17601. var utils = baidu.editor.utils,
  17602. Popup = baidu.editor.ui.Popup,
  17603. TablePicker = baidu.editor.ui.TablePicker,
  17604. SplitButton = baidu.editor.ui.SplitButton,
  17605. TableButton = baidu.editor.ui.TableButton = function (options) {
  17606. this.initOptions(options);
  17607. this.initTableButton();
  17608. };
  17609. TableButton.prototype = {
  17610. initTableButton: function () {
  17611. var me = this;
  17612. this.popup = new Popup({
  17613. content: new TablePicker({
  17614. editor: me.editor,
  17615. onpicktable: function (t, numCols, numRows) {
  17616. me._onPickTable(numCols, numRows);
  17617. }
  17618. }),
  17619. 'editor': me.editor
  17620. });
  17621. this.initSplitButton();
  17622. },
  17623. _onPickTable: function (numCols, numRows) {
  17624. if (this.fireEvent('picktable', numCols, numRows) !== false) {
  17625. this.popup.hide();
  17626. }
  17627. }
  17628. };
  17629. utils.inherits(TableButton, SplitButton);
  17630. })();
  17631. ///import core
  17632. ///import uicore
  17633. (function () {
  17634. var utils = baidu.editor.utils,
  17635. UIBase = baidu.editor.ui.UIBase;
  17636. var AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker = function (options) {
  17637. this.initOptions(options);
  17638. this.initAutoTypeSetPicker();
  17639. };
  17640. AutoTypeSetPicker.prototype = {
  17641. initAutoTypeSetPicker: function () {
  17642. this.initUIBase();
  17643. },
  17644. getHtmlTpl: function () {
  17645. var me = this.editor,
  17646. opt = me.options.autotypeset,
  17647. lang = me.getLang("autoTypeSet");
  17648. var textAlignInputName = 'textAlignValue' + me.uid,
  17649. imageBlockInputName = 'imageBlockLineValue' + me.uid;
  17650. return '<div id="##" class="edui-autotypesetpicker %%">' +
  17651. '<div class="edui-autotypesetpicker-body">' +
  17652. '<table >' +
  17653. '<tr><td nowrap 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>' +
  17654. '<tr><td nowrap 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>' +
  17655. '<tr><td nowrap colspan="2"><input type="checkbox" name="textAlign" ' + (opt["textAlign"] ? "checked" : "" ) + '>' + lang.alignment + '</td><td colspan="2" id="' + textAlignInputName + '"><input type="radio" name="' + textAlignInputName + '" value="left" ' + ((opt["textAlign"] && opt["textAlign"] == "left") ? "checked" : "") + '>' + me.getLang("justifyleft") + '<input type="radio" name="' + textAlignInputName + '" value="center" ' + ((opt["textAlign"] && opt["textAlign"] == "center") ? "checked" : "") + '>' + me.getLang("justifycenter") + '<input type="radio" name="' + textAlignInputName + '" value="right" ' + ((opt["textAlign"] && opt["textAlign"] == "right") ? "checked" : "") + '>' + me.getLang("justifyright") + ' </tr>' +
  17656. '<tr><td nowrap colspan="2"><input type="checkbox" name="imageBlockLine" ' + (opt["imageBlockLine"] ? "checked" : "" ) + '>' + lang.imageFloat + '</td>' +
  17657. '<td nowrap colspan="2" id="' + imageBlockInputName + '">' +
  17658. '<input type="radio" name="' + imageBlockInputName + '" value="none" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "none") ? "checked" : "") + '>' + me.getLang("default") +
  17659. '<input type="radio" name="' + imageBlockInputName + '" value="left" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "left") ? "checked" : "") + '>' + me.getLang("justifyleft") +
  17660. '<input type="radio" name="' + imageBlockInputName + '" value="center" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "center") ? "checked" : "") + '>' + me.getLang("justifycenter") +
  17661. '<input type="radio" name="' + imageBlockInputName + '" value="right" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "right") ? "checked" : "") + '>' + me.getLang("justifyright") + '</tr>' +
  17662. '<tr><td nowrap 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>' +
  17663. '<tr><td nowrap colspan="4"><input type="checkbox" name="removeEmptyNode" ' + (opt["removeEmptyNode"] ? "checked" : "" ) + '>' + lang.removeHtml + '</td></tr>' +
  17664. '<tr><td nowrap colspan="4"><input type="checkbox" name="pasteFilter" ' + (opt["pasteFilter"] ? "checked" : "" ) + '>' + lang.pasteFilter + '</td></tr>' +
  17665. '<tr><td nowrap colspan="4" align="right"><button >' + lang.run + '</button></td></tr>' +
  17666. '</table>' +
  17667. '</div>' +
  17668. '</div>';
  17669. },
  17670. _UIBase_render: UIBase.prototype.render
  17671. };
  17672. utils.inherits(AutoTypeSetPicker, UIBase);
  17673. })();
  17674. ///import core
  17675. ///import uicore
  17676. ///import ui/popup.js
  17677. ///import ui/autotypesetpicker.js
  17678. ///import ui/splitbutton.js
  17679. (function () {
  17680. var utils = baidu.editor.utils,
  17681. Popup = baidu.editor.ui.Popup,
  17682. AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
  17683. SplitButton = baidu.editor.ui.SplitButton,
  17684. AutoTypeSetButton = baidu.editor.ui.AutoTypeSetButton = function (options) {
  17685. this.initOptions(options);
  17686. this.initAutoTypeSetButton();
  17687. };
  17688. function getPara(me) {
  17689. var opt = me.editor.options.autotypeset,
  17690. cont = me.getDom(),
  17691. editorId = me.editor.uid,
  17692. inputType = null,
  17693. attrName = null,
  17694. ipts = domUtils.getElementsByTagName(cont, "input");
  17695. for (var i = ipts.length - 1, ipt; ipt = ipts[i--];) {
  17696. inputType = ipt.getAttribute("type");
  17697. if (inputType == "checkbox") {
  17698. attrName = ipt.getAttribute("name");
  17699. opt[attrName] && delete opt[attrName];
  17700. if (ipt.checked) {
  17701. var attrValue = document.getElementById(attrName + "Value" + editorId);
  17702. if (attrValue) {
  17703. if (/input/ig.test(attrValue.tagName)) {
  17704. opt[attrName] = attrValue.value;
  17705. } else {
  17706. var iptChilds = attrValue.getElementsByTagName("input");
  17707. for (var j = iptChilds.length - 1, iptchild; iptchild = iptChilds[j--];) {
  17708. if (iptchild.checked) {
  17709. opt[attrName] = iptchild.value;
  17710. break;
  17711. }
  17712. }
  17713. }
  17714. } else {
  17715. opt[attrName] = true;
  17716. }
  17717. }
  17718. }
  17719. }
  17720. var selects = domUtils.getElementsByTagName(cont, "select");
  17721. for (var i = 0, si; si = selects[i++];) {
  17722. var attr = si.getAttribute('name');
  17723. opt[attr] = opt[attr] ? si.value : '';
  17724. }
  17725. me.editor.options.autotypeset = opt;
  17726. }
  17727. AutoTypeSetButton.prototype = {
  17728. initAutoTypeSetButton: function () {
  17729. var me = this;
  17730. this.popup = new Popup({
  17731. //传入配置参数
  17732. content: new AutoTypeSetPicker({editor: me.editor}),
  17733. 'editor': me.editor,
  17734. hide: function () {
  17735. if (!this._hidden && this.getDom()) {
  17736. getPara(this);
  17737. this.getDom().style.display = 'none';
  17738. this._hidden = true;
  17739. this.fireEvent('hide');
  17740. }
  17741. }
  17742. });
  17743. var flag = 0;
  17744. this.popup.addListener('postRenderAfter', function () {
  17745. var popupUI = this;
  17746. if (flag)return;
  17747. var cont = this.getDom(),
  17748. btn = cont.getElementsByTagName('button')[0];
  17749. btn.onclick = function () {
  17750. getPara(popupUI);
  17751. me.editor.execCommand('autotypeset');
  17752. popupUI.hide()
  17753. };
  17754. flag = 1;
  17755. });
  17756. this.initSplitButton();
  17757. }
  17758. };
  17759. utils.inherits(AutoTypeSetButton, SplitButton);
  17760. })();
  17761. ///import core
  17762. ///import uicore
  17763. (function () {
  17764. var utils = baidu.editor.utils,
  17765. Popup = baidu.editor.ui.Popup,
  17766. Stateful = baidu.editor.ui.Stateful,
  17767. UIBase = baidu.editor.ui.UIBase;
  17768. /**
  17769. * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
  17770. * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
  17771. * @update 2013/4/2 hancong03@baidu.com
  17772. */
  17773. var CellAlignPicker = baidu.editor.ui.CellAlignPicker = function (options) {
  17774. this.initOptions(options);
  17775. this.initSelected();
  17776. this.initCellAlignPicker();
  17777. };
  17778. CellAlignPicker.prototype = {
  17779. //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
  17780. initSelected: function () {
  17781. var status = {
  17782. valign: {
  17783. top: 0,
  17784. middle: 1,
  17785. bottom: 2
  17786. },
  17787. align: {
  17788. left: 0,
  17789. center: 1,
  17790. right: 2
  17791. },
  17792. count: 3
  17793. },
  17794. result = -1;
  17795. if (this.selected) {
  17796. this.selectedIndex = status.valign[ this.selected.valign ] * status.count + status.align[ this.selected.align ];
  17797. }
  17798. },
  17799. initCellAlignPicker: function () {
  17800. this.initUIBase();
  17801. this.Stateful_init();
  17802. },
  17803. getHtmlTpl: function () {
  17804. var alignType = [ 'left', 'center', 'right' ],
  17805. COUNT = 9,
  17806. tempClassName = null,
  17807. tempIndex = -1,
  17808. tmpl = [];
  17809. for (var i = 0; i < COUNT; i++) {
  17810. tempClassName = this.selectedIndex === i ? ' class="edui-cellalign-selected" ' : '';
  17811. tempIndex = i % 3;
  17812. tempIndex === 0 && tmpl.push('<tr>');
  17813. tmpl.push('<td index="' + i + '" ' + tempClassName + ' stateful><div class="edui-icon edui-' + alignType[ tempIndex ] + '"></div></td>');
  17814. tempIndex === 2 && tmpl.push('</tr>');
  17815. }
  17816. return '<div id="##" class="edui-cellalignpicker %%">' +
  17817. '<div class="edui-cellalignpicker-body">' +
  17818. '<table onclick="$$._onClick(event);">' +
  17819. tmpl.join('') +
  17820. '</table>' +
  17821. '</div>' +
  17822. '</div>';
  17823. },
  17824. getStateDom: function () {
  17825. return this.target;
  17826. },
  17827. _onClick: function (evt) {
  17828. var target = evt.target || evt.srcElement;
  17829. if (/icon/.test(target.className)) {
  17830. this.items[target.parentNode.getAttribute("index")].onclick();
  17831. Popup.postHide(evt);
  17832. }
  17833. },
  17834. _UIBase_render: UIBase.prototype.render
  17835. };
  17836. utils.inherits(CellAlignPicker, UIBase);
  17837. utils.extend(CellAlignPicker.prototype, Stateful, true);
  17838. })();
  17839. ///import core
  17840. ///import uicore
  17841. (function () {
  17842. var utils = baidu.editor.utils,
  17843. Stateful = baidu.editor.ui.Stateful,
  17844. uiUtils = baidu.editor.ui.uiUtils,
  17845. UIBase = baidu.editor.ui.UIBase;
  17846. var PastePicker = baidu.editor.ui.PastePicker = function (options) {
  17847. this.initOptions(options);
  17848. this.initPastePicker();
  17849. };
  17850. PastePicker.prototype = {
  17851. initPastePicker: function () {
  17852. this.initUIBase();
  17853. this.Stateful_init();
  17854. },
  17855. getHtmlTpl: function () {
  17856. return '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
  17857. '<div class="edui-pastecontainer">' +
  17858. '<div class="edui-title">' + this.editor.getLang("pasteOpt") + '</div>' +
  17859. '<div class="edui-button">' +
  17860. '<div title="' + this.editor.getLang("pasteSourceFormat") + '" onclick="$$.format(false)" stateful>' +
  17861. '<div class="edui-richtxticon"></div></div>' +
  17862. '<div title="' + this.editor.getLang("tagFormat") + '" onclick="$$.format(2)" stateful>' +
  17863. '<div class="edui-tagicon"></div></div>' +
  17864. '<div title="' + this.editor.getLang("pasteTextFormat") + '" onclick="$$.format(true)" stateful>' +
  17865. '<div class="edui-plaintxticon"></div></div>' +
  17866. '</div>' +
  17867. '</div>' +
  17868. '</div>'
  17869. },
  17870. getStateDom: function () {
  17871. return this.target;
  17872. },
  17873. format: function (param) {
  17874. this.editor.ui._isTransfer = true;
  17875. this.editor.fireEvent('pasteTransfer', param);
  17876. },
  17877. _onClick: function (cur) {
  17878. var node = domUtils.getNextDomNode(cur),
  17879. screenHt = uiUtils.getViewportRect().height,
  17880. subPop = uiUtils.getClientRect(node);
  17881. if ((subPop.top + subPop.height) > screenHt)
  17882. node.style.top = (-subPop.height - cur.offsetHeight) + "px";
  17883. else
  17884. node.style.top = "";
  17885. if (/hidden/ig.test(domUtils.getComputedStyle(node, "visibility"))) {
  17886. node.style.visibility = "visible";
  17887. domUtils.addClass(cur, "edui-state-opened");
  17888. } else {
  17889. node.style.visibility = "hidden";
  17890. domUtils.removeClasses(cur, "edui-state-opened")
  17891. }
  17892. },
  17893. _UIBase_render: UIBase.prototype.render
  17894. };
  17895. utils.inherits(PastePicker, UIBase);
  17896. utils.extend(PastePicker.prototype, Stateful, true);
  17897. })();
  17898. (function () {
  17899. var utils = baidu.editor.utils,
  17900. uiUtils = baidu.editor.ui.uiUtils,
  17901. UIBase = baidu.editor.ui.UIBase,
  17902. Toolbar = baidu.editor.ui.Toolbar = function (options) {
  17903. this.initOptions(options);
  17904. this.initToolbar();
  17905. };
  17906. Toolbar.prototype = {
  17907. items: null,
  17908. initToolbar: function () {
  17909. this.items = this.items || [];
  17910. this.initUIBase();
  17911. },
  17912. add: function (item) {
  17913. this.items.push(item);
  17914. },
  17915. getHtmlTpl: function () {
  17916. var buff = [];
  17917. for (var i = 0; i < this.items.length; i++) {
  17918. buff[i] = this.items[i].renderHtml();
  17919. }
  17920. return '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
  17921. buff.join('') +
  17922. '</div>'
  17923. },
  17924. postRender: function () {
  17925. var box = this.getDom();
  17926. for (var i = 0; i < this.items.length; i++) {
  17927. this.items[i].postRender();
  17928. }
  17929. uiUtils.makeUnselectable(box);
  17930. },
  17931. _onMouseDown: function () {
  17932. return false;
  17933. }
  17934. };
  17935. utils.inherits(Toolbar, UIBase);
  17936. })();
  17937. ///import core
  17938. ///import uicore
  17939. ///import ui\popup.js
  17940. ///import ui\stateful.js
  17941. (function () {
  17942. var utils = baidu.editor.utils,
  17943. domUtils = baidu.editor.dom.domUtils,
  17944. uiUtils = baidu.editor.ui.uiUtils,
  17945. UIBase = baidu.editor.ui.UIBase,
  17946. Popup = baidu.editor.ui.Popup,
  17947. Stateful = baidu.editor.ui.Stateful,
  17948. CellAlignPicker = baidu.editor.ui.CellAlignPicker,
  17949. Menu = baidu.editor.ui.Menu = function (options) {
  17950. this.initOptions(options);
  17951. this.initMenu();
  17952. };
  17953. var menuSeparator = {
  17954. renderHtml: function () {
  17955. return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>';
  17956. },
  17957. postRender: function () {
  17958. },
  17959. queryAutoHide: function () {
  17960. return true;
  17961. }
  17962. };
  17963. Menu.prototype = {
  17964. items: null,
  17965. uiName: 'menu',
  17966. initMenu: function () {
  17967. this.items = this.items || [];
  17968. this.initPopup();
  17969. this.initItems();
  17970. },
  17971. initItems: function () {
  17972. for (var i = 0; i < this.items.length; i++) {
  17973. var item = this.items[i];
  17974. if (item == '-') {
  17975. this.items[i] = this.getSeparator();
  17976. } else if (!(item instanceof MenuItem)) {
  17977. item.editor = this.editor;
  17978. item.theme = this.editor.options.theme;
  17979. this.items[i] = this.createItem(item);
  17980. }
  17981. }
  17982. },
  17983. getSeparator: function () {
  17984. return menuSeparator;
  17985. },
  17986. createItem: function (item) {
  17987. //新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  17988. item.menu = this;
  17989. return new MenuItem(item);
  17990. },
  17991. _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
  17992. getContentHtmlTpl: function () {
  17993. if (this.items.length == 0) {
  17994. return this._Popup_getContentHtmlTpl();
  17995. }
  17996. var buff = [];
  17997. for (var i = 0; i < this.items.length; i++) {
  17998. var item = this.items[i];
  17999. buff[i] = item.renderHtml();
  18000. }
  18001. return ('<div class="%%-body">' + buff.join('') + '</div>');
  18002. },
  18003. _Popup_postRender: Popup.prototype.postRender,
  18004. postRender: function () {
  18005. var me = this;
  18006. for (var i = 0; i < this.items.length; i++) {
  18007. var item = this.items[i];
  18008. item.ownerMenu = this;
  18009. item.postRender();
  18010. }
  18011. domUtils.on(this.getDom(), 'mouseover', function (evt) {
  18012. evt = evt || event;
  18013. var rel = evt.relatedTarget || evt.fromElement;
  18014. var el = me.getDom();
  18015. if (!uiUtils.contains(el, rel) && el !== rel) {
  18016. me.fireEvent('over');
  18017. }
  18018. });
  18019. this._Popup_postRender();
  18020. },
  18021. queryAutoHide: function (el) {
  18022. if (el) {
  18023. if (uiUtils.contains(this.getDom(), el)) {
  18024. return false;
  18025. }
  18026. for (var i = 0; i < this.items.length; i++) {
  18027. var item = this.items[i];
  18028. if (item.queryAutoHide(el) === false) {
  18029. return false;
  18030. }
  18031. }
  18032. }
  18033. },
  18034. clearItems: function () {
  18035. for (var i = 0; i < this.items.length; i++) {
  18036. var item = this.items[i];
  18037. clearTimeout(item._showingTimer);
  18038. clearTimeout(item._closingTimer);
  18039. if (item.subMenu) {
  18040. item.subMenu.destroy();
  18041. }
  18042. }
  18043. this.items = [];
  18044. },
  18045. destroy: function () {
  18046. if (this.getDom()) {
  18047. domUtils.remove(this.getDom());
  18048. }
  18049. this.clearItems();
  18050. },
  18051. dispose: function () {
  18052. this.destroy();
  18053. }
  18054. };
  18055. utils.inherits(Menu, Popup);
  18056. /**
  18057. * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  18058. * @type {Function}
  18059. */
  18060. var MenuItem = baidu.editor.ui.MenuItem = function (options) {
  18061. this.initOptions(options);
  18062. this.initUIBase();
  18063. this.Stateful_init();
  18064. if (this.subMenu && !(this.subMenu instanceof Menu)) {
  18065. if (options.className && options.className.indexOf("aligntd") != -1) {
  18066. var me = this;
  18067. //获取单元格对齐初始状态
  18068. this.subMenu.selected = this.editor.queryCommandValue('cellalignment');
  18069. this.subMenu = new Popup({
  18070. content: new CellAlignPicker(this.subMenu),
  18071. parentMenu: me,
  18072. editor: me.editor,
  18073. destroy: function () {
  18074. if (this.getDom()) {
  18075. domUtils.remove(this.getDom());
  18076. }
  18077. }
  18078. });
  18079. this.subMenu.addListener("postRenderAfter", function () {
  18080. domUtils.on(this.getDom(), "mouseover", function () {
  18081. me.addState('opened');
  18082. });
  18083. });
  18084. } else {
  18085. this.subMenu = new Menu(this.subMenu);
  18086. }
  18087. }
  18088. };
  18089. MenuItem.prototype = {
  18090. label: '',
  18091. subMenu: null,
  18092. ownerMenu: null,
  18093. uiName: 'menuitem',
  18094. alwalysHoverable: true,
  18095. getHtmlTpl: function () {
  18096. return '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
  18097. '<div class="%%-body">' +
  18098. this.renderLabelHtml() +
  18099. '</div>' +
  18100. '</div>';
  18101. },
  18102. postRender: function () {
  18103. var me = this;
  18104. this.addListener('over', function () {
  18105. me.ownerMenu.fireEvent('submenuover', me);
  18106. if (me.subMenu) {
  18107. me.delayShowSubMenu();
  18108. }
  18109. });
  18110. if (this.subMenu) {
  18111. this.getDom().className += ' edui-hassubmenu';
  18112. this.subMenu.render();
  18113. this.addListener('out', function () {
  18114. me.delayHideSubMenu();
  18115. });
  18116. this.subMenu.addListener('over', function () {
  18117. clearTimeout(me._closingTimer);
  18118. me._closingTimer = null;
  18119. me.addState('opened');
  18120. });
  18121. this.ownerMenu.addListener('hide', function () {
  18122. me.hideSubMenu();
  18123. });
  18124. this.ownerMenu.addListener('submenuover', function (t, subMenu) {
  18125. if (subMenu !== me) {
  18126. me.delayHideSubMenu();
  18127. }
  18128. });
  18129. this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
  18130. this.subMenu.queryAutoHide = function (el) {
  18131. if (el && uiUtils.contains(me.getDom(), el)) {
  18132. return false;
  18133. }
  18134. return this._bakQueryAutoHide(el);
  18135. };
  18136. }
  18137. this.getDom().style.tabIndex = '-1';
  18138. uiUtils.makeUnselectable(this.getDom());
  18139. this.Stateful_postRender();
  18140. },
  18141. delayShowSubMenu: function () {
  18142. var me = this;
  18143. if (!me.isDisabled()) {
  18144. me.addState('opened');
  18145. clearTimeout(me._showingTimer);
  18146. clearTimeout(me._closingTimer);
  18147. me._closingTimer = null;
  18148. me._showingTimer = setTimeout(function () {
  18149. me.showSubMenu();
  18150. }, 250);
  18151. }
  18152. },
  18153. delayHideSubMenu: function () {
  18154. var me = this;
  18155. if (!me.isDisabled()) {
  18156. me.removeState('opened');
  18157. clearTimeout(me._showingTimer);
  18158. if (!me._closingTimer) {
  18159. me._closingTimer = setTimeout(function () {
  18160. if (!me.hasState('opened')) {
  18161. me.hideSubMenu();
  18162. }
  18163. me._closingTimer = null;
  18164. }, 400);
  18165. }
  18166. }
  18167. },
  18168. renderLabelHtml: function () {
  18169. return '<div class="edui-arrow"></div>' +
  18170. '<div class="edui-box edui-icon"></div>' +
  18171. '<div class="edui-box edui-label %%-label">' + (this.label || '') + '</div>';
  18172. },
  18173. getStateDom: function () {
  18174. return this.getDom();
  18175. },
  18176. queryAutoHide: function (el) {
  18177. if (this.subMenu && this.hasState('opened')) {
  18178. return this.subMenu.queryAutoHide(el);
  18179. }
  18180. },
  18181. _onClick: function (event, this_) {
  18182. if (this.hasState('disabled')) return;
  18183. if (this.fireEvent('click', event, this_) !== false) {
  18184. if (this.subMenu) {
  18185. this.showSubMenu();
  18186. } else {
  18187. Popup.postHide(event);
  18188. }
  18189. }
  18190. },
  18191. showSubMenu: function () {
  18192. var rect = uiUtils.getClientRect(this.getDom());
  18193. rect.right -= 5;
  18194. rect.left += 2;
  18195. rect.width -= 7;
  18196. rect.top -= 4;
  18197. rect.bottom += 4;
  18198. rect.height += 8;
  18199. this.subMenu.showAnchorRect(rect, true, true);
  18200. },
  18201. hideSubMenu: function () {
  18202. this.subMenu.hide();
  18203. }
  18204. };
  18205. utils.inherits(MenuItem, UIBase);
  18206. utils.extend(MenuItem.prototype, Stateful, true);
  18207. })();
  18208. ///import core
  18209. ///import uicore
  18210. ///import ui/menu.js
  18211. ///import ui/splitbutton.js
  18212. (function () {
  18213. // todo: menu和item提成通用list
  18214. var utils = baidu.editor.utils,
  18215. uiUtils = baidu.editor.ui.uiUtils,
  18216. Menu = baidu.editor.ui.Menu,
  18217. SplitButton = baidu.editor.ui.SplitButton,
  18218. Combox = baidu.editor.ui.Combox = function (options) {
  18219. this.initOptions(options);
  18220. this.initCombox();
  18221. };
  18222. Combox.prototype = {
  18223. uiName: 'combox',
  18224. initCombox: function () {
  18225. var me = this;
  18226. this.items = this.items || [];
  18227. for (var i = 0; i < this.items.length; i++) {
  18228. var item = this.items[i];
  18229. item.uiName = 'listitem';
  18230. item.index = i;
  18231. item.onclick = function () {
  18232. me.selectByIndex(this.index);
  18233. };
  18234. }
  18235. this.popup = new Menu({
  18236. items: this.items,
  18237. uiName: 'list',
  18238. editor: this.editor,
  18239. captureWheel: true,
  18240. combox: this
  18241. });
  18242. this.initSplitButton();
  18243. },
  18244. _SplitButton_postRender: SplitButton.prototype.postRender,
  18245. postRender: function () {
  18246. this._SplitButton_postRender();
  18247. this.setLabel(this.label || '');
  18248. this.setValue(this.initValue || '');
  18249. },
  18250. showPopup: function () {
  18251. var rect = uiUtils.getClientRect(this.getDom());
  18252. rect.top += 1;
  18253. rect.bottom -= 1;
  18254. rect.height -= 2;
  18255. this.popup.showAnchorRect(rect);
  18256. },
  18257. getValue: function () {
  18258. return this.value;
  18259. },
  18260. setValue: function (value) {
  18261. var index = this.indexByValue(value);
  18262. if (index != -1) {
  18263. this.selectedIndex = index;
  18264. this.setLabel(this.items[index].label);
  18265. this.value = this.items[index].value;
  18266. } else {
  18267. this.selectedIndex = -1;
  18268. this.setLabel(this.getLabelForUnknowValue(value));
  18269. this.value = value;
  18270. }
  18271. },
  18272. setLabel: function (label) {
  18273. this.getDom('button_body').innerHTML = label;
  18274. this.label = label;
  18275. },
  18276. getLabelForUnknowValue: function (value) {
  18277. return value;
  18278. },
  18279. indexByValue: function (value) {
  18280. for (var i = 0; i < this.items.length; i++) {
  18281. if (value == this.items[i].value) {
  18282. return i;
  18283. }
  18284. }
  18285. return -1;
  18286. },
  18287. getItem: function (index) {
  18288. return this.items[index];
  18289. },
  18290. selectByIndex: function (index) {
  18291. if (index < this.items.length && this.fireEvent('select', index) !== false) {
  18292. this.selectedIndex = index;
  18293. this.value = this.items[index].value;
  18294. this.setLabel(this.items[index].label);
  18295. }
  18296. }
  18297. };
  18298. utils.inherits(Combox, SplitButton);
  18299. })();
  18300. ///import core
  18301. ///import uicore
  18302. ///import ui/mask.js
  18303. ///import ui/button.js
  18304. (function () {
  18305. var utils = baidu.editor.utils,
  18306. domUtils = baidu.editor.dom.domUtils,
  18307. uiUtils = baidu.editor.ui.uiUtils,
  18308. Mask = baidu.editor.ui.Mask,
  18309. UIBase = baidu.editor.ui.UIBase,
  18310. Button = baidu.editor.ui.Button,
  18311. Dialog = baidu.editor.ui.Dialog = function (options) {
  18312. this.initOptions(utils.extend({
  18313. autoReset: true,
  18314. draggable: true,
  18315. onok: function () {
  18316. },
  18317. oncancel: function () {
  18318. },
  18319. onclose: function (t, ok) {
  18320. return ok ? this.onok() : this.oncancel();
  18321. },
  18322. //是否控制dialog中的scroll事件, 默认为不阻止
  18323. holdScroll: false
  18324. }, options));
  18325. this.initDialog();
  18326. };
  18327. var modalMask;
  18328. var dragMask;
  18329. Dialog.prototype = {
  18330. draggable: false,
  18331. uiName: 'dialog',
  18332. initDialog: function () {
  18333. var me = this,
  18334. theme = this.editor.options.theme;
  18335. this.initUIBase();
  18336. this.modalMask = (modalMask || (modalMask = new Mask({
  18337. className: 'edui-dialog-modalmask',
  18338. theme: theme
  18339. })));
  18340. this.dragMask = (dragMask || (dragMask = new Mask({
  18341. className: 'edui-dialog-dragmask',
  18342. theme: theme
  18343. })));
  18344. this.closeButton = new Button({
  18345. className: 'edui-dialog-closebutton',
  18346. title: me.closeDialog,
  18347. theme: theme,
  18348. onclick: function () {
  18349. me.close(false);
  18350. }
  18351. });
  18352. if (this.buttons) {
  18353. for (var i = 0; i < this.buttons.length; i++) {
  18354. if (!(this.buttons[i] instanceof Button)) {
  18355. this.buttons[i] = new Button(this.buttons[i]);
  18356. }
  18357. }
  18358. }
  18359. },
  18360. fitSize: function () {
  18361. var popBodyEl = this.getDom('body');
  18362. // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
  18363. // uiUtils.removeStyle(popBodyEl, 'width');
  18364. // uiUtils.removeStyle(popBodyEl, 'height');
  18365. // }
  18366. var size = this.mesureSize();
  18367. popBodyEl.style.width = size.width + 'px';
  18368. popBodyEl.style.height = size.height + 'px';
  18369. return size;
  18370. },
  18371. safeSetOffset: function (offset) {
  18372. var me = this;
  18373. var el = me.getDom();
  18374. var vpRect = uiUtils.getViewportRect();
  18375. var rect = uiUtils.getClientRect(el);
  18376. var left = offset.left;
  18377. if (left + rect.width > vpRect.right) {
  18378. left = vpRect.right - rect.width;
  18379. }
  18380. var top = offset.top;
  18381. if (top + rect.height > vpRect.bottom) {
  18382. top = vpRect.bottom - rect.height;
  18383. }
  18384. el.style.left = Math.max(left, 0) + 'px';
  18385. el.style.top = Math.max(top, 0) + 'px';
  18386. },
  18387. showAtCenter: function () {
  18388. this.getDom().style.display = '';
  18389. var vpRect = uiUtils.getViewportRect();
  18390. var popSize = this.fitSize();
  18391. var titleHeight = this.getDom('titlebar').offsetHeight | 0;
  18392. var left = vpRect.width / 2 - popSize.width / 2;
  18393. var top = vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
  18394. var popEl = this.getDom();
  18395. this.safeSetOffset({
  18396. left: Math.max(left | 0, 0),
  18397. top: Math.max(top | 0, 0)
  18398. });
  18399. if (!domUtils.hasClass(popEl, 'edui-state-centered')) {
  18400. popEl.className += ' edui-state-centered';
  18401. }
  18402. this._show();
  18403. },
  18404. getContentHtml: function () {
  18405. var contentHtml = '';
  18406. if (typeof this.content == 'string') {
  18407. contentHtml = this.content;
  18408. } else if (this.iframeUrl) {
  18409. contentHtml = '<span id="' + this.id + '_contmask" class="dialogcontmask"></span><iframe id="' + this.id +
  18410. '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="' + this.iframeUrl + '"></iframe>';
  18411. }
  18412. return contentHtml;
  18413. },
  18414. getHtmlTpl: function () {
  18415. var footHtml = '';
  18416. if (this.buttons) {
  18417. var buff = [];
  18418. for (var i = 0; i < this.buttons.length; i++) {
  18419. buff[i] = this.buttons[i].renderHtml();
  18420. }
  18421. footHtml = '<div class="%%-foot">' +
  18422. '<div id="##_buttons" class="%%-buttons">' + buff.join('') + '</div>' +
  18423. '</div>';
  18424. }
  18425. return '<div id="##" class="%%"><div class="%%-wrap"><div id="##_body" class="%%-body">' +
  18426. '<div class="%%-shadow"></div>' +
  18427. '<div id="##_titlebar" class="%%-titlebar">' +
  18428. '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
  18429. '<span class="%%-caption">' + (this.title || '') + '</span>' +
  18430. '</div>' +
  18431. this.closeButton.renderHtml() +
  18432. '</div>' +
  18433. '<div id="##_content" class="%%-content">' + ( this.autoReset ? '' : this.getContentHtml()) + '</div>' +
  18434. footHtml +
  18435. '</div></div></div>';
  18436. },
  18437. postRender: function () {
  18438. // todo: 保持居中/记住上次关闭位置选项
  18439. if (!this.modalMask.getDom()) {
  18440. this.modalMask.render();
  18441. this.modalMask.hide();
  18442. }
  18443. if (!this.dragMask.getDom()) {
  18444. this.dragMask.render();
  18445. this.dragMask.hide();
  18446. }
  18447. var me = this;
  18448. this.addListener('show', function () {
  18449. me.modalMask.show(this.getDom().style.zIndex - 2);
  18450. });
  18451. this.addListener('hide', function () {
  18452. me.modalMask.hide();
  18453. });
  18454. if (this.buttons) {
  18455. for (var i = 0; i < this.buttons.length; i++) {
  18456. this.buttons[i].postRender();
  18457. }
  18458. }
  18459. domUtils.on(window, 'resize', function () {
  18460. setTimeout(function () {
  18461. if (!me.isHidden()) {
  18462. me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
  18463. }
  18464. });
  18465. });
  18466. //hold住scroll事件,防止dialog的滚动影响页面
  18467. if (this.holdScroll) {
  18468. if (!me.iframeUrl) {
  18469. domUtils.on(document.getElementById(me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function (e) {
  18470. domUtils.preventDefault(e);
  18471. });
  18472. } else {
  18473. me.addListener('dialogafterreset', function () {
  18474. window.setTimeout(function () {
  18475. var iframeWindow = document.getElementById(me.id + "_iframe").contentWindow;
  18476. if (browser.ie) {
  18477. var timer = window.setInterval(function () {
  18478. if (iframeWindow.document && iframeWindow.document.body) {
  18479. window.clearInterval(timer);
  18480. timer = null;
  18481. domUtils.on(iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function (e) {
  18482. domUtils.preventDefault(e);
  18483. });
  18484. }
  18485. }, 100);
  18486. } else {
  18487. domUtils.on(iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function (e) {
  18488. domUtils.preventDefault(e);
  18489. });
  18490. }
  18491. }, 1);
  18492. });
  18493. }
  18494. }
  18495. this._hide();
  18496. },
  18497. mesureSize: function () {
  18498. var body = this.getDom('body');
  18499. var width = uiUtils.getClientRect(this.getDom('content')).width;
  18500. var dialogBodyStyle = body.style;
  18501. dialogBodyStyle.width = width;
  18502. return uiUtils.getClientRect(body);
  18503. },
  18504. _onTitlebarMouseDown: function (evt, el) {
  18505. if (this.draggable) {
  18506. var rect;
  18507. var vpRect = uiUtils.getViewportRect();
  18508. var me = this;
  18509. uiUtils.startDrag(evt, {
  18510. ondragstart: function () {
  18511. rect = uiUtils.getClientRect(me.getDom());
  18512. me.getDom('contmask').style.visibility = 'visible';
  18513. me.dragMask.show(me.getDom().style.zIndex - 1);
  18514. },
  18515. ondragmove: function (x, y) {
  18516. var left = rect.left + x;
  18517. var top = rect.top + y;
  18518. me.safeSetOffset({
  18519. left: left,
  18520. top: top
  18521. });
  18522. },
  18523. ondragstop: function () {
  18524. me.getDom('contmask').style.visibility = 'hidden';
  18525. domUtils.removeClasses(me.getDom(), ['edui-state-centered']);
  18526. me.dragMask.hide();
  18527. }
  18528. });
  18529. }
  18530. },
  18531. reset: function () {
  18532. this.getDom('content').innerHTML = this.getContentHtml();
  18533. this.fireEvent('dialogafterreset');
  18534. },
  18535. _show: function () {
  18536. if (this._hidden) {
  18537. this.getDom().style.display = '';
  18538. //要高过编辑器的zindxe
  18539. this.editor.container.style.zIndex && (this.getDom().style.zIndex = this.editor.container.style.zIndex * 1 + 10);
  18540. this._hidden = false;
  18541. this.fireEvent('show');
  18542. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = this.getDom().style.zIndex - 4;
  18543. }
  18544. },
  18545. isHidden: function () {
  18546. return this._hidden;
  18547. },
  18548. _hide: function () {
  18549. if (!this._hidden) {
  18550. this.getDom().style.display = 'none';
  18551. this.getDom().style.zIndex = '';
  18552. this._hidden = true;
  18553. this.fireEvent('hide');
  18554. }
  18555. },
  18556. open: function () {
  18557. if (this.autoReset) {
  18558. //有可能还没有渲染
  18559. try {
  18560. this.reset();
  18561. } catch (e) {
  18562. this.render();
  18563. this.open()
  18564. }
  18565. }
  18566. this.showAtCenter();
  18567. if (this.iframeUrl) {
  18568. try {
  18569. this.getDom('iframe').focus();
  18570. } catch (ex) {
  18571. }
  18572. }
  18573. },
  18574. _onCloseButtonClick: function (evt, el) {
  18575. this.close(false);
  18576. },
  18577. close: function (ok) {
  18578. if (this.fireEvent('close', ok) !== false) {
  18579. this._hide();
  18580. }
  18581. }
  18582. };
  18583. utils.inherits(Dialog, UIBase);
  18584. })();
  18585. ///import core
  18586. ///import uicore
  18587. ///import ui/menu.js
  18588. ///import ui/splitbutton.js
  18589. (function () {
  18590. var utils = baidu.editor.utils,
  18591. Menu = baidu.editor.ui.Menu,
  18592. SplitButton = baidu.editor.ui.SplitButton,
  18593. MenuButton = baidu.editor.ui.MenuButton = function (options) {
  18594. this.initOptions(options);
  18595. this.initMenuButton();
  18596. };
  18597. MenuButton.prototype = {
  18598. initMenuButton: function () {
  18599. var me = this;
  18600. this.uiName = "menubutton";
  18601. this.popup = new Menu({
  18602. items: me.items,
  18603. className: me.className,
  18604. editor: me.editor
  18605. });
  18606. this.popup.addListener('show', function () {
  18607. var list = this;
  18608. for (var i = 0; i < list.items.length; i++) {
  18609. list.items[i].removeState('checked');
  18610. if (list.items[i].value == me._value) {
  18611. list.items[i].addState('checked');
  18612. this.value = me._value;
  18613. }
  18614. }
  18615. });
  18616. this.initSplitButton();
  18617. },
  18618. setValue: function (value) {
  18619. this._value = value;
  18620. }
  18621. };
  18622. utils.inherits(MenuButton, SplitButton);
  18623. })();
  18624. //ui跟编辑器的适配層
  18625. //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
  18626. //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据ueditor.config中的toolbars找到相应的进行实例化
  18627. (function () {
  18628. var utils = baidu.editor.utils;
  18629. var editorui = baidu.editor.ui;
  18630. var _Dialog = editorui.Dialog;
  18631. editorui.buttons = {};
  18632. editorui.Dialog = function (options) {
  18633. var dialog = new _Dialog(options);
  18634. dialog.addListener('hide', function () {
  18635. if (dialog.editor) {
  18636. var editor = dialog.editor;
  18637. try {
  18638. if (browser.gecko) {
  18639. var y = editor.window.scrollY,
  18640. x = editor.window.scrollX;
  18641. editor.body.focus();
  18642. editor.window.scrollTo(x, y);
  18643. } else {
  18644. editor.focus();
  18645. }
  18646. } catch (ex) {
  18647. }
  18648. }
  18649. });
  18650. return dialog;
  18651. };
  18652. var iframeUrlMap = {
  18653. 'anchor': '~/dialogs/anchor/anchor.html',
  18654. 'insertimage': '~/dialogs/image/image.html',
  18655. 'link': '~/dialogs/link/link.html',
  18656. 'spechars': '~/dialogs/spechars/spechars.html',
  18657. 'searchreplace': '~/dialogs/searchreplace/searchreplace.html',
  18658. 'map': '~/dialogs/map/map.html',
  18659. 'gmap': '~/dialogs/gmap/gmap.html',
  18660. 'insertvideo': '~/dialogs/video/video.html',
  18661. 'help': '~/dialogs/help/help.html',
  18662. //'highlightcode':'~/dialogs/highlightcode/highlightcode.html',
  18663. 'emotion': '~/dialogs/emotion/emotion.html',
  18664. 'wordimage': '~/dialogs/wordimage/wordimage.html',
  18665. 'attachment': '~/dialogs/attachment/attachment.html',
  18666. 'insertframe': '~/dialogs/insertframe/insertframe.html',
  18667. 'edittip': '~/dialogs/table/edittip.html',
  18668. 'edittable': '~/dialogs/table/edittable.html',
  18669. 'edittd': '~/dialogs/table/edittd.html',
  18670. 'webapp': '~/dialogs/webapp/webapp.html',
  18671. 'snapscreen': '~/dialogs/snapscreen/snapscreen.html',
  18672. 'scrawl': '~/dialogs/scrawl/scrawl.html',
  18673. 'music': '~/dialogs/music/music.html',
  18674. 'template': '~/dialogs/template/template.html',
  18675. 'background': '~/dialogs/background/background.html'
  18676. };
  18677. //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  18678. var btnCmds = ['undo', 'redo', 'formatmatch',
  18679. 'bold', 'italic', 'underline', 'fontborder', 'touppercase', 'tolowercase',
  18680. 'strikethrough', 'subscript', 'superscript', 'source', 'indent', 'outdent',
  18681. 'blockquote', 'pasteplain', 'pagebreak',
  18682. 'selectall', 'print', 'preview', 'horizontal', 'removeformat', 'time', 'date', 'unlink',
  18683. 'insertparagraphbeforetable', 'insertrow', 'insertcol', 'mergeright', 'mergedown', 'deleterow',
  18684. 'deletecol', 'splittorows', 'splittocols', 'splittocells', 'mergecells', 'deletetable'];
  18685. for (var i = 0, ci; ci = btnCmds[i++];) {
  18686. ci = ci.toLowerCase();
  18687. editorui[ci] = function (cmd) {
  18688. return function (editor) {
  18689. var ui = new editorui.Button({
  18690. className: 'edui-for-' + cmd,
  18691. title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '',
  18692. onclick: function () {
  18693. editor.execCommand(cmd);
  18694. },
  18695. theme: editor.options.theme,
  18696. showText: false
  18697. });
  18698. editorui.buttons[cmd] = ui;
  18699. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  18700. var state = editor.queryCommandState(cmd);
  18701. if (state == -1) {
  18702. ui.setDisabled(true);
  18703. ui.setChecked(false);
  18704. } else {
  18705. if (!uiReady) {
  18706. ui.setDisabled(false);
  18707. ui.setChecked(state);
  18708. }
  18709. }
  18710. });
  18711. return ui;
  18712. };
  18713. }(ci);
  18714. }
  18715. //清除文档
  18716. editorui.cleardoc = function (editor) {
  18717. var ui = new editorui.Button({
  18718. className: 'edui-for-cleardoc',
  18719. title: editor.options.labelMap.cleardoc || editor.getLang("labelMap.cleardoc") || '',
  18720. theme: editor.options.theme,
  18721. onclick: function () {
  18722. if (confirm(editor.getLang("confirmClear"))) {
  18723. editor.execCommand('cleardoc');
  18724. }
  18725. }
  18726. });
  18727. editorui.buttons["cleardoc"] = ui;
  18728. editor.addListener('selectionchange', function () {
  18729. ui.setDisabled(editor.queryCommandState('cleardoc') == -1);
  18730. });
  18731. return ui;
  18732. };
  18733. //排版,图片排版,文字方向
  18734. var typeset = {
  18735. 'justify': ['left', 'right', 'center', 'justify'],
  18736. 'imagefloat': ['none', 'left', 'center', 'right'],
  18737. 'directionality': ['ltr', 'rtl']
  18738. };
  18739. for (var p in typeset) {
  18740. (function (cmd, val) {
  18741. for (var i = 0, ci; ci = val[i++];) {
  18742. (function (cmd2) {
  18743. editorui[cmd.replace('float', '') + cmd2] = function (editor) {
  18744. var ui = new editorui.Button({
  18745. className: 'edui-for-' + cmd.replace('float', '') + cmd2,
  18746. title: editor.options.labelMap[cmd.replace('float', '') + cmd2] || editor.getLang("labelMap." + cmd.replace('float', '') + cmd2) || '',
  18747. theme: editor.options.theme,
  18748. onclick: function () {
  18749. editor.execCommand(cmd, cmd2);
  18750. }
  18751. });
  18752. editorui.buttons[cmd] = ui;
  18753. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  18754. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  18755. ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady);
  18756. });
  18757. return ui;
  18758. };
  18759. })(ci)
  18760. }
  18761. })(p, typeset[p])
  18762. }
  18763. //字体颜色和背景颜色
  18764. for (var i = 0, ci; ci = ['backcolor', 'forecolor'][i++];) {
  18765. editorui[ci] = function (cmd) {
  18766. return function (editor) {
  18767. var ui = new editorui.ColorButton({
  18768. className: 'edui-for-' + cmd,
  18769. color: 'default',
  18770. title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '',
  18771. editor: editor,
  18772. onpickcolor: function (t, color) {
  18773. editor.execCommand(cmd, color);
  18774. },
  18775. onpicknocolor: function () {
  18776. editor.execCommand(cmd, 'default');
  18777. this.setColor('transparent');
  18778. this.color = 'default';
  18779. },
  18780. onbuttonclick: function () {
  18781. editor.execCommand(cmd, this.color);
  18782. }
  18783. });
  18784. editorui.buttons[cmd] = ui;
  18785. editor.addListener('selectionchange', function () {
  18786. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  18787. });
  18788. return ui;
  18789. };
  18790. }(ci);
  18791. }
  18792. var dialogBtns = {
  18793. noOk: ['searchreplace', 'help', 'spechars', 'webapp'],
  18794. ok: ['attachment', 'anchor', 'link', 'insertimage', 'map', 'gmap', 'insertframe', 'wordimage',
  18795. 'insertvideo', 'insertframe', 'edittip', 'edittable', 'edittd', 'scrawl', 'template', 'music', 'background']
  18796. };
  18797. for (var p in dialogBtns) {
  18798. (function (type, vals) {
  18799. for (var i = 0, ci; ci = vals[i++];) {
  18800. //todo opera下存在问题
  18801. if (browser.opera && ci === "searchreplace") {
  18802. continue;
  18803. }
  18804. (function (cmd) {
  18805. editorui[cmd] = function (editor, iframeUrl, title) {
  18806. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})[cmd] || iframeUrlMap[cmd];
  18807. title = editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '';
  18808. var dialog;
  18809. //没有iframeUrl不创建dialog
  18810. if (iframeUrl) {
  18811. dialog = new editorui.Dialog(utils.extend({
  18812. iframeUrl: editor.ui.mapUrl(iframeUrl),
  18813. editor: editor,
  18814. className: 'edui-for-' + cmd,
  18815. title: title,
  18816. holdScroll: cmd === 'insertimage',
  18817. closeDialog: editor.getLang("closeDialog")
  18818. }, type == 'ok' ? {
  18819. buttons: [
  18820. {
  18821. className: 'edui-okbutton',
  18822. label: editor.getLang("ok"),
  18823. editor: editor,
  18824. onclick: function () {
  18825. dialog.close(true);
  18826. }
  18827. },
  18828. {
  18829. className: 'edui-cancelbutton',
  18830. label: editor.getLang("cancel"),
  18831. editor: editor,
  18832. onclick: function () {
  18833. dialog.close(false);
  18834. }
  18835. }
  18836. ]
  18837. } : {}));
  18838. editor.ui._dialogs[cmd + "Dialog"] = dialog;
  18839. }
  18840. var ui = new editorui.Button({
  18841. className: 'edui-for-' + cmd,
  18842. title: title,
  18843. onclick: function () {
  18844. if (dialog) {
  18845. switch (cmd) {
  18846. case "wordimage":
  18847. editor.execCommand("wordimage", "word_img");
  18848. if (editor.word_img) {
  18849. dialog.render();
  18850. dialog.open();
  18851. }
  18852. break;
  18853. case "scrawl":
  18854. if (editor.queryCommandState("scrawl") != -1) {
  18855. dialog.render();
  18856. dialog.open();
  18857. }
  18858. break;
  18859. default:
  18860. dialog.render();
  18861. dialog.open();
  18862. }
  18863. }
  18864. },
  18865. theme: editor.options.theme,
  18866. disabled: cmd == 'scrawl' && editor.queryCommandState("scrawl") == -1
  18867. });
  18868. editorui.buttons[cmd] = ui;
  18869. editor.addListener('selectionchange', function () {
  18870. //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
  18871. var unNeedCheckState = {'edittable': 1};
  18872. if (cmd in unNeedCheckState)return;
  18873. var state = editor.queryCommandState(cmd);
  18874. if (ui.getDom()) {
  18875. ui.setDisabled(state == -1);
  18876. ui.setChecked(state);
  18877. }
  18878. });
  18879. return ui;
  18880. };
  18881. })(ci.toLowerCase())
  18882. }
  18883. })(p, dialogBtns[p])
  18884. }
  18885. editorui.snapscreen = function (editor, iframeUrl, title) {
  18886. title = editor.options.labelMap['snapscreen'] || editor.getLang("labelMap.snapscreen") || '';
  18887. var ui = new editorui.Button({
  18888. className: 'edui-for-snapscreen',
  18889. title: title,
  18890. onclick: function () {
  18891. editor.execCommand("snapscreen");
  18892. },
  18893. theme: editor.options.theme
  18894. });
  18895. editorui.buttons['snapscreen'] = ui;
  18896. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})["snapscreen"] || iframeUrlMap["snapscreen"];
  18897. if (iframeUrl) {
  18898. var dialog = new editorui.Dialog({
  18899. iframeUrl: editor.ui.mapUrl(iframeUrl),
  18900. editor: editor,
  18901. className: 'edui-for-snapscreen',
  18902. title: title,
  18903. buttons: [
  18904. {
  18905. className: 'edui-okbutton',
  18906. label: editor.getLang("ok"),
  18907. editor: editor,
  18908. onclick: function () {
  18909. dialog.close(true);
  18910. }
  18911. },
  18912. {
  18913. className: 'edui-cancelbutton',
  18914. label: editor.getLang("cancel"),
  18915. editor: editor,
  18916. onclick: function () {
  18917. dialog.close(false);
  18918. }
  18919. }
  18920. ]
  18921. });
  18922. dialog.render();
  18923. editor.ui._dialogs["snapscreenDialog"] = dialog;
  18924. }
  18925. editor.addListener('selectionchange', function () {
  18926. ui.setDisabled(editor.queryCommandState('snapscreen') == -1);
  18927. });
  18928. return ui;
  18929. };
  18930. editorui.insertcode = function (editor, list, title) {
  18931. list = editor.options['insertcode'] || [];
  18932. title = editor.options.labelMap['insertcode'] || editor.getLang("labelMap.insertcode") || '';
  18933. // if (!list.length) return;
  18934. var items = [];
  18935. utils.each(list, function (key, val) {
  18936. items.push({
  18937. label: key,
  18938. value: val,
  18939. theme: editor.options.theme,
  18940. renderLabelHtml: function () {
  18941. return '<div class="edui-label %%-label" >' + (this.label || '') + '</div>';
  18942. }
  18943. });
  18944. });
  18945. var ui = new editorui.Combox({
  18946. editor: editor,
  18947. items: items,
  18948. onselect: function (t, index) {
  18949. editor.execCommand('insertcode', this.items[index].value);
  18950. },
  18951. onbuttonclick: function () {
  18952. this.showPopup();
  18953. },
  18954. title: title,
  18955. initValue: title,
  18956. className: 'edui-for-insertcode',
  18957. indexByValue: function (value) {
  18958. if (value) {
  18959. for (var i = 0, ci; ci = this.items[i]; i++) {
  18960. if (ci.value.indexOf(value) != -1)
  18961. return i;
  18962. }
  18963. }
  18964. return -1;
  18965. }
  18966. });
  18967. editorui.buttons['insertcode'] = ui;
  18968. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  18969. if (!uiReady) {
  18970. var state = editor.queryCommandState('insertcode');
  18971. if (state == -1) {
  18972. ui.setDisabled(true);
  18973. } else {
  18974. ui.setDisabled(false);
  18975. var value = editor.queryCommandValue('insertcode');
  18976. if (!value) {
  18977. ui.setValue(title);
  18978. return;
  18979. }
  18980. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  18981. value && (value = value.replace(/['"]/g, '').split(',')[0]);
  18982. ui.setValue(value);
  18983. }
  18984. }
  18985. });
  18986. return ui;
  18987. };
  18988. editorui.fontfamily = function (editor, list, title) {
  18989. list = editor.options['fontfamily'] || [];
  18990. title = editor.options.labelMap['fontfamily'] || editor.getLang("labelMap.fontfamily") || '';
  18991. if (!list.length) return;
  18992. for (var i = 0, ci, items = []; ci = list[i]; i++) {
  18993. var langLabel = editor.getLang('fontfamily')[ci.name] || "";
  18994. (function (key, val) {
  18995. items.push({
  18996. label: key,
  18997. value: val,
  18998. theme: editor.options.theme,
  18999. renderLabelHtml: function () {
  19000. return '<div class="edui-label %%-label" style="font-family:' +
  19001. utils.unhtml(this.value) + '">' + (this.label || '') + '</div>';
  19002. }
  19003. });
  19004. })(ci.label || langLabel, ci.val)
  19005. }
  19006. var ui = new editorui.Combox({
  19007. editor: editor,
  19008. items: items,
  19009. onselect: function (t, index) {
  19010. editor.execCommand('FontFamily', this.items[index].value);
  19011. },
  19012. onbuttonclick: function () {
  19013. this.showPopup();
  19014. },
  19015. title: title,
  19016. initValue: title,
  19017. className: 'edui-for-fontfamily',
  19018. indexByValue: function (value) {
  19019. if (value) {
  19020. for (var i = 0, ci; ci = this.items[i]; i++) {
  19021. if (ci.value.indexOf(value) != -1)
  19022. return i;
  19023. }
  19024. }
  19025. return -1;
  19026. }
  19027. });
  19028. editorui.buttons['fontfamily'] = ui;
  19029. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  19030. if (!uiReady) {
  19031. var state = editor.queryCommandState('FontFamily');
  19032. if (state == -1) {
  19033. ui.setDisabled(true);
  19034. } else {
  19035. ui.setDisabled(false);
  19036. var value = editor.queryCommandValue('FontFamily');
  19037. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  19038. value && (value = value.replace(/['"]/g, '').split(',')[0]);
  19039. ui.setValue(value);
  19040. }
  19041. }
  19042. });
  19043. return ui;
  19044. };
  19045. editorui.fontsize = function (editor, list, title) {
  19046. title = editor.options.labelMap['fontsize'] || editor.getLang("labelMap.fontsize") || '';
  19047. list = list || editor.options['fontsize'] || [];
  19048. if (!list.length) return;
  19049. var items = [];
  19050. for (var i = 0; i < list.length; i++) {
  19051. var size = list[i] + 'px';
  19052. items.push({
  19053. label: size,
  19054. value: size,
  19055. theme: editor.options.theme,
  19056. renderLabelHtml: function () {
  19057. return '<div class="edui-label %%-label" style="line-height:1;font-size:' +
  19058. this.value + '">' + (this.label || '') + '</div>';
  19059. }
  19060. });
  19061. }
  19062. var ui = new editorui.Combox({
  19063. editor: editor,
  19064. items: items,
  19065. title: title,
  19066. initValue: title,
  19067. onselect: function (t, index) {
  19068. editor.execCommand('FontSize', this.items[index].value);
  19069. },
  19070. onbuttonclick: function () {
  19071. this.showPopup();
  19072. },
  19073. className: 'edui-for-fontsize'
  19074. });
  19075. editorui.buttons['fontsize'] = ui;
  19076. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  19077. if (!uiReady) {
  19078. var state = editor.queryCommandState('FontSize');
  19079. if (state == -1) {
  19080. ui.setDisabled(true);
  19081. } else {
  19082. ui.setDisabled(false);
  19083. ui.setValue(editor.queryCommandValue('FontSize'));
  19084. }
  19085. }
  19086. });
  19087. return ui;
  19088. };
  19089. editorui.paragraph = function (editor, list, title) {
  19090. title = editor.options.labelMap['paragraph'] || editor.getLang("labelMap.paragraph") || '';
  19091. list = editor.options['paragraph'] || [];
  19092. if (utils.isEmptyObject(list)) return;
  19093. var items = [];
  19094. for (var i in list) {
  19095. items.push({
  19096. value: i,
  19097. label: list[i] || editor.getLang("paragraph")[i],
  19098. theme: editor.options.theme,
  19099. renderLabelHtml: function () {
  19100. return '<div class="edui-label %%-label"><span class="edui-for-' + this.value + '">' + (this.label || '') + '</span></div>';
  19101. }
  19102. })
  19103. }
  19104. var ui = new editorui.Combox({
  19105. editor: editor,
  19106. items: items,
  19107. title: title,
  19108. initValue: title,
  19109. className: 'edui-for-paragraph',
  19110. onselect: function (t, index) {
  19111. editor.execCommand('Paragraph', this.items[index].value);
  19112. },
  19113. onbuttonclick: function () {
  19114. this.showPopup();
  19115. }
  19116. });
  19117. editorui.buttons['paragraph'] = ui;
  19118. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  19119. if (!uiReady) {
  19120. var state = editor.queryCommandState('Paragraph');
  19121. if (state == -1) {
  19122. ui.setDisabled(true);
  19123. } else {
  19124. ui.setDisabled(false);
  19125. var value = editor.queryCommandValue('Paragraph');
  19126. var index = ui.indexByValue(value);
  19127. if (index != -1) {
  19128. ui.setValue(value);
  19129. } else {
  19130. ui.setValue(ui.initValue);
  19131. }
  19132. }
  19133. }
  19134. });
  19135. return ui;
  19136. };
  19137. //自定义标题
  19138. editorui.customstyle = function (editor) {
  19139. var list = editor.options['customstyle'] || [],
  19140. title = editor.options.labelMap['customstyle'] || editor.getLang("labelMap.customstyle") || '';
  19141. if (!list.length)return;
  19142. var langCs = editor.getLang('customstyle');
  19143. for (var i = 0, items = [], t; t = list[i++];) {
  19144. (function (t) {
  19145. var ck = {};
  19146. ck.label = t.label ? t.label : langCs[t.name];
  19147. ck.style = t.style;
  19148. ck.className = t.className;
  19149. ck.tag = t.tag;
  19150. items.push({
  19151. label: ck.label,
  19152. value: ck,
  19153. theme: editor.options.theme,
  19154. renderLabelHtml: function () {
  19155. return '<div class="edui-label %%-label">' + '<' + ck.tag + ' ' + (ck.className ? ' class="' + ck.className + '"' : "")
  19156. + (ck.style ? ' style="' + ck.style + '"' : "") + '>' + ck.label + "<\/" + ck.tag + ">"
  19157. + '</div>';
  19158. }
  19159. });
  19160. })(t);
  19161. }
  19162. var ui = new editorui.Combox({
  19163. editor: editor,
  19164. items: items,
  19165. title: title,
  19166. initValue: title,
  19167. className: 'edui-for-customstyle',
  19168. onselect: function (t, index) {
  19169. editor.execCommand('customstyle', this.items[index].value);
  19170. },
  19171. onbuttonclick: function () {
  19172. this.showPopup();
  19173. },
  19174. indexByValue: function (value) {
  19175. for (var i = 0, ti; ti = this.items[i++];) {
  19176. if (ti.label == value) {
  19177. return i - 1
  19178. }
  19179. }
  19180. return -1;
  19181. }
  19182. });
  19183. editorui.buttons['customstyle'] = ui;
  19184. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  19185. if (!uiReady) {
  19186. var state = editor.queryCommandState('customstyle');
  19187. if (state == -1) {
  19188. ui.setDisabled(true);
  19189. } else {
  19190. ui.setDisabled(false);
  19191. var value = editor.queryCommandValue('customstyle');
  19192. var index = ui.indexByValue(value);
  19193. if (index != -1) {
  19194. ui.setValue(value);
  19195. } else {
  19196. ui.setValue(ui.initValue);
  19197. }
  19198. }
  19199. }
  19200. });
  19201. return ui;
  19202. };
  19203. editorui.inserttable = function (editor, iframeUrl, title) {
  19204. title = editor.options.labelMap['inserttable'] || editor.getLang("labelMap.inserttable") || '';
  19205. var ui = new editorui.TableButton({
  19206. editor: editor,
  19207. title: title,
  19208. className: 'edui-for-inserttable',
  19209. onpicktable: function (t, numCols, numRows) {
  19210. editor.execCommand('InsertTable', {numRows: numRows, numCols: numCols, border: 1});
  19211. },
  19212. onbuttonclick: function () {
  19213. this.showPopup();
  19214. }
  19215. });
  19216. editorui.buttons['inserttable'] = ui;
  19217. editor.addListener('selectionchange', function () {
  19218. ui.setDisabled(editor.queryCommandState('inserttable') == -1);
  19219. });
  19220. return ui;
  19221. };
  19222. editorui.lineheight = function (editor) {
  19223. var val = editor.options.lineheight || [];
  19224. if (!val.length)return;
  19225. for (var i = 0, ci, items = []; ci = val[i++];) {
  19226. items.push({
  19227. //todo:写死了
  19228. label: ci,
  19229. value: ci,
  19230. theme: editor.options.theme,
  19231. onclick: function () {
  19232. editor.execCommand("lineheight", this.value);
  19233. }
  19234. })
  19235. }
  19236. var ui = new editorui.MenuButton({
  19237. editor: editor,
  19238. className: 'edui-for-lineheight',
  19239. title: editor.options.labelMap['lineheight'] || editor.getLang("labelMap.lineheight") || '',
  19240. items: items,
  19241. onbuttonclick: function () {
  19242. var value = editor.queryCommandValue('LineHeight') || this.value;
  19243. editor.execCommand("LineHeight", value);
  19244. }
  19245. });
  19246. editorui.buttons['lineheight'] = ui;
  19247. editor.addListener('selectionchange', function () {
  19248. var state = editor.queryCommandState('LineHeight');
  19249. if (state == -1) {
  19250. ui.setDisabled(true);
  19251. } else {
  19252. ui.setDisabled(false);
  19253. var value = editor.queryCommandValue('LineHeight');
  19254. value && ui.setValue((value + '').replace(/cm/, ''));
  19255. ui.setChecked(state)
  19256. }
  19257. });
  19258. return ui;
  19259. };
  19260. var rowspacings = ['top', 'bottom'];
  19261. for (var r = 0, ri; ri = rowspacings[r++];) {
  19262. (function (cmd) {
  19263. editorui['rowspacing' + cmd] = function (editor) {
  19264. var val = editor.options['rowspacing' + cmd] || [];
  19265. if (!val.length) return null;
  19266. for (var i = 0, ci, items = []; ci = val[i++];) {
  19267. items.push({
  19268. label: ci,
  19269. value: ci,
  19270. theme: editor.options.theme,
  19271. onclick: function () {
  19272. editor.execCommand("rowspacing", this.value, cmd);
  19273. }
  19274. })
  19275. }
  19276. var ui = new editorui.MenuButton({
  19277. editor: editor,
  19278. className: 'edui-for-rowspacing' + cmd,
  19279. title: editor.options.labelMap['rowspacing' + cmd] || editor.getLang("labelMap.rowspacing" + cmd) || '',
  19280. items: items,
  19281. onbuttonclick: function () {
  19282. var value = editor.queryCommandValue('rowspacing', cmd) || this.value;
  19283. editor.execCommand("rowspacing", value, cmd);
  19284. }
  19285. });
  19286. editorui.buttons[cmd] = ui;
  19287. editor.addListener('selectionchange', function () {
  19288. var state = editor.queryCommandState('rowspacing', cmd);
  19289. if (state == -1) {
  19290. ui.setDisabled(true);
  19291. } else {
  19292. ui.setDisabled(false);
  19293. var value = editor.queryCommandValue('rowspacing', cmd);
  19294. value && ui.setValue((value + '').replace(/%/, ''));
  19295. ui.setChecked(state)
  19296. }
  19297. });
  19298. return ui;
  19299. }
  19300. })(ri)
  19301. }
  19302. //有序,无序列表
  19303. var lists = ['insertorderedlist', 'insertunorderedlist'];
  19304. for (var l = 0, cl; cl = lists[l++];) {
  19305. (function (cmd) {
  19306. editorui[cmd] = function (editor) {
  19307. var vals = editor.options[cmd],
  19308. _onMenuClick = function () {
  19309. editor.execCommand(cmd, this.value);
  19310. }, items = [];
  19311. for (var i in vals) {
  19312. items.push({
  19313. label: vals[i] || editor.getLang()[cmd][i] || "",
  19314. value: i,
  19315. theme: editor.options.theme,
  19316. onclick: _onMenuClick
  19317. })
  19318. }
  19319. var ui = new editorui.MenuButton({
  19320. editor: editor,
  19321. className: 'edui-for-' + cmd,
  19322. title: editor.getLang("labelMap." + cmd) || '',
  19323. 'items': items,
  19324. onbuttonclick: function () {
  19325. var value = editor.queryCommandValue(cmd) || this.value;
  19326. editor.execCommand(cmd, value);
  19327. }
  19328. });
  19329. editorui.buttons[cmd] = ui;
  19330. editor.addListener('selectionchange', function () {
  19331. var state = editor.queryCommandState(cmd);
  19332. if (state == -1) {
  19333. ui.setDisabled(true);
  19334. } else {
  19335. ui.setDisabled(false);
  19336. var value = editor.queryCommandValue(cmd);
  19337. ui.setValue(value);
  19338. ui.setChecked(state)
  19339. }
  19340. });
  19341. return ui;
  19342. };
  19343. })(cl)
  19344. }
  19345. editorui.fullscreen = function (editor, title) {
  19346. title = editor.options.labelMap['fullscreen'] || editor.getLang("labelMap.fullscreen") || '';
  19347. var ui = new editorui.Button({
  19348. className: 'edui-for-fullscreen',
  19349. title: title,
  19350. theme: editor.options.theme,
  19351. onclick: function () {
  19352. if (editor.ui) {
  19353. editor.ui.setFullScreen(!editor.ui.isFullScreen());
  19354. }
  19355. this.setChecked(editor.ui.isFullScreen());
  19356. }
  19357. });
  19358. editorui.buttons['fullscreen'] = ui;
  19359. editor.addListener('selectionchange', function () {
  19360. var state = editor.queryCommandState('fullscreen');
  19361. ui.setDisabled(state == -1);
  19362. ui.setChecked(editor.ui.isFullScreen());
  19363. });
  19364. return ui;
  19365. };
  19366. // 表情
  19367. editorui["emotion"] = function (editor, iframeUrl) {
  19368. var cmd = "emotion";
  19369. var ui = new editorui.MultiMenuPop({
  19370. title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd + "") || '',
  19371. editor: editor,
  19372. className: 'edui-for-' + cmd,
  19373. iframeUrl: editor.ui.mapUrl(iframeUrl || (editor.options.iframeUrlMap || {})[cmd] || iframeUrlMap[cmd])
  19374. });
  19375. editorui.buttons[cmd] = ui;
  19376. editor.addListener('selectionchange', function () {
  19377. ui.setDisabled(editor.queryCommandState(cmd) == -1)
  19378. });
  19379. return ui;
  19380. };
  19381. editorui.autotypeset = function (editor) {
  19382. var ui = new editorui.AutoTypeSetButton({
  19383. editor: editor,
  19384. title: editor.options.labelMap['autotypeset'] || editor.getLang("labelMap.autotypeset") || '',
  19385. className: 'edui-for-autotypeset',
  19386. onbuttonclick: function () {
  19387. editor.execCommand('autotypeset')
  19388. }
  19389. });
  19390. editorui.buttons['autotypeset'] = ui;
  19391. editor.addListener('selectionchange', function () {
  19392. ui.setDisabled(editor.queryCommandState('autotypeset') == -1);
  19393. });
  19394. return ui;
  19395. };
  19396. })();
  19397. ///import core
  19398. ///commands 全屏
  19399. ///commandsName FullScreen
  19400. ///commandsTitle 全屏
  19401. (function () {
  19402. var utils = baidu.editor.utils,
  19403. uiUtils = baidu.editor.ui.uiUtils,
  19404. UIBase = baidu.editor.ui.UIBase,
  19405. domUtils = baidu.editor.dom.domUtils;
  19406. var nodeStack = [];
  19407. function EditorUI(options) {
  19408. this.initOptions(options);
  19409. this.initEditorUI();
  19410. }
  19411. EditorUI.prototype = {
  19412. uiName: 'editor',
  19413. initEditorUI: function () {
  19414. this.editor.ui = this;
  19415. this._dialogs = {};
  19416. this.initUIBase();
  19417. this._initToolbars();
  19418. var editor = this.editor,
  19419. me = this;
  19420. editor.addListener('ready', function () {
  19421. //提供getDialog方法
  19422. editor.getDialog = function (name) {
  19423. return editor.ui._dialogs[name + "Dialog"];
  19424. };
  19425. domUtils.on(editor.window, 'scroll', function (evt) {
  19426. baidu.editor.ui.Popup.postHide(evt);
  19427. });
  19428. //提供编辑器实时宽高(全屏时宽高不变化)
  19429. editor.ui._actualFrameWidth = editor.options.initialFrameWidth;
  19430. //display bottom-bar label based on config
  19431. if (editor.options.elementPathEnabled) {
  19432. editor.ui.getDom('elementpath').innerHTML = '<div class="edui-editor-breadcrumb">' + editor.getLang("elementPathTip") + ':</div>';
  19433. }
  19434. if (editor.options.wordCount) {
  19435. function countFn() {
  19436. setCount(editor, me);
  19437. domUtils.un(editor.document, "click", arguments.callee);
  19438. }
  19439. domUtils.on(editor.document, "click", countFn);
  19440. editor.ui.getDom('wordcount').innerHTML = editor.getLang("wordCountTip");
  19441. }
  19442. editor.ui._scale();
  19443. if (editor.options.scaleEnabled) {
  19444. if (editor.autoHeightEnabled) {
  19445. editor.disableAutoHeight();
  19446. }
  19447. me.enableScale();
  19448. } else {
  19449. me.disableScale();
  19450. }
  19451. if (!editor.options.elementPathEnabled && !editor.options.wordCount && !editor.options.scaleEnabled) {
  19452. editor.ui.getDom('elementpath').style.display = "none";
  19453. editor.ui.getDom('wordcount').style.display = "none";
  19454. editor.ui.getDom('scale').style.display = "none";
  19455. }
  19456. if (!editor.selection.isFocus())return;
  19457. editor.fireEvent('selectionchange', false, true);
  19458. });
  19459. editor.addListener('mousedown', function (t, evt) {
  19460. var el = evt.target || evt.srcElement;
  19461. baidu.editor.ui.Popup.postHide(evt, el);
  19462. baidu.editor.ui.ShortCutMenu.postHide(evt);
  19463. });
  19464. editor.addListener("delcells", function () {
  19465. if (UE.ui['edittip']) {
  19466. new UE.ui['edittip'](editor);
  19467. }
  19468. editor.getDialog('edittip').open();
  19469. });
  19470. var pastePop, isPaste = false, timer;
  19471. editor.addListener("afterpaste", function () {
  19472. if (editor.queryCommandState('pasteplain'))
  19473. return;
  19474. if (baidu.editor.ui.PastePicker) {
  19475. pastePop = new baidu.editor.ui.Popup({
  19476. content: new baidu.editor.ui.PastePicker({editor: editor}),
  19477. editor: editor,
  19478. className: 'edui-wordpastepop'
  19479. });
  19480. pastePop.render();
  19481. }
  19482. isPaste = true;
  19483. });
  19484. editor.addListener("afterinserthtml", function () {
  19485. clearTimeout(timer);
  19486. timer = setTimeout(function () {
  19487. if (pastePop && (isPaste || editor.ui._isTransfer)) {
  19488. if (pastePop.isHidden()) {
  19489. var span = domUtils.createElement(editor.document, 'span', {
  19490. 'style': "line-height:0px;",
  19491. 'innerHTML': '\ufeff'
  19492. }),
  19493. range = editor.selection.getRange();
  19494. range.insertNode(span);
  19495. var tmp = getDomNode(span, 'firstChild', 'previousSibling');
  19496. pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp);
  19497. domUtils.remove(span);
  19498. } else {
  19499. pastePop.show();
  19500. }
  19501. delete editor.ui._isTransfer;
  19502. isPaste = false;
  19503. }
  19504. }, 200)
  19505. });
  19506. editor.addListener('contextmenu', function (t, evt) {
  19507. baidu.editor.ui.Popup.postHide(evt);
  19508. });
  19509. editor.addListener('keydown', function (t, evt) {
  19510. if (pastePop) pastePop.dispose(evt);
  19511. var keyCode = evt.keyCode || evt.which;
  19512. if (evt.altKey && keyCode == 90) {
  19513. UE.ui.buttons['fullscreen'].onclick();
  19514. }
  19515. });
  19516. editor.addListener('wordcount', function (type) {
  19517. setCount(this, me);
  19518. });
  19519. function setCount(editor, ui) {
  19520. editor.setOpt({
  19521. wordCount: true,
  19522. maximumWords: 10000,
  19523. wordCountMsg: editor.options.wordCountMsg || editor.getLang("wordCountMsg"),
  19524. wordOverFlowMsg: editor.options.wordOverFlowMsg || editor.getLang("wordOverFlowMsg")
  19525. });
  19526. var opt = editor.options,
  19527. max = opt.maximumWords,
  19528. msg = opt.wordCountMsg ,
  19529. errMsg = opt.wordOverFlowMsg,
  19530. countDom = ui.getDom('wordcount');
  19531. if (!opt.wordCount) {
  19532. return;
  19533. }
  19534. var count = editor.getContentLength(true);
  19535. if (count > max) {
  19536. countDom.innerHTML = errMsg;
  19537. editor.fireEvent("wordcountoverflow");
  19538. } else {
  19539. countDom.innerHTML = msg.replace("{#leave}", max - count).replace("{#count}", count);
  19540. }
  19541. }
  19542. editor.addListener('selectionchange', function () {
  19543. if (editor.options.elementPathEnabled) {
  19544. me[(editor.queryCommandState('elementpath') == -1 ? 'dis' : 'en') + 'ableElementPath']()
  19545. }
  19546. if (editor.options.scaleEnabled) {
  19547. me[(editor.queryCommandState('scale') == -1 ? 'dis' : 'en') + 'ableScale']();
  19548. }
  19549. });
  19550. var popup = new baidu.editor.ui.Popup({
  19551. editor: editor,
  19552. content: '',
  19553. className: 'edui-bubble',
  19554. _onEditButtonClick: function () {
  19555. this.hide();
  19556. editor.ui._dialogs.linkDialog.open();
  19557. },
  19558. _onImgEditButtonClick: function (name) {
  19559. this.hide();
  19560. editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
  19561. },
  19562. _onImgSetFloat: function (value) {
  19563. this.hide();
  19564. editor.execCommand("imagefloat", value);
  19565. },
  19566. _setIframeAlign: function (value) {
  19567. var frame = popup.anchorEl;
  19568. var newFrame = frame.cloneNode(true);
  19569. switch (value) {
  19570. case -2:
  19571. newFrame.setAttribute("align", "");
  19572. break;
  19573. case -1:
  19574. newFrame.setAttribute("align", "left");
  19575. break;
  19576. case 1:
  19577. newFrame.setAttribute("align", "right");
  19578. break;
  19579. }
  19580. frame.parentNode.insertBefore(newFrame, frame);
  19581. domUtils.remove(frame);
  19582. popup.anchorEl = newFrame;
  19583. popup.showAnchor(popup.anchorEl);
  19584. },
  19585. _updateIframe: function () {
  19586. editor._iframe = popup.anchorEl;
  19587. editor.ui._dialogs.insertframeDialog.open();
  19588. popup.hide();
  19589. },
  19590. _onRemoveButtonClick: function (cmdName) {
  19591. editor.execCommand(cmdName);
  19592. this.hide();
  19593. },
  19594. queryAutoHide: function (el) {
  19595. if (el && el.ownerDocument == editor.document) {
  19596. if (el.tagName.toLowerCase() == 'img' || domUtils.findParentByTagName(el, 'a', true)) {
  19597. return el !== popup.anchorEl;
  19598. }
  19599. }
  19600. return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el);
  19601. }
  19602. });
  19603. popup.render();
  19604. if (editor.options.imagePopup) {
  19605. editor.addListener('mouseover', function (t, evt) {
  19606. evt = evt || window.event;
  19607. var el = evt.target || evt.srcElement;
  19608. if (editor.ui._dialogs.insertframeDialog && /iframe/ig.test(el.tagName)) {
  19609. var html = popup.formatHtml(
  19610. '<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;' +
  19611. ' <span onclick="$$._updateIframe( this);" class="edui-clickable">' + editor.getLang("modify") + '</span></nobr>');
  19612. if (html) {
  19613. popup.getDom('content').innerHTML = html;
  19614. popup.anchorEl = el;
  19615. popup.showAnchor(popup.anchorEl);
  19616. } else {
  19617. popup.hide();
  19618. }
  19619. }
  19620. });
  19621. editor.addListener('selectionchange', function (t, causeByUi) {
  19622. if (!causeByUi) return;
  19623. var html = '', str = "",
  19624. img = editor.selection.getRange().getClosedNode(),
  19625. dialogs = editor.ui._dialogs;
  19626. if (img && img.tagName == 'IMG') {
  19627. var dialogName = 'insertimageDialog';
  19628. if (img.className.indexOf("edui-faked-video") != -1) {
  19629. dialogName = "insertvideoDialog"
  19630. }
  19631. if (img.className.indexOf("edui-faked-webapp") != -1) {
  19632. dialogName = "webappDialog"
  19633. }
  19634. if (img.src.indexOf("http://api.map.baidu.com") != -1) {
  19635. dialogName = "mapDialog"
  19636. }
  19637. if (img.className.indexOf("edui-faked-music") != -1) {
  19638. dialogName = "musicDialog"
  19639. }
  19640. if (img.src.indexOf("http://maps.google.com/maps/api/staticmap") != -1) {
  19641. dialogName = "gmapDialog"
  19642. }
  19643. if (img.getAttribute("anchorname")) {
  19644. dialogName = "anchorDialog";
  19645. html = popup.formatHtml(
  19646. '<nobr>' + editor.getLang("property") + ': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' + editor.getLang("modify") + '</span>&nbsp;&nbsp;' +
  19647. '<span onclick=$$._onRemoveButtonClick(\'anchor\') class="edui-clickable">' + editor.getLang("delete") + '</span></nobr>');
  19648. }
  19649. if (img.getAttribute("word_img")) {
  19650. //todo 放到dialog去做查询
  19651. editor.word_img = [img.getAttribute("word_img")];
  19652. dialogName = "wordimageDialog"
  19653. }
  19654. if (!dialogs[dialogName]) {
  19655. return;
  19656. }
  19657. str = '<nobr>' + editor.getLang("property") + ': ' +
  19658. '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' + editor.getLang("default") + '</span>&nbsp;&nbsp;' +
  19659. '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' + editor.getLang("justifyleft") + '</span>&nbsp;&nbsp;' +
  19660. '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' + editor.getLang("justifyright") + '</span>&nbsp;&nbsp;' +
  19661. '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' + editor.getLang("justifycenter") + '</span>&nbsp;&nbsp;' +
  19662. '<span onclick="$$._onImgEditButtonClick(\'' + dialogName + '\');" class="edui-clickable">' + editor.getLang("modify") + '</span></nobr>';
  19663. !html && (html = popup.formatHtml(str))
  19664. }
  19665. if (editor.ui._dialogs.linkDialog) {
  19666. var link = editor.queryCommandValue('link');
  19667. var url;
  19668. if (link && (url = (link.getAttribute('_href') || link.getAttribute('href', 2)))) {
  19669. var txt = url;
  19670. if (url.length > 30) {
  19671. txt = url.substring(0, 20) + "...";
  19672. }
  19673. if (html) {
  19674. html += '<div style="height:5px;"></div>'
  19675. }
  19676. html += popup.formatHtml(
  19677. '<nobr>' + editor.getLang("anthorMsg") + ': <a target="_blank" href="' + url + '" title="' + url + '" >' + txt + '</a>' +
  19678. ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' + editor.getLang("modify") + '</span>' +
  19679. ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' + editor.getLang("clear") + '</span></nobr>');
  19680. popup.showAnchor(link);
  19681. }
  19682. }
  19683. if (html) {
  19684. popup.getDom('content').innerHTML = html;
  19685. popup.anchorEl = img || link;
  19686. popup.showAnchor(popup.anchorEl);
  19687. } else {
  19688. popup.hide();
  19689. }
  19690. });
  19691. }
  19692. },
  19693. _initToolbars: function () {
  19694. var editor = this.editor;
  19695. var toolbars = this.toolbars || [];
  19696. var toolbarUis = [];
  19697. for (var i = 0; i < toolbars.length; i++) {
  19698. var toolbar = toolbars[i];
  19699. var toolbarUi = new baidu.editor.ui.Toolbar({theme: editor.options.theme});
  19700. for (var j = 0; j < toolbar.length; j++) {
  19701. var toolbarItem = toolbar[j];
  19702. var toolbarItemUi = null;
  19703. if (typeof toolbarItem == 'string') {
  19704. toolbarItem = toolbarItem.toLowerCase();
  19705. if (toolbarItem == '|') {
  19706. toolbarItem = 'Separator';
  19707. }
  19708. if (toolbarItem == '||') {
  19709. toolbarItem = 'Breakline';
  19710. }
  19711. if (baidu.editor.ui[toolbarItem]) {
  19712. toolbarItemUi = new baidu.editor.ui[toolbarItem](editor);
  19713. }
  19714. //fullscreen这里单独处理一下,放到首行去
  19715. if (toolbarItem == 'fullscreen') {
  19716. if (toolbarUis && toolbarUis[0]) {
  19717. toolbarUis[0].items.splice(0, 0, toolbarItemUi);
  19718. } else {
  19719. toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi);
  19720. }
  19721. continue;
  19722. }
  19723. } else {
  19724. toolbarItemUi = toolbarItem;
  19725. }
  19726. if (toolbarItemUi && toolbarItemUi.id) {
  19727. toolbarUi.add(toolbarItemUi);
  19728. }
  19729. }
  19730. toolbarUis[i] = toolbarUi;
  19731. }
  19732. this.toolbars = toolbarUis;
  19733. },
  19734. getHtmlTpl: function () {
  19735. return '<div id="##" class="%%">' +
  19736. '<div id="##_toolbarbox" class="%%-toolbarbox">' +
  19737. (this.toolbars.length ?
  19738. '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
  19739. this.renderToolbarBoxHtml() +
  19740. '</div></div>' : '') +
  19741. '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
  19742. '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' + this.editor.getLang("clickToUpload") + '</div>' +
  19743. '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
  19744. '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
  19745. '<div style="height:0;overflow:hidden;clear:both;"></div>' +
  19746. '</div>' +
  19747. '</div>' +
  19748. '<div id="##_iframeholder" class="%%-iframeholder"></div>' +
  19749. //modify wdcount by matao
  19750. '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
  19751. '<td id="##_elementpath" class="%%-bottombar"></td>' +
  19752. '<td id="##_wordcount" class="%%-wordcount"></td>' +
  19753. '<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
  19754. '</tr></table></div>' +
  19755. '<div id="##_scalelayer"></div>' +
  19756. '</div>';
  19757. },
  19758. showWordImageDialog: function () {
  19759. this.editor.execCommand("wordimage", "word_img");
  19760. this._dialogs['wordimageDialog'].open();
  19761. },
  19762. renderToolbarBoxHtml: function () {
  19763. var buff = [];
  19764. for (var i = 0; i < this.toolbars.length; i++) {
  19765. buff.push(this.toolbars[i].renderHtml());
  19766. }
  19767. return buff.join('');
  19768. },
  19769. setFullScreen: function (fullscreen) {
  19770. var editor = this.editor,
  19771. container = editor.container.parentNode.parentNode;
  19772. if (this._fullscreen != fullscreen) {
  19773. this._fullscreen = fullscreen;
  19774. this.editor.fireEvent('beforefullscreenchange', fullscreen);
  19775. if (baidu.editor.browser.gecko) {
  19776. var bk = editor.selection.getRange().createBookmark();
  19777. }
  19778. if (fullscreen) {
  19779. while (container.tagName != "BODY") {
  19780. var position = baidu.editor.dom.domUtils.getComputedStyle(container, "position");
  19781. nodeStack.push(position);
  19782. container.style.position = "static";
  19783. container = container.parentNode;
  19784. }
  19785. this._bakHtmlOverflow = document.documentElement.style.overflow;
  19786. this._bakBodyOverflow = document.body.style.overflow;
  19787. this._bakAutoHeight = this.editor.autoHeightEnabled;
  19788. this._bakScrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
  19789. this._bakEditorContaninerWidth = editor.iframe.parentNode.offsetWidth;
  19790. if (this._bakAutoHeight) {
  19791. //当全屏时不能执行自动长高
  19792. editor.autoHeightEnabled = false;
  19793. this.editor.disableAutoHeight();
  19794. }
  19795. document.documentElement.style.overflow = 'hidden';
  19796. document.body.style.overflow = 'hidden';
  19797. this._bakCssText = this.getDom().style.cssText;
  19798. this._bakCssText1 = this.getDom('iframeholder').style.cssText;
  19799. editor.iframe.parentNode.style.width = '';
  19800. this._updateFullScreen();
  19801. } else {
  19802. while (container.tagName != "BODY") {
  19803. container.style.position = nodeStack.shift();
  19804. container = container.parentNode;
  19805. }
  19806. this.getDom().style.cssText = this._bakCssText;
  19807. this.getDom('iframeholder').style.cssText = this._bakCssText1;
  19808. if (this._bakAutoHeight) {
  19809. editor.autoHeightEnabled = true;
  19810. this.editor.enableAutoHeight();
  19811. }
  19812. document.documentElement.style.overflow = this._bakHtmlOverflow;
  19813. document.body.style.overflow = this._bakBodyOverflow;
  19814. editor.iframe.parentNode.style.width = this._bakEditorContaninerWidth + 'px';
  19815. window.scrollTo(0, this._bakScrollTop);
  19816. }
  19817. if (browser.gecko && editor.body.contentEditable === 'true') {
  19818. var input = document.createElement('input');
  19819. document.body.appendChild(input);
  19820. editor.body.contentEditable = false;
  19821. setTimeout(function () {
  19822. input.focus();
  19823. setTimeout(function () {
  19824. editor.body.contentEditable = true;
  19825. editor.fireEvent('fullscreenchanged', fullscreen);
  19826. editor.selection.getRange().moveToBookmark(bk).select(true);
  19827. baidu.editor.dom.domUtils.remove(input);
  19828. fullscreen && window.scroll(0, 0);
  19829. }, 0)
  19830. }, 0)
  19831. }
  19832. if (editor.body.contentEditable === 'true') {
  19833. this.editor.fireEvent('fullscreenchanged', fullscreen);
  19834. this.triggerLayout();
  19835. }
  19836. }
  19837. },
  19838. _updateFullScreen: function () {
  19839. if (this._fullscreen) {
  19840. var vpRect = uiUtils.getViewportRect();
  19841. 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);
  19842. uiUtils.setViewportOffset(this.getDom(), { left: 0, top: this.editor.options.topOffset || 0 });
  19843. this.editor.setHeight(vpRect.height - this.getDom('toolbarbox').offsetHeight - this.getDom('bottombar').offsetHeight - (this.editor.options.topOffset || 0));
  19844. //不手动调一下,会导致全屏失效
  19845. if (browser.gecko) {
  19846. try {
  19847. window.onresize();
  19848. } catch (e) {
  19849. }
  19850. }
  19851. }
  19852. },
  19853. _updateElementPath: function () {
  19854. var bottom = this.getDom('elementpath'), list;
  19855. if (this.elementPathEnabled && (list = this.editor.queryCommandValue('elementpath'))) {
  19856. var buff = [];
  19857. for (var i = 0, ci; ci = list[i]; i++) {
  19858. buff[i] = this.formatHtml('<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' + i + '&quot;);">' + ci + '</span>');
  19859. }
  19860. bottom.innerHTML = '<div class="edui-editor-breadcrumb" onmousedown="return false;">' + this.editor.getLang("elementPathTip") + ': ' + buff.join(' &gt; ') + '</div>';
  19861. } else {
  19862. bottom.style.display = 'none'
  19863. }
  19864. },
  19865. disableElementPath: function () {
  19866. var bottom = this.getDom('elementpath');
  19867. bottom.innerHTML = '';
  19868. bottom.style.display = 'none';
  19869. this.elementPathEnabled = false;
  19870. },
  19871. enableElementPath: function () {
  19872. var bottom = this.getDom('elementpath');
  19873. bottom.style.display = '';
  19874. this.elementPathEnabled = true;
  19875. this._updateElementPath();
  19876. },
  19877. _scale: function () {
  19878. var doc = document,
  19879. editor = this.editor,
  19880. editorHolder = editor.container,
  19881. editorDocument = editor.document,
  19882. toolbarBox = this.getDom("toolbarbox"),
  19883. bottombar = this.getDom("bottombar"),
  19884. scale = this.getDom("scale"),
  19885. scalelayer = this.getDom("scalelayer");
  19886. var isMouseMove = false,
  19887. position = null,
  19888. minEditorHeight = 0,
  19889. minEditorWidth = editor.options.minFrameWidth,
  19890. pageX = 0,
  19891. pageY = 0,
  19892. scaleWidth = 0,
  19893. scaleHeight = 0;
  19894. function down() {
  19895. position = domUtils.getXY(editorHolder);
  19896. if (!minEditorHeight) {
  19897. minEditorHeight = editor.options.minFrameHeight + toolbarBox.offsetHeight + bottombar.offsetHeight;
  19898. }
  19899. scalelayer.style.cssText = "position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:" + editorHolder.offsetWidth + "px;height:"
  19900. + editorHolder.offsetHeight + "px;z-index:" + (editor.options.zIndex + 1);
  19901. domUtils.on(doc, "mousemove", move);
  19902. domUtils.on(editorDocument, "mouseup", up);
  19903. domUtils.on(doc, "mouseup", up);
  19904. }
  19905. var me = this;
  19906. //by xuheng 全屏时关掉缩放
  19907. this.editor.addListener('fullscreenchanged', function (e, fullScreen) {
  19908. if (fullScreen) {
  19909. me.disableScale();
  19910. } else {
  19911. if (me.editor.options.scaleEnabled) {
  19912. me.enableScale();
  19913. var tmpNode = me.editor.document.createElement('span');
  19914. me.editor.body.appendChild(tmpNode);
  19915. me.editor.body.style.height = Math.max(domUtils.getXY(tmpNode).y, me.editor.iframe.offsetHeight - 20) + 'px';
  19916. domUtils.remove(tmpNode)
  19917. }
  19918. }
  19919. });
  19920. function move(event) {
  19921. clearSelection();
  19922. var e = event || window.event;
  19923. pageX = e.pageX || (doc.documentElement.scrollLeft + e.clientX);
  19924. pageY = e.pageY || (doc.documentElement.scrollTop + e.clientY);
  19925. scaleWidth = pageX - position.x;
  19926. scaleHeight = pageY - position.y;
  19927. if (scaleWidth >= minEditorWidth) {
  19928. isMouseMove = true;
  19929. scalelayer.style.width = scaleWidth + 'px';
  19930. }
  19931. if (scaleHeight >= minEditorHeight) {
  19932. isMouseMove = true;
  19933. scalelayer.style.height = scaleHeight + "px";
  19934. }
  19935. }
  19936. function up() {
  19937. if (isMouseMove) {
  19938. isMouseMove = false;
  19939. editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
  19940. editorHolder.style.width = editor.ui._actualFrameWidth + 'px';
  19941. editor.setHeight(scalelayer.offsetHeight - bottombar.offsetHeight - toolbarBox.offsetHeight - 2);
  19942. }
  19943. if (scalelayer) {
  19944. scalelayer.style.display = "none";
  19945. }
  19946. clearSelection();
  19947. domUtils.un(doc, "mousemove", move);
  19948. domUtils.un(editorDocument, "mouseup", up);
  19949. domUtils.un(doc, "mouseup", up);
  19950. }
  19951. function clearSelection() {
  19952. if (browser.ie)
  19953. doc.selection.clear();
  19954. else
  19955. window.getSelection().removeAllRanges();
  19956. }
  19957. this.enableScale = function () {
  19958. //trace:2868
  19959. if (editor.queryCommandState("source") == 1) return;
  19960. scale.style.display = "";
  19961. this.scaleEnabled = true;
  19962. domUtils.on(scale, "mousedown", down);
  19963. };
  19964. this.disableScale = function () {
  19965. scale.style.display = "none";
  19966. this.scaleEnabled = false;
  19967. domUtils.un(scale, "mousedown", down);
  19968. };
  19969. },
  19970. isFullScreen: function () {
  19971. return this._fullscreen;
  19972. },
  19973. postRender: function () {
  19974. UIBase.prototype.postRender.call(this);
  19975. for (var i = 0; i < this.toolbars.length; i++) {
  19976. this.toolbars[i].postRender();
  19977. }
  19978. var me = this;
  19979. var timerId,
  19980. domUtils = baidu.editor.dom.domUtils,
  19981. updateFullScreenTime = function () {
  19982. clearTimeout(timerId);
  19983. timerId = setTimeout(function () {
  19984. me._updateFullScreen();
  19985. });
  19986. };
  19987. domUtils.on(window, 'resize', updateFullScreenTime);
  19988. me.addListener('destroy', function () {
  19989. domUtils.un(window, 'resize', updateFullScreenTime);
  19990. clearTimeout(timerId);
  19991. })
  19992. },
  19993. showToolbarMsg: function (msg, flag) {
  19994. this.getDom('toolbarmsg_label').innerHTML = msg;
  19995. this.getDom('toolbarmsg').style.display = '';
  19996. //
  19997. if (!flag) {
  19998. var w = this.getDom('upload_dialog');
  19999. w.style.display = 'none';
  20000. }
  20001. },
  20002. hideToolbarMsg: function () {
  20003. this.getDom('toolbarmsg').style.display = 'none';
  20004. },
  20005. mapUrl: function (url) {
  20006. return url ? url.replace('~/', this.editor.options.UEDITOR_HOME_URL || '') : ''
  20007. },
  20008. triggerLayout: function () {
  20009. var dom = this.getDom();
  20010. if (dom.style.zoom == '1') {
  20011. dom.style.zoom = '100%';
  20012. } else {
  20013. dom.style.zoom = '1';
  20014. }
  20015. }
  20016. };
  20017. utils.inherits(EditorUI, baidu.editor.ui.UIBase);
  20018. var instances = {};
  20019. UE.ui.Editor = function (options) {
  20020. var editor = new UE.Editor(options);
  20021. editor.options.editor = editor;
  20022. utils.loadFile(document, {
  20023. href: editor.options.themePath + editor.options.theme + "/css/ueditor.css",
  20024. tag: "link",
  20025. type: "text/css",
  20026. rel: "stylesheet"
  20027. });
  20028. var oldRender = editor.render;
  20029. editor.render = function (holder) {
  20030. if (holder.constructor === String) {
  20031. editor.key = holder;
  20032. instances[holder] = editor;
  20033. }
  20034. utils.domReady(function () {
  20035. editor.langIsReady ? renderUI() : editor.addListener("langReady", renderUI);
  20036. function renderUI() {
  20037. editor.setOpt({
  20038. labelMap: editor.options.labelMap || editor.getLang('labelMap')
  20039. });
  20040. new EditorUI(editor.options);
  20041. if (holder) {
  20042. if (holder.constructor === String) {
  20043. holder = document.getElementById(holder);
  20044. }
  20045. holder && holder.getAttribute('name') && ( editor.options.textarea = holder.getAttribute('name'));
  20046. if (holder && /script|textarea/ig.test(holder.tagName)) {
  20047. var newDiv = document.createElement('div');
  20048. holder.parentNode.insertBefore(newDiv, holder);
  20049. var cont = holder.value || holder.innerHTML;
  20050. editor.options.initialContent = /^[\t\r\n ]*$/.test(cont) ? editor.options.initialContent :
  20051. cont.replace(/>[\n\r\t]+([ ]{4})+/g, '>')
  20052. .replace(/[\n\r\t]+([ ]{4})+</g, '<')
  20053. .replace(/>[\n\r\t]+</g, '><');
  20054. holder.className && (newDiv.className = holder.className);
  20055. holder.style.cssText && (newDiv.style.cssText = holder.style.cssText);
  20056. if (/textarea/i.test(holder.tagName)) {
  20057. editor.textarea = holder;
  20058. editor.textarea.style.display = 'none';
  20059. } else {
  20060. holder.parentNode.removeChild(holder);
  20061. holder.id && (newDiv.id = holder.id);
  20062. }
  20063. holder = newDiv;
  20064. holder.innerHTML = '';
  20065. }
  20066. }
  20067. domUtils.addClass(holder, "edui-" + editor.options.theme);
  20068. editor.ui.render(holder);
  20069. var opt = editor.options;
  20070. //给实例添加一个编辑器的容器引用
  20071. editor.container = editor.ui.getDom();
  20072. var parents = domUtils.findParents(holder, true);
  20073. var displays = [];
  20074. for (var i = 0 , ci; ci = parents[i]; i++) {
  20075. displays[i] = ci.style.display;
  20076. ci.style.display = 'block'
  20077. }
  20078. if (opt.initialFrameWidth) {
  20079. opt.minFrameWidth = opt.initialFrameWidth;
  20080. } else {
  20081. opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth;
  20082. }
  20083. if (opt.initialFrameHeight) {
  20084. opt.minFrameHeight = opt.initialFrameHeight;
  20085. } else {
  20086. opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight;
  20087. }
  20088. for (var i = 0 , ci; ci = parents[i]; i++) {
  20089. ci.style.display = displays[i]
  20090. }
  20091. //编辑器最外容器设置了高度,会导致,编辑器不占位
  20092. //todo 先去掉,没有找到原因
  20093. if (holder.style.height) {
  20094. holder.style.height = ''
  20095. }
  20096. editor.container.style.width = opt.initialFrameWidth + (/%$/.test(opt.initialFrameWidth) ? '' : 'px');
  20097. editor.container.style.zIndex = opt.zIndex;
  20098. oldRender.call(editor, editor.ui.getDom('iframeholder'));
  20099. }
  20100. })
  20101. };
  20102. return editor;
  20103. };
  20104. /**
  20105. * @file
  20106. * @name UE
  20107. * @short UE
  20108. * @desc UEditor的顶部命名空间
  20109. */
  20110. /**
  20111. * @name getEditor
  20112. * @since 1.2.4+
  20113. * @grammar UE.getEditor(id,[opt]) => Editor实例
  20114. * @desc 提供一个全局的方法得到编辑器实例
  20115. *
  20116. * * ''id'' 放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
  20117. * * ''opt'' 编辑器的可选参数
  20118. * @example
  20119. * UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
  20120. * this.setContent('hello')
  20121. * }});
  20122. * UE.getEditor('containerId'); //返回刚创建的实例
  20123. *
  20124. */
  20125. UE.getEditor = function (id, opt) {
  20126. var editor = instances[id];
  20127. if (!editor) {
  20128. editor = instances[id] = new UE.ui.Editor(opt);
  20129. editor.render(id);
  20130. }
  20131. return editor;
  20132. };
  20133. UE.delEditor = function (id) {
  20134. var editor;
  20135. if (editor = instances[id]) {
  20136. editor.key && editor.destroy();
  20137. delete instances[id]
  20138. }
  20139. }
  20140. })();
  20141. ///import core
  20142. ///import uicore
  20143. ///commands 表情
  20144. (function () {
  20145. var utils = baidu.editor.utils,
  20146. Popup = baidu.editor.ui.Popup,
  20147. SplitButton = baidu.editor.ui.SplitButton,
  20148. MultiMenuPop = baidu.editor.ui.MultiMenuPop = function (options) {
  20149. this.initOptions(options);
  20150. this.initMultiMenu();
  20151. };
  20152. MultiMenuPop.prototype = {
  20153. initMultiMenu: function () {
  20154. var me = this;
  20155. this.popup = new Popup({
  20156. content: '',
  20157. editor: me.editor,
  20158. iframe_rendered: false,
  20159. onshow: function () {
  20160. if (!this.iframe_rendered) {
  20161. this.iframe_rendered = true;
  20162. this.getDom('content').innerHTML = '<iframe id="' + me.id + '_iframe" src="' + me.iframeUrl + '" frameborder="0"></iframe>';
  20163. me.editor.container.style.zIndex && (this.getDom().style.zIndex = me.editor.container.style.zIndex * 1 + 1);
  20164. }
  20165. }
  20166. // canSideUp:false,
  20167. // canSideLeft:false
  20168. });
  20169. this.onbuttonclick = function () {
  20170. this.showPopup();
  20171. };
  20172. this.initSplitButton();
  20173. }
  20174. };
  20175. utils.inherits(MultiMenuPop, SplitButton);
  20176. })();
  20177. (function () {
  20178. var UI = baidu.editor.ui,
  20179. UIBase = UI.UIBase,
  20180. uiUtils = UI.uiUtils,
  20181. utils = baidu.editor.utils,
  20182. domUtils = baidu.editor.dom.domUtils;
  20183. var allMenus = [],//存储所有快捷菜单
  20184. timeID,
  20185. isSubMenuShow = false;//是否有子pop显示
  20186. var ShortCutMenu = UI.ShortCutMenu = function (options) {
  20187. this.initOptions(options);
  20188. this.initShortCutMenu();
  20189. };
  20190. ShortCutMenu.postHide = hideAllMenu;
  20191. ShortCutMenu.prototype = {
  20192. isHidden: true,
  20193. SPACE: 5,
  20194. initShortCutMenu: function () {
  20195. this.items = this.items || [];
  20196. this.initUIBase();
  20197. this.initItems();
  20198. this.initEvent();
  20199. allMenus.push(this);
  20200. },
  20201. initEvent: function () {
  20202. var me = this,
  20203. doc = me.editor.document;
  20204. domUtils.on(doc, "mousemove", function (e) {
  20205. if (me.isHidden === false) {
  20206. //有pop显示就不隐藏快捷菜单
  20207. if (me.getSubMenuMark() || me.eventType == "contextmenu") return;
  20208. var flag = true,
  20209. el = me.getDom(),
  20210. wt = el.offsetWidth,
  20211. ht = el.offsetHeight,
  20212. distanceX = wt / 2 + me.SPACE,//距离中心X标准
  20213. distanceY = ht / 2,//距离中心Y标准
  20214. x = Math.abs(e.screenX - me.left),//离中心距离横坐标
  20215. y = Math.abs(e.screenY - me.top);//离中心距离纵坐标
  20216. clearTimeout(timeID);
  20217. timeID = setTimeout(function () {
  20218. if (y > 0 && y < distanceY) {
  20219. me.setOpacity(el, "1");
  20220. } else if (y > distanceY && y < distanceY + 70) {
  20221. me.setOpacity(el, "0.5");
  20222. flag = false;
  20223. } else if (y > distanceY + 70 && y < distanceY + 140) {
  20224. me.hide();
  20225. }
  20226. if (flag && x > 0 && x < distanceX) {
  20227. me.setOpacity(el, "1")
  20228. } else if (x > distanceX && x < distanceX + 70) {
  20229. me.setOpacity(el, "0.5")
  20230. } else if (x > distanceX + 70 && x < distanceX + 140) {
  20231. me.hide();
  20232. }
  20233. });
  20234. }
  20235. });
  20236. //ie\ff下 mouseout不准
  20237. if (browser.chrome) {
  20238. domUtils.on(doc, "mouseout", function (e) {
  20239. var relatedTgt = e.relatedTarget || e.toElement;
  20240. if (relatedTgt == null || relatedTgt.tagName == "HTML") {
  20241. me.hide();
  20242. }
  20243. });
  20244. }
  20245. me.editor.addListener("afterhidepop", function () {
  20246. if (!me.isHidden) {
  20247. isSubMenuShow = true;
  20248. }
  20249. });
  20250. },
  20251. initItems: function () {
  20252. if (utils.isArray(this.items)) {
  20253. for (var i = 0, len = this.items.length; i < len; i++) {
  20254. var item = this.items[i].toLowerCase();
  20255. if (UI[item]) {
  20256. this.items[i] = new UI[item](this.editor);
  20257. this.items[i].className += " edui-shortcutsubmenu ";
  20258. }
  20259. }
  20260. }
  20261. },
  20262. setOpacity: function (el, value) {
  20263. if (browser.ie && browser.version < 9) {
  20264. el.style.filter = "alpha(opacity = " + parseFloat(value) * 100 + ");"
  20265. } else {
  20266. el.style.opacity = value;
  20267. }
  20268. },
  20269. getSubMenuMark: function () {
  20270. isSubMenuShow = false;
  20271. var layerEle = uiUtils.getFixedLayer();
  20272. var list = domUtils.getElementsByTagName(layerEle, "div", function (node) {
  20273. return domUtils.hasClass(node, "edui-shortcutsubmenu edui-popup")
  20274. });
  20275. for (var i = 0, node; node = list[i++];) {
  20276. if (node.style.display != "none") {
  20277. isSubMenuShow = true;
  20278. }
  20279. }
  20280. return isSubMenuShow;
  20281. },
  20282. show: function (e, hasContextmenu) {
  20283. var me = this,
  20284. offset = {},
  20285. el = this.getDom(),
  20286. fixedlayer = uiUtils.getFixedLayer();
  20287. function setPos(offset) {
  20288. if (offset.left < 0) {
  20289. offset.left = 0;
  20290. }
  20291. if (offset.top < 0) {
  20292. offset.top = 0;
  20293. }
  20294. el.style.cssText = "position:absolute;left:" + offset.left + "px;top:" + offset.top + "px;";
  20295. }
  20296. function setPosByCxtMenu(menu) {
  20297. if (!menu.tagName) {
  20298. menu = menu.getDom();
  20299. }
  20300. offset.left = parseInt(menu.style.left);
  20301. offset.top = parseInt(menu.style.top);
  20302. offset.top -= el.offsetHeight + 15;
  20303. setPos(offset);
  20304. }
  20305. me.eventType = e.type;
  20306. el.style.cssText = "display:block;left:-9999px";
  20307. if (e.type == "contextmenu" && hasContextmenu) {
  20308. var menu = domUtils.getElementsByTagName(fixedlayer, "div", "edui-contextmenu")[0];
  20309. if (menu) {
  20310. setPosByCxtMenu(menu)
  20311. } else {
  20312. me.editor.addListener("aftershowcontextmenu", function (type, menu) {
  20313. setPosByCxtMenu(menu);
  20314. });
  20315. }
  20316. } else {
  20317. offset = uiUtils.getViewportOffsetByEvent(e);
  20318. offset.top -= el.offsetHeight + me.SPACE;
  20319. offset.left += me.SPACE + 20;
  20320. setPos(offset);
  20321. me.setOpacity(el, 0.2);
  20322. }
  20323. me.isHidden = false;
  20324. me.left = e.screenX + el.offsetWidth / 2 - me.SPACE;
  20325. me.top = e.screenY - (el.offsetHeight / 2) - me.SPACE;
  20326. if (me.editor) {
  20327. el.style.zIndex = me.editor.container.style.zIndex * 1 + 10;
  20328. fixedlayer.style.zIndex = el.style.zIndex - 1;
  20329. }
  20330. },
  20331. hide: function () {
  20332. if (this.getDom()) {
  20333. this.getDom().style.display = "none";
  20334. }
  20335. this.isHidden = true;
  20336. },
  20337. postRender: function () {
  20338. if (utils.isArray(this.items)) {
  20339. for (var i = 0, item; item = this.items[i++];) {
  20340. item.postRender();
  20341. }
  20342. }
  20343. },
  20344. getHtmlTpl: function () {
  20345. var buff;
  20346. if (utils.isArray(this.items)) {
  20347. buff = [];
  20348. for (var i = 0; i < this.items.length; i++) {
  20349. buff[i] = this.items[i].renderHtml();
  20350. }
  20351. buff = buff.join("");
  20352. } else {
  20353. buff = this.items;
  20354. }
  20355. return '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
  20356. buff +
  20357. '</div>';
  20358. }
  20359. };
  20360. utils.inherits(ShortCutMenu, UIBase);
  20361. function hideAllMenu(e) {
  20362. var tgt = e.target || e.srcElement,
  20363. cur = domUtils.findParent(tgt, function (node) {
  20364. return domUtils.hasClass(node, "edui-shortcutmenu") || domUtils.hasClass(node, "edui-popup");
  20365. }, true);
  20366. if (!cur) {
  20367. for (var i = 0, menu; menu = allMenus[i++];) {
  20368. menu.hide()
  20369. }
  20370. }
  20371. }
  20372. domUtils.on(document, 'mousedown', function (e) {
  20373. hideAllMenu(e);
  20374. });
  20375. domUtils.on(window, 'scroll', function (e) {
  20376. hideAllMenu(e);
  20377. });
  20378. })();
  20379. (function () {
  20380. var utils = baidu.editor.utils,
  20381. UIBase = baidu.editor.ui.UIBase,
  20382. Breakline = baidu.editor.ui.Breakline = function (options) {
  20383. this.initOptions(options);
  20384. this.initSeparator();
  20385. };
  20386. Breakline.prototype = {
  20387. uiName: 'Breakline',
  20388. initSeparator: function () {
  20389. this.initUIBase();
  20390. },
  20391. getHtmlTpl: function () {
  20392. return '<br/>';
  20393. }
  20394. };
  20395. utils.inherits(Breakline, UIBase);
  20396. })();
  20397. })()